Kstars

qcustomplot.cpp
1 /*
2  QCustomPlot, an easy to use, modern plotting widget for Qt
3  SPDX-FileCopyrightText: 2011-2021 Emanuel Eichhammer <http://www.qcustomplot.com/>
4 
5  SPDX-License-Identifier: GPL-3.0-or-later
6 */
7 
8 #include "qcustomplot.h"
9 
10 
11 /* including file 'src/vector2d.cpp' */
12 /* modified 2021-03-29T02:30:44, size 7973 */
13 
14 ////////////////////////////////////////////////////////////////////////////////////////////////////
15 //////////////////// QCPVector2D
16 ////////////////////////////////////////////////////////////////////////////////////////////////////
17 
18 /*! \class QCPVector2D
19  \brief Represents two doubles as a mathematical 2D vector
20 
21  This class acts as a replacement for QVector2D with the advantage of double precision instead of
22  single, and some convenience methods tailored for the QCustomPlot library.
23 */
24 
25 /* start documentation of inline functions */
26 
27 /*! \fn void QCPVector2D::setX(double x)
28 
29  Sets the x coordinate of this vector to \a x.
30 
31  \see setY
32 */
33 
34 /*! \fn void QCPVector2D::setY(double y)
35 
36  Sets the y coordinate of this vector to \a y.
37 
38  \see setX
39 */
40 
41 /*! \fn double QCPVector2D::length() const
42 
43  Returns the length of this vector.
44 
45  \see lengthSquared
46 */
47 
48 /*! \fn double QCPVector2D::lengthSquared() const
49 
50  Returns the squared length of this vector. In some situations, e.g. when just trying to find the
51  shortest vector of a group, this is faster than calculating \ref length, because it avoids
52  calculation of a square root.
53 
54  \see length
55 */
56 
57 /*! \fn double QCPVector2D::angle() const
58 
59  Returns the angle of the vector in radians. The angle is measured between the positive x line and
60  the vector, counter-clockwise in a mathematical coordinate system (y axis upwards positive). In
61  screen/widget coordinates where the y axis is inverted, the angle appears clockwise.
62 */
63 
64 /*! \fn QPoint QCPVector2D::toPoint() const
65 
66  Returns a QPoint which has the x and y coordinates of this vector, truncating any floating point
67  information.
68 
69  \see toPointF
70 */
71 
72 /*! \fn QPointF QCPVector2D::toPointF() const
73 
74  Returns a QPointF which has the x and y coordinates of this vector.
75 
76  \see toPoint
77 */
78 
79 /*! \fn bool QCPVector2D::isNull() const
80 
81  Returns whether this vector is null. A vector is null if \c qIsNull returns true for both x and y
82  coordinates, i.e. if both are binary equal to 0.
83 */
84 
85 /*! \fn QCPVector2D QCPVector2D::perpendicular() const
86 
87  Returns a vector perpendicular to this vector, with the same length.
88 */
89 
90 /*! \fn double QCPVector2D::dot() const
91 
92  Returns the dot/scalar product of this vector with the specified vector \a vec.
93 */
94 
95 /* end documentation of inline functions */
96 
97 /*!
98  Creates a QCPVector2D object and initializes the x and y coordinates to 0.
99 */
101  mX(0),
102  mY(0)
103 {
104 }
105 
106 /*!
107  Creates a QCPVector2D object and initializes the \a x and \a y coordinates with the specified
108  values.
109 */
110 QCPVector2D::QCPVector2D(double x, double y) :
111  mX(x),
112  mY(y)
113 {
114 }
115 
116 /*!
117  Creates a QCPVector2D object and initializes the x and y coordinates respective coordinates of
118  the specified \a point.
119 */
121  mX(point.x()),
122  mY(point.y())
123 {
124 }
125 
126 /*!
127  Creates a QCPVector2D object and initializes the x and y coordinates respective coordinates of
128  the specified \a point.
129 */
131  mX(point.x()),
132  mY(point.y())
133 {
134 }
135 
136 /*!
137  Normalizes this vector. After this operation, the length of the vector is equal to 1.
138 
139  If the vector has both entries set to zero, this method does nothing.
140 
141  \see normalized, length, lengthSquared
142 */
144 {
145  if (mX == 0.0 && mY == 0.0) return;
146  const double lenInv = 1.0/length();
147  mX *= lenInv;
148  mY *= lenInv;
149 }
150 
151 /*!
152  Returns a normalized version of this vector. The length of the returned vector is equal to 1.
153 
154  If the vector has both entries set to zero, this method returns the vector unmodified.
155 
156  \see normalize, length, lengthSquared
157 */
159 {
160  if (mX == 0.0 && mY == 0.0) return *this;
161  const double lenInv = 1.0/length();
162  return QCPVector2D(mX*lenInv, mY*lenInv);
163 }
164 
165 /*! \overload
166 
167  Returns the squared shortest distance of this vector (interpreted as a point) to the finite line
168  segment given by \a start and \a end.
169 
170  \see distanceToStraightLine
171 */
172 double QCPVector2D::distanceSquaredToLine(const QCPVector2D &start, const QCPVector2D &end) const
173 {
174  const QCPVector2D v(end-start);
175  const double vLengthSqr = v.lengthSquared();
176  if (!qFuzzyIsNull(vLengthSqr))
177  {
178  const double mu = v.dot(*this-start)/vLengthSqr;
179  if (mu < 0)
180  return (*this-start).lengthSquared();
181  else if (mu > 1)
182  return (*this-end).lengthSquared();
183  else
184  return ((start + mu*v)-*this).lengthSquared();
185  } else
186  return (*this-start).lengthSquared();
187 }
188 
189 /*! \overload
190 
191  Returns the squared shortest distance of this vector (interpreted as a point) to the finite line
192  segment given by \a line.
193 
194  \see distanceToStraightLine
195 */
197 {
198  return distanceSquaredToLine(QCPVector2D(line.p1()), QCPVector2D(line.p2()));
199 }
200 
201 /*!
202  Returns the shortest distance of this vector (interpreted as a point) to the infinite straight
203  line given by a \a base point and a \a direction vector.
204 
205  \see distanceSquaredToLine
206 */
207 double QCPVector2D::distanceToStraightLine(const QCPVector2D &base, const QCPVector2D &direction) const
208 {
209  return qAbs((*this-base).dot(direction.perpendicular()))/direction.length();
210 }
211 
212 /*!
213  Scales this vector by the given \a factor, i.e. the x and y components are multiplied by \a
214  factor.
215 */
217 {
218  mX *= factor;
219  mY *= factor;
220  return *this;
221 }
222 
223 /*!
224  Scales this vector by the given \a divisor, i.e. the x and y components are divided by \a
225  divisor.
226 */
228 {
229  mX /= divisor;
230  mY /= divisor;
231  return *this;
232 }
233 
234 /*!
235  Adds the given \a vector to this vector component-wise.
236 */
238 {
239  mX += vector.mX;
240  mY += vector.mY;
241  return *this;
242 }
243 
244 /*!
245  subtracts the given \a vector from this vector component-wise.
246 */
248 {
249  mX -= vector.mX;
250  mY -= vector.mY;
251  return *this;
252 }
253 /* end of 'src/vector2d.cpp' */
254 
255 
256 /* including file 'src/painter.cpp' */
257 /* modified 2021-03-29T02:30:44, size 8656 */
258 
259 ////////////////////////////////////////////////////////////////////////////////////////////////////
260 //////////////////// QCPPainter
261 ////////////////////////////////////////////////////////////////////////////////////////////////////
262 
263 /*! \class QCPPainter
264  \brief QPainter subclass used internally
265 
266  This QPainter subclass is used to provide some extended functionality e.g. for tweaking position
267  consistency between antialiased and non-antialiased painting. Further it provides workarounds
268  for QPainter quirks.
269 
270  \warning This class intentionally hides non-virtual functions of QPainter, e.g. setPen, save and
271  restore. So while it is possible to pass a QCPPainter instance to a function that expects a
272  QPainter pointer, some of the workarounds and tweaks will be unavailable to the function (because
273  it will call the base class implementations of the functions actually hidden by QCPPainter).
274 */
275 
276 /*!
277  Creates a new QCPPainter instance and sets default values
278 */
280  mModes(pmDefault),
281  mIsAntialiasing(false)
282 {
283  // don't setRenderHint(QPainter::NonCosmeticDefautPen) here, because painter isn't active yet and
284  // a call to begin() will follow
285 }
286 
287 /*!
288  Creates a new QCPPainter instance on the specified paint \a device and sets default values. Just
289  like the analogous QPainter constructor, begins painting on \a device immediately.
290 
291  Like \ref begin, this method sets QPainter::NonCosmeticDefaultPen in Qt versions before Qt5.
292 */
294  QPainter(device),
295  mModes(pmDefault),
296  mIsAntialiasing(false)
297 {
298 #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.
299  if (isActive())
301 #endif
302 }
303 
304 /*!
305  Sets the pen of the painter and applies certain fixes to it, depending on the mode of this
306  QCPPainter.
307 
308  \note this function hides the non-virtual base class implementation.
309 */
310 void QCPPainter::setPen(const QPen &pen)
311 {
313  if (mModes.testFlag(pmNonCosmetic))
314  makeNonCosmetic();
315 }
316 
317 /*! \overload
318 
319  Sets the pen (by color) of the painter and applies certain fixes to it, depending on the mode of
320  this QCPPainter.
321 
322  \note this function hides the non-virtual base class implementation.
323 */
324 void QCPPainter::setPen(const QColor &color)
325 {
326  QPainter::setPen(color);
327  if (mModes.testFlag(pmNonCosmetic))
328  makeNonCosmetic();
329 }
330 
331 /*! \overload
332 
333  Sets the pen (by style) of the painter and applies certain fixes to it, depending on the mode of
334  this QCPPainter.
335 
336  \note this function hides the non-virtual base class implementation.
337 */
339 {
340  QPainter::setPen(penStyle);
341  if (mModes.testFlag(pmNonCosmetic))
342  makeNonCosmetic();
343 }
344 
345 /*! \overload
346 
347  Works around a Qt bug introduced with Qt 4.8 which makes drawing QLineF unpredictable when
348  antialiasing is disabled. Thus when antialiasing is disabled, it rounds the \a line to
349  integer coordinates and then passes it to the original drawLine.
350 
351  \note this function hides the non-virtual base class implementation.
352 */
353 void QCPPainter::drawLine(const QLineF &line)
354 {
355  if (mIsAntialiasing || mModes.testFlag(pmVectorized))
356  QPainter::drawLine(line);
357  else
358  QPainter::drawLine(line.toLine());
359 }
360 
361 /*!
362  Sets whether painting uses antialiasing or not. Use this method instead of using setRenderHint
363  with QPainter::Antialiasing directly, as it allows QCPPainter to regain pixel exactness between
364  antialiased and non-antialiased painting (Since Qt < 5.0 uses slightly different coordinate systems for
365  AA/Non-AA painting).
366 */
367 void QCPPainter::setAntialiasing(bool enabled)
368 {
370  if (mIsAntialiasing != enabled)
371  {
372  mIsAntialiasing = enabled;
373  if (!mModes.testFlag(pmVectorized)) // antialiasing half-pixel shift only needed for rasterized outputs
374  {
375  if (mIsAntialiasing)
376  translate(0.5, 0.5);
377  else
378  translate(-0.5, -0.5);
379  }
380  }
381 }
382 
383 /*!
384  Sets the mode of the painter. This controls whether the painter shall adjust its
385  fixes/workarounds optimized for certain output devices.
386 */
388 {
389  mModes = modes;
390 }
391 
392 /*!
393  Sets the QPainter::NonCosmeticDefaultPen in Qt versions before Qt5 after beginning painting on \a
394  device. This is necessary to get cosmetic pen consistency across Qt versions, because since Qt5,
395  all pens are non-cosmetic by default, and in Qt4 this render hint must be set to get that
396  behaviour.
397 
398  The Constructor \ref QCPPainter(QPaintDevice *device) which directly starts painting also sets
399  the render hint as appropriate.
400 
401  \note this function hides the non-virtual base class implementation.
402 */
404 {
405  bool result = QPainter::begin(device);
406 #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.
407  if (result)
409 #endif
410  return result;
411 }
412 
413 /*! \overload
414 
415  Sets the mode of the painter. This controls whether the painter shall adjust its
416  fixes/workarounds optimized for certain output devices.
417 */
419 {
420  if (!enabled && mModes.testFlag(mode))
421  mModes &= ~mode;
422  else if (enabled && !mModes.testFlag(mode))
423  mModes |= mode;
424 }
425 
426 /*!
427  Saves the painter (see QPainter::save). Since QCPPainter adds some new internal state to
428  QPainter, the save/restore functions are reimplemented to also save/restore those members.
429 
430  \note this function hides the non-virtual base class implementation.
431 
432  \see restore
433 */
435 {
436  mAntialiasingStack.push(mIsAntialiasing);
437  QPainter::save();
438 }
439 
440 /*!
441  Restores the painter (see QPainter::restore). Since QCPPainter adds some new internal state to
442  QPainter, the save/restore functions are reimplemented to also save/restore those members.
443 
444  \note this function hides the non-virtual base class implementation.
445 
446  \see save
447 */
449 {
450  if (!mAntialiasingStack.isEmpty())
451  mIsAntialiasing = mAntialiasingStack.pop();
452  else
453  qDebug() << Q_FUNC_INFO << "Unbalanced save/restore";
455 }
456 
457 /*!
458  Changes the pen width to 1 if it currently is 0. This function is called in the \ref setPen
459  overrides when the \ref pmNonCosmetic mode is set.
460 */
462 {
463  if (qFuzzyIsNull(pen().widthF()))
464  {
465  QPen p = pen();
466  p.setWidth(1);
467  QPainter::setPen(p);
468  }
469 }
470 /* end of 'src/painter.cpp' */
471 
472 
473 /* including file 'src/paintbuffer.cpp' */
474 /* modified 2021-03-29T02:30:44, size 18915 */
475 
476 ////////////////////////////////////////////////////////////////////////////////////////////////////
477 //////////////////// QCPAbstractPaintBuffer
478 ////////////////////////////////////////////////////////////////////////////////////////////////////
479 
480 /*! \class QCPAbstractPaintBuffer
481  \brief The abstract base class for paint buffers, which define the rendering backend
482 
483  This abstract base class defines the basic interface that a paint buffer needs to provide in
484  order to be usable by QCustomPlot.
485 
486  A paint buffer manages both a surface to draw onto, and the matching paint device. The size of
487  the surface can be changed via \ref setSize. External classes (\ref QCustomPlot and \ref
488  QCPLayer) request a painter via \ref startPainting and then perform the draw calls. Once the
489  painting is complete, \ref donePainting is called, so the paint buffer implementation can do
490  clean up if necessary. Before rendering a frame, each paint buffer is usually filled with a color
491  using \ref clear (usually the color is \c Qt::transparent), to remove the contents of the
492  previous frame.
493 
494  The simplest paint buffer implementation is \ref QCPPaintBufferPixmap which allows regular
495  software rendering via the raster engine. Hardware accelerated rendering via pixel buffers and
496  frame buffer objects is provided by \ref QCPPaintBufferGlPbuffer and \ref QCPPaintBufferGlFbo.
497  They are used automatically if \ref QCustomPlot::setOpenGl is enabled.
498 */
499 
500 /* start documentation of pure virtual functions */
501 
502 /*! \fn virtual QCPPainter *QCPAbstractPaintBuffer::startPainting() = 0
503 
504  Returns a \ref QCPPainter which is ready to draw to this buffer. The ownership and thus the
505  responsibility to delete the painter after the painting operations are complete is given to the
506  caller of this method.
507 
508  Once you are done using the painter, delete the painter and call \ref donePainting.
509 
510  While a painter generated with this method is active, you must not call \ref setSize, \ref
511  setDevicePixelRatio or \ref clear.
512 
513  This method may return 0, if a painter couldn't be activated on the buffer. This usually
514  indicates a problem with the respective painting backend.
515 */
516 
517 /*! \fn virtual void QCPAbstractPaintBuffer::draw(QCPPainter *painter) const = 0
518 
519  Draws the contents of this buffer with the provided \a painter. This is the method that is used
520  to finally join all paint buffers and draw them onto the screen.
521 */
522 
523 /*! \fn virtual void QCPAbstractPaintBuffer::clear(const QColor &color) = 0
524 
525  Fills the entire buffer with the provided \a color. To have an empty transparent buffer, use the
526  named color \c Qt::transparent.
527 
528  This method must not be called if there is currently a painter (acquired with \ref startPainting)
529  active.
530 */
531 
532 /*! \fn virtual void QCPAbstractPaintBuffer::reallocateBuffer() = 0
533 
534  Reallocates the internal buffer with the currently configured size (\ref setSize) and device
535  pixel ratio, if applicable (\ref setDevicePixelRatio). It is called as soon as any of those
536  properties are changed on this paint buffer.
537 
538  \note Subclasses of \ref QCPAbstractPaintBuffer must call their reimplementation of this method
539  in their constructor, to perform the first allocation (this can not be done by the base class
540  because calling pure virtual methods in base class constructors is not possible).
541 */
542 
543 /* end documentation of pure virtual functions */
544 /* start documentation of inline functions */
545 
546 /*! \fn virtual void QCPAbstractPaintBuffer::donePainting()
547 
548  If you have acquired a \ref QCPPainter to paint onto this paint buffer via \ref startPainting,
549  call this method as soon as you are done with the painting operations and have deleted the
550  painter.
551 
552  paint buffer subclasses may use this method to perform any type of cleanup that is necessary. The
553  default implementation does nothing.
554 */
555 
556 /* end documentation of inline functions */
557 
558 /*!
559  Creates a paint buffer and initializes it with the provided \a size and \a devicePixelRatio.
560 
561  Subclasses must call their \ref reallocateBuffer implementation in their respective constructors.
562 */
563 QCPAbstractPaintBuffer::QCPAbstractPaintBuffer(const QSize &size, double devicePixelRatio) :
564  mSize(size),
565  mDevicePixelRatio(devicePixelRatio),
566  mInvalidated(true)
567 {
568 }
569 
570 QCPAbstractPaintBuffer::~QCPAbstractPaintBuffer()
571 {
572 }
573 
574 /*!
575  Sets the paint buffer size.
576 
577  The buffer is reallocated (by calling \ref reallocateBuffer), so any painters that were obtained
578  by \ref startPainting are invalidated and must not be used after calling this method.
579 
580  If \a size is already the current buffer size, this method does nothing.
581 */
583 {
584  if (mSize != size)
585  {
586  mSize = size;
588  }
589 }
590 
591 /*!
592  Sets the invalidated flag to \a invalidated.
593 
594  This mechanism is used internally in conjunction with isolated replotting of \ref QCPLayer
595  instances (in \ref QCPLayer::lmBuffered mode). If \ref QCPLayer::replot is called on a buffered
596  layer, i.e. an isolated repaint of only that layer (and its dedicated paint buffer) is requested,
597  QCustomPlot will decide depending on the invalidated flags of other paint buffers whether it also
598  replots them, instead of only the layer on which the replot was called.
599 
600  The invalidated flag is set to true when \ref QCPLayer association has changed, i.e. if layers
601  were added or removed from this buffer, or if they were reordered. It is set to false as soon as
602  all associated \ref QCPLayer instances are drawn onto the buffer.
603 
604  Under normal circumstances, it is not necessary to manually call this method.
605 */
607 {
608  mInvalidated = invalidated;
609 }
610 
611 /*!
612  Sets the device pixel ratio to \a ratio. This is useful to render on high-DPI output devices.
613  The ratio is automatically set to the device pixel ratio used by the parent QCustomPlot instance.
614 
615  The buffer is reallocated (by calling \ref reallocateBuffer), so any painters that were obtained
616  by \ref startPainting are invalidated and must not be used after calling this method.
617 
618  \note This method is only available for Qt versions 5.4 and higher.
619 */
621 {
622  if (!qFuzzyCompare(ratio, mDevicePixelRatio))
623  {
624 #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
625  mDevicePixelRatio = ratio;
627 #else
628  qDebug() << Q_FUNC_INFO << "Device pixel ratios not supported for Qt versions before 5.4";
629  mDevicePixelRatio = 1.0;
630 #endif
631  }
632 }
633 
634 ////////////////////////////////////////////////////////////////////////////////////////////////////
635 //////////////////// QCPPaintBufferPixmap
636 ////////////////////////////////////////////////////////////////////////////////////////////////////
637 
638 /*! \class QCPPaintBufferPixmap
639  \brief A paint buffer based on QPixmap, using software raster rendering
640 
641  This paint buffer is the default and fall-back paint buffer which uses software rendering and
642  QPixmap as internal buffer. It is used if \ref QCustomPlot::setOpenGl is false.
643 */
644 
645 /*!
646  Creates a pixmap paint buffer instancen with the specified \a size and \a devicePixelRatio, if
647  applicable.
648 */
649 QCPPaintBufferPixmap::QCPPaintBufferPixmap(const QSize &size, double devicePixelRatio) :
650  QCPAbstractPaintBuffer(size, devicePixelRatio)
651 {
653 }
654 
655 QCPPaintBufferPixmap::~QCPPaintBufferPixmap()
656 {
657 }
658 
659 /* inherits documentation from base class */
661 {
662  QCPPainter *result = new QCPPainter(&mBuffer);
663 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
665 #endif
666  return result;
667 }
668 
669 /* inherits documentation from base class */
671 {
672  if (painter && painter->isActive())
673  painter->drawPixmap(0, 0, mBuffer);
674  else
675  qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed";
676 }
677 
678 /* inherits documentation from base class */
680 {
681  mBuffer.fill(color);
682 }
683 
684 /* inherits documentation from base class */
686 {
687  setInvalidated();
688  if (!qFuzzyCompare(1.0, mDevicePixelRatio))
689  {
690 #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
691  mBuffer = QPixmap(mSize*mDevicePixelRatio);
692  mBuffer.setDevicePixelRatio(mDevicePixelRatio);
693 #else
694  qDebug() << Q_FUNC_INFO << "Device pixel ratios not supported for Qt versions before 5.4";
695  mDevicePixelRatio = 1.0;
696  mBuffer = QPixmap(mSize);
697 #endif
698  } else
699  {
700  mBuffer = QPixmap(mSize);
701  }
702 }
703 
704 
705 #ifdef QCP_OPENGL_PBUFFER
706 ////////////////////////////////////////////////////////////////////////////////////////////////////
707 //////////////////// QCPPaintBufferGlPbuffer
708 ////////////////////////////////////////////////////////////////////////////////////////////////////
709 
710 /*! \class QCPPaintBufferGlPbuffer
711  \brief A paint buffer based on OpenGL pixel buffers, using hardware accelerated rendering
712 
713  This paint buffer is one of the OpenGL paint buffers which facilitate hardware accelerated plot
714  rendering. It is based on OpenGL pixel buffers (pbuffer) and is used in Qt versions before 5.0.
715  (See \ref QCPPaintBufferGlFbo used in newer Qt versions.)
716 
717  The OpenGL paint buffers are used if \ref QCustomPlot::setOpenGl is set to true, and if they are
718  supported by the system.
719 */
720 
721 /*!
722  Creates a \ref QCPPaintBufferGlPbuffer instance with the specified \a size and \a
723  devicePixelRatio, if applicable.
724 
725  The parameter \a multisamples defines how many samples are used per pixel. Higher values thus
726  result in higher quality antialiasing. If the specified \a multisamples value exceeds the
727  capability of the graphics hardware, the highest supported multisampling is used.
728 */
729 QCPPaintBufferGlPbuffer::QCPPaintBufferGlPbuffer(const QSize &size, double devicePixelRatio, int multisamples) :
730  QCPAbstractPaintBuffer(size, devicePixelRatio),
731  mGlPBuffer(0),
732  mMultisamples(qMax(0, multisamples))
733 {
734  QCPPaintBufferGlPbuffer::reallocateBuffer();
735 }
736 
737 QCPPaintBufferGlPbuffer::~QCPPaintBufferGlPbuffer()
738 {
739  if (mGlPBuffer)
740  delete mGlPBuffer;
741 }
742 
743 /* inherits documentation from base class */
744 QCPPainter *QCPPaintBufferGlPbuffer::startPainting()
745 {
746  if (!mGlPBuffer->isValid())
747  {
748  qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?";
749  return 0;
750  }
751 
752  QCPPainter *result = new QCPPainter(mGlPBuffer);
754  return result;
755 }
756 
757 /* inherits documentation from base class */
758 void QCPPaintBufferGlPbuffer::draw(QCPPainter *painter) const
759 {
760  if (!painter || !painter->isActive())
761  {
762  qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed";
763  return;
764  }
765  if (!mGlPBuffer->isValid())
766  {
767  qDebug() << Q_FUNC_INFO << "OpenGL pbuffer isn't valid, reallocateBuffer was not called?";
768  return;
769  }
770  painter->drawImage(0, 0, mGlPBuffer->toImage());
771 }
772 
773 /* inherits documentation from base class */
774 void QCPPaintBufferGlPbuffer::clear(const QColor &color)
775 {
776  if (mGlPBuffer->isValid())
777  {
778  mGlPBuffer->makeCurrent();
779  glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
780  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
781  mGlPBuffer->doneCurrent();
782  } else
783  qDebug() << Q_FUNC_INFO << "OpenGL pbuffer invalid or context not current";
784 }
785 
786 /* inherits documentation from base class */
787 void QCPPaintBufferGlPbuffer::reallocateBuffer()
788 {
789  if (mGlPBuffer)
790  delete mGlPBuffer;
791 
792  QGLFormat format;
793  format.setAlpha(true);
794  format.setSamples(mMultisamples);
795  mGlPBuffer = new QGLPixelBuffer(mSize, format);
796 }
797 #endif // QCP_OPENGL_PBUFFER
798 
799 
800 #ifdef QCP_OPENGL_FBO
801 ////////////////////////////////////////////////////////////////////////////////////////////////////
802 //////////////////// QCPPaintBufferGlFbo
803 ////////////////////////////////////////////////////////////////////////////////////////////////////
804 
805 /*! \class QCPPaintBufferGlFbo
806  \brief A paint buffer based on OpenGL frame buffers objects, using hardware accelerated rendering
807 
808  This paint buffer is one of the OpenGL paint buffers which facilitate hardware accelerated plot
809  rendering. It is based on OpenGL frame buffer objects (fbo) and is used in Qt versions 5.0 and
810  higher. (See \ref QCPPaintBufferGlPbuffer used in older Qt versions.)
811 
812  The OpenGL paint buffers are used if \ref QCustomPlot::setOpenGl is set to true, and if they are
813  supported by the system.
814 */
815 
816 /*!
817  Creates a \ref QCPPaintBufferGlFbo instance with the specified \a size and \a devicePixelRatio,
818  if applicable.
819 
820  All frame buffer objects shall share one OpenGL context and paint device, which need to be set up
821  externally and passed via \a glContext and \a glPaintDevice. The set-up is done in \ref
822  QCustomPlot::setupOpenGl and the context and paint device are managed by the parent QCustomPlot
823  instance.
824 */
825 QCPPaintBufferGlFbo::QCPPaintBufferGlFbo(const QSize &size, double devicePixelRatio, QWeakPointer<QOpenGLContext> glContext, QWeakPointer<QOpenGLPaintDevice> glPaintDevice) :
826  QCPAbstractPaintBuffer(size, devicePixelRatio),
827  mGlContext(glContext),
828  mGlPaintDevice(glPaintDevice),
829  mGlFrameBuffer(0)
830 {
831  QCPPaintBufferGlFbo::reallocateBuffer();
832 }
833 
834 QCPPaintBufferGlFbo::~QCPPaintBufferGlFbo()
835 {
836  if (mGlFrameBuffer)
837  delete mGlFrameBuffer;
838 }
839 
840 /* inherits documentation from base class */
841 QCPPainter *QCPPaintBufferGlFbo::startPainting()
842 {
843  QSharedPointer<QOpenGLPaintDevice> paintDevice = mGlPaintDevice.toStrongRef();
844  QSharedPointer<QOpenGLContext> context = mGlContext.toStrongRef();
845  if (!paintDevice)
846  {
847  qDebug() << Q_FUNC_INFO << "OpenGL paint device doesn't exist";
848  return 0;
849  }
850  if (!context)
851  {
852  qDebug() << Q_FUNC_INFO << "OpenGL context doesn't exist";
853  return 0;
854  }
855  if (!mGlFrameBuffer)
856  {
857  qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?";
858  return 0;
859  }
860 
861  if (QOpenGLContext::currentContext() != context.data())
862  context->makeCurrent(context->surface());
863  mGlFrameBuffer->bind();
864  QCPPainter *result = new QCPPainter(paintDevice.data());
865 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
867 #endif
868  return result;
869 }
870 
871 /* inherits documentation from base class */
872 void QCPPaintBufferGlFbo::donePainting()
873 {
874  if (mGlFrameBuffer && mGlFrameBuffer->isBound())
875  mGlFrameBuffer->release();
876  else
877  qDebug() << Q_FUNC_INFO << "Either OpenGL frame buffer not valid or was not bound";
878 }
879 
880 /* inherits documentation from base class */
881 void QCPPaintBufferGlFbo::draw(QCPPainter *painter) const
882 {
883  if (!painter || !painter->isActive())
884  {
885  qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed";
886  return;
887  }
888  if (!mGlFrameBuffer)
889  {
890  qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?";
891  return;
892  }
893  painter->drawImage(0, 0, mGlFrameBuffer->toImage());
894 }
895 
896 /* inherits documentation from base class */
897 void QCPPaintBufferGlFbo::clear(const QColor &color)
898 {
899  QSharedPointer<QOpenGLContext> context = mGlContext.toStrongRef();
900  if (!context)
901  {
902  qDebug() << Q_FUNC_INFO << "OpenGL context doesn't exist";
903  return;
904  }
905  if (!mGlFrameBuffer)
906  {
907  qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?";
908  return;
909  }
910 
911  if (QOpenGLContext::currentContext() != context.data())
912  context->makeCurrent(context->surface());
913  mGlFrameBuffer->bind();
914  glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
915  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
916  mGlFrameBuffer->release();
917 }
918 
919 /* inherits documentation from base class */
920 void QCPPaintBufferGlFbo::reallocateBuffer()
921 {
922  // release and delete possibly existing framebuffer:
923  if (mGlFrameBuffer)
924  {
925  if (mGlFrameBuffer->isBound())
926  mGlFrameBuffer->release();
927  delete mGlFrameBuffer;
928  mGlFrameBuffer = 0;
929  }
930 
931  QSharedPointer<QOpenGLPaintDevice> paintDevice = mGlPaintDevice.toStrongRef();
932  QSharedPointer<QOpenGLContext> context = mGlContext.toStrongRef();
933  if (!paintDevice)
934  {
935  qDebug() << Q_FUNC_INFO << "OpenGL paint device doesn't exist";
936  return;
937  }
938  if (!context)
939  {
940  qDebug() << Q_FUNC_INFO << "OpenGL context doesn't exist";
941  return;
942  }
943 
944  // create new fbo with appropriate size:
945  context->makeCurrent(context->surface());
946  QOpenGLFramebufferObjectFormat frameBufferFormat;
947  frameBufferFormat.setSamples(context->format().samples());
949  mGlFrameBuffer = new QOpenGLFramebufferObject(mSize*mDevicePixelRatio, frameBufferFormat);
950  if (paintDevice->size() != mSize*mDevicePixelRatio)
951  paintDevice->setSize(mSize*mDevicePixelRatio);
952 #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
953  paintDevice->setDevicePixelRatio(mDevicePixelRatio);
954 #endif
955 }
956 #endif // QCP_OPENGL_FBO
957 /* end of 'src/paintbuffer.cpp' */
958 
959 
960 /* including file 'src/layer.cpp' */
961 /* modified 2021-03-29T02:30:44, size 37615 */
962 
963 ////////////////////////////////////////////////////////////////////////////////////////////////////
964 //////////////////// QCPLayer
965 ////////////////////////////////////////////////////////////////////////////////////////////////////
966 
967 /*! \class QCPLayer
968  \brief A layer that may contain objects, to control the rendering order
969 
970  The Layering system of QCustomPlot is the mechanism to control the rendering order of the
971  elements inside the plot.
972 
973  It is based on the two classes QCPLayer and QCPLayerable. QCustomPlot holds an ordered list of
974  one or more instances of QCPLayer (see QCustomPlot::addLayer, QCustomPlot::layer,
975  QCustomPlot::moveLayer, etc.). When replotting, QCustomPlot goes through the list of layers
976  bottom to top and successively draws the layerables of the layers into the paint buffer(s).
977 
978  A QCPLayer contains an ordered list of QCPLayerable instances. QCPLayerable is an abstract base
979  class from which almost all visible objects derive, like axes, grids, graphs, items, etc.
980 
981  \section qcplayer-defaultlayers Default layers
982 
983  Initially, QCustomPlot has six layers: "background", "grid", "main", "axes", "legend" and
984  "overlay" (in that order). On top is the "overlay" layer, which only contains the QCustomPlot's
985  selection rect (\ref QCustomPlot::selectionRect). The next two layers "axes" and "legend" contain
986  the default axes and legend, so they will be drawn above plottables. In the middle, there is the
987  "main" layer. It is initially empty and set as the current layer (see
988  QCustomPlot::setCurrentLayer). This means, all new plottables, items etc. are created on this
989  layer by default. Then comes the "grid" layer which contains the QCPGrid instances (which belong
990  tightly to QCPAxis, see \ref QCPAxis::grid). The Axis rect background shall be drawn behind
991  everything else, thus the default QCPAxisRect instance is placed on the "background" layer. Of
992  course, the layer affiliation of the individual objects can be changed as required (\ref
993  QCPLayerable::setLayer).
994 
995  \section qcplayer-ordering Controlling the rendering order via layers
996 
997  Controlling the ordering of layerables in the plot is easy: Create a new layer in the position
998  you want the layerable to be in, e.g. above "main", with \ref QCustomPlot::addLayer. Then set the
999  current layer with \ref QCustomPlot::setCurrentLayer to that new layer and finally create the
1000  objects normally. They will be placed on the new layer automatically, due to the current layer
1001  setting. Alternatively you could have also ignored the current layer setting and just moved the
1002  objects with \ref QCPLayerable::setLayer to the desired layer after creating them.
1003 
1004  It is also possible to move whole layers. For example, If you want the grid to be shown in front
1005  of all plottables/items on the "main" layer, just move it above "main" with
1006  QCustomPlot::moveLayer.
1007 
1008  The rendering order within one layer is simply by order of creation or insertion. The item
1009  created last (or added last to the layer), is drawn on top of all other objects on that layer.
1010 
1011  When a layer is deleted, the objects on it are not deleted with it, but fall on the layer below
1012  the deleted layer, see QCustomPlot::removeLayer.
1013 
1014  \section qcplayer-buffering Replotting only a specific layer
1015 
1016  If the layer mode (\ref setMode) is set to \ref lmBuffered, you can replot only this specific
1017  layer by calling \ref replot. In certain situations this can provide better replot performance,
1018  compared with a full replot of all layers. Upon creation of a new layer, the layer mode is
1019  initialized to \ref lmLogical. The only layer that is set to \ref lmBuffered in a new \ref
1020  QCustomPlot instance is the "overlay" layer, containing the selection rect.
1021 */
1022 
1023 /* start documentation of inline functions */
1024 
1025 /*! \fn QList<QCPLayerable*> QCPLayer::children() const
1026 
1027  Returns a list of all layerables on this layer. The order corresponds to the rendering order:
1028  layerables with higher indices are drawn above layerables with lower indices.
1029 */
1030 
1031 /*! \fn int QCPLayer::index() const
1032 
1033  Returns the index this layer has in the QCustomPlot. The index is the integer number by which this layer can be
1034  accessed via \ref QCustomPlot::layer.
1035 
1036  Layers with higher indices will be drawn above layers with lower indices.
1037 */
1038 
1039 /* end documentation of inline functions */
1040 
1041 /*!
1042  Creates a new QCPLayer instance.
1043 
1044  Normally you shouldn't directly instantiate layers, use \ref QCustomPlot::addLayer instead.
1045 
1046  \warning It is not checked that \a layerName is actually a unique layer name in \a parentPlot.
1047  This check is only performed by \ref QCustomPlot::addLayer.
1048 */
1049 QCPLayer::QCPLayer(QCustomPlot *parentPlot, const QString &layerName) :
1050  QObject(parentPlot),
1051  mParentPlot(parentPlot),
1052  mName(layerName),
1053  mIndex(-1), // will be set to a proper value by the QCustomPlot layer creation function
1054  mVisible(true),
1055  mMode(lmLogical)
1056 {
1057  // Note: no need to make sure layerName is unique, because layer
1058  // management is done with QCustomPlot functions.
1059 }
1060 
1061 QCPLayer::~QCPLayer()
1062 {
1063  // If child layerables are still on this layer, detach them, so they don't try to reach back to this
1064  // then invalid layer once they get deleted/moved themselves. This only happens when layers are deleted
1065  // directly, like in the QCustomPlot destructor. (The regular layer removal procedure for the user is to
1066  // call QCustomPlot::removeLayer, which moves all layerables off this layer before deleting it.)
1067 
1068  while (!mChildren.isEmpty())
1069  mChildren.last()->setLayer(nullptr); // removes itself from mChildren via removeChild()
1070 
1071  if (mParentPlot->currentLayer() == this)
1072  qDebug() << Q_FUNC_INFO << "The parent plot's mCurrentLayer will be a dangling pointer. Should have been set to a valid layer or nullptr beforehand.";
1073 }
1074 
1075 /*!
1076  Sets whether this layer is visible or not. If \a visible is set to false, all layerables on this
1077  layer will be invisible.
1078 
1079  This function doesn't change the visibility property of the layerables (\ref
1080  QCPLayerable::setVisible), but the \ref QCPLayerable::realVisibility of each layerable takes the
1081  visibility of the parent layer into account.
1082 */
1083 void QCPLayer::setVisible(bool visible)
1084 {
1085  mVisible = visible;
1086 }
1087 
1088 /*!
1089  Sets the rendering mode of this layer.
1090 
1091  If \a mode is set to \ref lmBuffered for a layer, it will be given a dedicated paint buffer by
1092  the parent QCustomPlot instance. This means it may be replotted individually by calling \ref
1093  QCPLayer::replot, without needing to replot all other layers.
1094 
1095  Layers which are set to \ref lmLogical (the default) are used only to define the rendering order
1096  and can't be replotted individually.
1097 
1098  Note that each layer which is set to \ref lmBuffered requires additional paint buffers for the
1099  layers below, above and for the layer itself. This increases the memory consumption and
1100  (slightly) decreases the repainting speed because multiple paint buffers need to be joined. So
1101  you should carefully choose which layers benefit from having their own paint buffer. A typical
1102  example would be a layer which contains certain layerables (e.g. items) that need to be changed
1103  and thus replotted regularly, while all other layerables on other layers stay static. By default,
1104  only the topmost layer called "overlay" is in mode \ref lmBuffered, and contains the selection
1105  rect.
1106 
1107  \see replot
1108 */
1110 {
1111  if (mMode != mode)
1112  {
1113  mMode = mode;
1114  if (QSharedPointer<QCPAbstractPaintBuffer> pb = mPaintBuffer.toStrongRef())
1115  pb->setInvalidated();
1116  }
1117 }
1118 
1119 /*! \internal
1120 
1121  Draws the contents of this layer with the provided \a painter.
1122 
1123  \see replot, drawToPaintBuffer
1124 */
1126 {
1127  foreach (QCPLayerable *child, mChildren)
1128  {
1129  if (child->realVisibility())
1130  {
1131  painter->save();
1132  painter->setClipRect(child->clipRect().translated(0, -1));
1133  child->applyDefaultAntialiasingHint(painter);
1134  child->draw(painter);
1135  painter->restore();
1136  }
1137  }
1138 }
1139 
1140 /*! \internal
1141 
1142  Draws the contents of this layer into the paint buffer which is associated with this layer. The
1143  association is established by the parent QCustomPlot, which manages all paint buffers (see \ref
1144  QCustomPlot::setupPaintBuffers).
1145 
1146  \see draw
1147 */
1149 {
1150  if (QSharedPointer<QCPAbstractPaintBuffer> pb = mPaintBuffer.toStrongRef())
1151  {
1152  if (QCPPainter *painter = pb->startPainting())
1153  {
1154  if (painter->isActive())
1155  draw(painter);
1156  else
1157  qDebug() << Q_FUNC_INFO << "paint buffer returned inactive painter";
1158  delete painter;
1159  pb->donePainting();
1160  } else
1161  qDebug() << Q_FUNC_INFO << "paint buffer returned nullptr painter";
1162  } else
1163  qDebug() << Q_FUNC_INFO << "no valid paint buffer associated with this layer";
1164 }
1165 
1166 /*!
1167  If the layer mode (\ref setMode) is set to \ref lmBuffered, this method allows replotting only
1168  the layerables on this specific layer, without the need to replot all other layers (as a call to
1169  \ref QCustomPlot::replot would do).
1170 
1171  QCustomPlot also makes sure to replot all layers instead of only this one, if the layer ordering
1172  or any layerable-layer-association has changed since the last full replot and any other paint
1173  buffers were thus invalidated.
1174 
1175  If the layer mode is \ref lmLogical however, this method simply calls \ref QCustomPlot::replot on
1176  the parent QCustomPlot instance.
1177 
1178  \see draw
1179 */
1181 {
1182  if (mMode == lmBuffered && !mParentPlot->hasInvalidatedPaintBuffers())
1183  {
1184  if (QSharedPointer<QCPAbstractPaintBuffer> pb = mPaintBuffer.toStrongRef())
1185  {
1186  pb->clear(Qt::transparent);
1188  pb->setInvalidated(false); // since layer is lmBuffered, we know only this layer is on buffer and we can reset invalidated flag
1189  mParentPlot->update();
1190  } else
1191  qDebug() << Q_FUNC_INFO << "no valid paint buffer associated with this layer";
1192  } else
1193  mParentPlot->replot();
1194 }
1195 
1196 /*! \internal
1197 
1198  Adds the \a layerable to the list of this layer. If \a prepend is set to true, the layerable will
1199  be prepended to the list, i.e. be drawn beneath the other layerables already in the list.
1200 
1201  This function does not change the \a mLayer member of \a layerable to this layer. (Use
1202  QCPLayerable::setLayer to change the layer of an object, not this function.)
1203 
1204  \see removeChild
1205 */
1206 void QCPLayer::addChild(QCPLayerable *layerable, bool prepend)
1207 {
1208  if (!mChildren.contains(layerable))
1209  {
1210  if (prepend)
1211  mChildren.prepend(layerable);
1212  else
1213  mChildren.append(layerable);
1214  if (QSharedPointer<QCPAbstractPaintBuffer> pb = mPaintBuffer.toStrongRef())
1215  pb->setInvalidated();
1216  } else
1217  qDebug() << Q_FUNC_INFO << "layerable is already child of this layer" << reinterpret_cast<quintptr>(layerable);
1218 }
1219 
1220 /*! \internal
1221 
1222  Removes the \a layerable from the list of this layer.
1223 
1224  This function does not change the \a mLayer member of \a layerable. (Use QCPLayerable::setLayer
1225  to change the layer of an object, not this function.)
1226 
1227  \see addChild
1228 */
1230 {
1231  if (mChildren.removeOne(layerable))
1232  {
1233  if (QSharedPointer<QCPAbstractPaintBuffer> pb = mPaintBuffer.toStrongRef())
1234  pb->setInvalidated();
1235  } else
1236  qDebug() << Q_FUNC_INFO << "layerable is not child of this layer" << reinterpret_cast<quintptr>(layerable);
1237 }
1238 
1239 
1240 ////////////////////////////////////////////////////////////////////////////////////////////////////
1241 //////////////////// QCPLayerable
1242 ////////////////////////////////////////////////////////////////////////////////////////////////////
1243 
1244 /*! \class QCPLayerable
1245  \brief Base class for all drawable objects
1246 
1247  This is the abstract base class most visible objects derive from, e.g. plottables, axes, grid
1248  etc.
1249 
1250  Every layerable is on a layer (QCPLayer) which allows controlling the rendering order by stacking
1251  the layers accordingly.
1252 
1253  For details about the layering mechanism, see the QCPLayer documentation.
1254 */
1255 
1256 /* start documentation of inline functions */
1257 
1258 /*! \fn QCPLayerable *QCPLayerable::parentLayerable() const
1259 
1260  Returns the parent layerable of this layerable. The parent layerable is used to provide
1261  visibility hierarchies in conjunction with the method \ref realVisibility. This way, layerables
1262  only get drawn if their parent layerables are visible, too.
1263 
1264  Note that a parent layerable is not necessarily also the QObject parent for memory management.
1265  Further, a layerable doesn't always have a parent layerable, so this function may return \c
1266  nullptr.
1267 
1268  A parent layerable is set implicitly when placed inside layout elements and doesn't need to be
1269  set manually by the user.
1270 */
1271 
1272 /* end documentation of inline functions */
1273 /* start documentation of pure virtual functions */
1274 
1275 /*! \fn virtual void QCPLayerable::applyDefaultAntialiasingHint(QCPPainter *painter) const = 0
1276  \internal
1277 
1278  This function applies the default antialiasing setting to the specified \a painter, using the
1279  function \ref applyAntialiasingHint. It is the antialiasing state the painter is put in, when
1280  \ref draw is called on the layerable. If the layerable has multiple entities whose antialiasing
1281  setting may be specified individually, this function should set the antialiasing state of the
1282  most prominent entity. In this case however, the \ref draw function usually calls the specialized
1283  versions of this function before drawing each entity, effectively overriding the setting of the
1284  default antialiasing hint.
1285 
1286  <b>First example:</b> QCPGraph has multiple entities that have an antialiasing setting: The graph
1287  line, fills and scatters. Those can be configured via QCPGraph::setAntialiased,
1288  QCPGraph::setAntialiasedFill and QCPGraph::setAntialiasedScatters. Consequently, there isn't only
1289  the QCPGraph::applyDefaultAntialiasingHint function (which corresponds to the graph line's
1290  antialiasing), but specialized ones like QCPGraph::applyFillAntialiasingHint and
1291  QCPGraph::applyScattersAntialiasingHint. So before drawing one of those entities, QCPGraph::draw
1292  calls the respective specialized applyAntialiasingHint function.
1293 
1294  <b>Second example:</b> QCPItemLine consists only of a line so there is only one antialiasing
1295  setting which can be controlled with QCPItemLine::setAntialiased. (This function is inherited by
1296  all layerables. The specialized functions, as seen on QCPGraph, must be added explicitly to the
1297  respective layerable subclass.) Consequently it only has the normal
1298  QCPItemLine::applyDefaultAntialiasingHint. The \ref QCPItemLine::draw function doesn't need to
1299  care about setting any antialiasing states, because the default antialiasing hint is already set
1300  on the painter when the \ref draw function is called, and that's the state it wants to draw the
1301  line with.
1302 */
1303 
1304 /*! \fn virtual void QCPLayerable::draw(QCPPainter *painter) const = 0
1305  \internal
1306 
1307  This function draws the layerable with the specified \a painter. It is only called by
1308  QCustomPlot, if the layerable is visible (\ref setVisible).
1309 
1310  Before this function is called, the painter's antialiasing state is set via \ref
1311  applyDefaultAntialiasingHint, see the documentation there. Further, the clipping rectangle was
1312  set to \ref clipRect.
1313 */
1314 
1315 /* end documentation of pure virtual functions */
1316 /* start documentation of signals */
1317 
1318 /*! \fn void QCPLayerable::layerChanged(QCPLayer *newLayer);
1319 
1320  This signal is emitted when the layer of this layerable changes, i.e. this layerable is moved to
1321  a different layer.
1322 
1323  \see setLayer
1324 */
1325 
1326 /* end documentation of signals */
1327 
1328 /*!
1329  Creates a new QCPLayerable instance.
1330 
1331  Since QCPLayerable is an abstract base class, it can't be instantiated directly. Use one of the
1332  derived classes.
1333 
1334  If \a plot is provided, it automatically places itself on the layer named \a targetLayer. If \a
1335  targetLayer is an empty string, it places itself on the current layer of the plot (see \ref
1336  QCustomPlot::setCurrentLayer).
1337 
1338  It is possible to provide \c nullptr as \a plot. In that case, you should assign a parent plot at
1339  a later time with \ref initializeParentPlot.
1340 
1341  The layerable's parent layerable is set to \a parentLayerable, if provided. Direct layerable
1342  parents are mainly used to control visibility in a hierarchy of layerables. This means a
1343  layerable is only drawn, if all its ancestor layerables are also visible. Note that \a
1344  parentLayerable does not become the QObject-parent (for memory management) of this layerable, \a
1345  plot does. It is not uncommon to set the QObject-parent to something else in the constructors of
1346  QCPLayerable subclasses, to guarantee a working destruction hierarchy.
1347 */
1348 QCPLayerable::QCPLayerable(QCustomPlot *plot, QString targetLayer, QCPLayerable *parentLayerable) :
1349  QObject(plot),
1350  mVisible(true),
1351  mParentPlot(plot),
1352  mParentLayerable(parentLayerable),
1353  mLayer(nullptr),
1354  mAntialiased(true)
1355 {
1356  if (mParentPlot)
1357  {
1358  if (targetLayer.isEmpty())
1359  setLayer(mParentPlot->currentLayer());
1360  else if (!setLayer(targetLayer))
1361  qDebug() << Q_FUNC_INFO << "setting QCPlayerable initial layer to" << targetLayer << "failed.";
1362  }
1363 }
1364 
1365 QCPLayerable::~QCPLayerable()
1366 {
1367  if (mLayer)
1368  {
1369  mLayer->removeChild(this);
1370  mLayer = nullptr;
1371  }
1372 }
1373 
1374 /*!
1375  Sets the visibility of this layerable object. If an object is not visible, it will not be drawn
1376  on the QCustomPlot surface, and user interaction with it (e.g. click and selection) is not
1377  possible.
1378 */
1380 {
1381  mVisible = on;
1382 }
1383 
1384 /*!
1385  Sets the \a layer of this layerable object. The object will be placed on top of the other objects
1386  already on \a layer.
1387 
1388  If \a layer is 0, this layerable will not be on any layer and thus not appear in the plot (or
1389  interact/receive events).
1390 
1391  Returns true if the layer of this layerable was successfully changed to \a layer.
1392 */
1394 {
1395  return moveToLayer(layer, false);
1396 }
1397 
1398 /*! \overload
1399  Sets the layer of this layerable object by name
1400 
1401  Returns true on success, i.e. if \a layerName is a valid layer name.
1402 */
1403 bool QCPLayerable::setLayer(const QString &layerName)
1404 {
1405  if (!mParentPlot)
1406  {
1407  qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set";
1408  return false;
1409  }
1410  if (QCPLayer *layer = mParentPlot->layer(layerName))
1411  {
1412  return setLayer(layer);
1413  } else
1414  {
1415  qDebug() << Q_FUNC_INFO << "there is no layer with name" << layerName;
1416  return false;
1417  }
1418 }
1419 
1420 /*!
1421  Sets whether this object will be drawn antialiased or not.
1422 
1423  Note that antialiasing settings may be overridden by QCustomPlot::setAntialiasedElements and
1424  QCustomPlot::setNotAntialiasedElements.
1425 */
1427 {
1428  mAntialiased = enabled;
1429 }
1430 
1431 /*!
1432  Returns whether this layerable is visible, taking the visibility of the layerable parent and the
1433  visibility of this layerable's layer into account. This is the method that is consulted to decide
1434  whether a layerable shall be drawn or not.
1435 
1436  If this layerable has a direct layerable parent (usually set via hierarchies implemented in
1437  subclasses, like in the case of \ref QCPLayoutElement), this function returns true only if this
1438  layerable has its visibility set to true and the parent layerable's \ref realVisibility returns
1439  true.
1440 */
1442 {
1443  return mVisible && (!mLayer || mLayer->visible()) && (!mParentLayerable || mParentLayerable.data()->realVisibility());
1444 }
1445 
1446 /*!
1447  This function is used to decide whether a click hits a layerable object or not.
1448 
1449  \a pos is a point in pixel coordinates on the QCustomPlot surface. This function returns the
1450  shortest pixel distance of this point to the object. If the object is either invisible or the
1451  distance couldn't be determined, -1.0 is returned. Further, if \a onlySelectable is true and the
1452  object is not selectable, -1.0 is returned, too.
1453 
1454  If the object is represented not by single lines but by an area like a \ref QCPItemText or the
1455  bars of a \ref QCPBars plottable, a click inside the area should also be considered a hit. In
1456  these cases this function thus returns a constant value greater zero but still below the parent
1457  plot's selection tolerance. (typically the selectionTolerance multiplied by 0.99).
1458 
1459  Providing a constant value for area objects allows selecting line objects even when they are
1460  obscured by such area objects, by clicking close to the lines (i.e. closer than
1461  0.99*selectionTolerance).
1462 
1463  The actual setting of the selection state is not done by this function. This is handled by the
1464  parent QCustomPlot when the mouseReleaseEvent occurs, and the finally selected object is notified
1465  via the \ref selectEvent/\ref deselectEvent methods.
1466 
1467  \a details is an optional output parameter. Every layerable subclass may place any information
1468  in \a details. This information will be passed to \ref selectEvent when the parent QCustomPlot
1469  decides on the basis of this selectTest call, that the object was successfully selected. The
1470  subsequent call to \ref selectEvent will carry the \a details. This is useful for multi-part
1471  objects (like QCPAxis). This way, a possibly complex calculation to decide which part was clicked
1472  is only done once in \ref selectTest. The result (i.e. the actually clicked part) can then be
1473  placed in \a details. So in the subsequent \ref selectEvent, the decision which part was
1474  selected doesn't have to be done a second time for a single selection operation.
1475 
1476  In the case of 1D Plottables (\ref QCPAbstractPlottable1D, like \ref QCPGraph or \ref QCPBars) \a
1477  details will be set to a \ref QCPDataSelection, describing the closest data point to \a pos.
1478 
1479  You may pass \c nullptr as \a details to indicate that you are not interested in those selection
1480  details.
1481 
1482  \see selectEvent, deselectEvent, mousePressEvent, wheelEvent, QCustomPlot::setInteractions,
1483  QCPAbstractPlottable1D::selectTestRect
1484 */
1485 double QCPLayerable::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
1486 {
1487  Q_UNUSED(pos)
1488  Q_UNUSED(onlySelectable)
1489  Q_UNUSED(details)
1490  return -1.0;
1491 }
1492 
1493 /*! \internal
1494 
1495  Sets the parent plot of this layerable. Use this function once to set the parent plot if you have
1496  passed \c nullptr in the constructor. It can not be used to move a layerable from one QCustomPlot
1497  to another one.
1498 
1499  Note that, unlike when passing a non \c nullptr parent plot in the constructor, this function
1500  does not make \a parentPlot the QObject-parent of this layerable. If you want this, call
1501  QObject::setParent(\a parentPlot) in addition to this function.
1502 
1503  Further, you will probably want to set a layer (\ref setLayer) after calling this function, to
1504  make the layerable appear on the QCustomPlot.
1505 
1506  The parent plot change will be propagated to subclasses via a call to \ref parentPlotInitialized
1507  so they can react accordingly (e.g. also initialize the parent plot of child layerables, like
1508  QCPLayout does).
1509 */
1511 {
1512  if (mParentPlot)
1513  {
1514  qDebug() << Q_FUNC_INFO << "called with mParentPlot already initialized";
1515  return;
1516  }
1517 
1518  if (!parentPlot)
1519  qDebug() << Q_FUNC_INFO << "called with parentPlot zero";
1520 
1521  mParentPlot = parentPlot;
1522  parentPlotInitialized(mParentPlot);
1523 }
1524 
1525 /*! \internal
1526 
1527  Sets the parent layerable of this layerable to \a parentLayerable. Note that \a parentLayerable does not
1528  become the QObject-parent (for memory management) of this layerable.
1529 
1530  The parent layerable has influence on the return value of the \ref realVisibility method. Only
1531  layerables with a fully visible parent tree will return true for \ref realVisibility, and thus be
1532  drawn.
1533 
1534  \see realVisibility
1535 */
1537 {
1538  mParentLayerable = parentLayerable;
1539 }
1540 
1541 /*! \internal
1542 
1543  Moves this layerable object to \a layer. If \a prepend is true, this object will be prepended to
1544  the new layer's list, i.e. it will be drawn below the objects already on the layer. If it is
1545  false, the object will be appended.
1546 
1547  Returns true on success, i.e. if \a layer is a valid layer.
1548 */
1549 bool QCPLayerable::moveToLayer(QCPLayer *layer, bool prepend)
1550 {
1551  if (layer && !mParentPlot)
1552  {
1553  qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set";
1554  return false;
1555  }
1556  if (layer && layer->parentPlot() != mParentPlot)
1557  {
1558  qDebug() << Q_FUNC_INFO << "layer" << layer->name() << "is not in same QCustomPlot as this layerable";
1559  return false;
1560  }
1561 
1562  QCPLayer *oldLayer = mLayer;
1563  if (mLayer)
1564  mLayer->removeChild(this);
1565  mLayer = layer;
1566  if (mLayer)
1567  mLayer->addChild(this, prepend);
1568  if (mLayer != oldLayer)
1569  emit layerChanged(mLayer);
1570  return true;
1571 }
1572 
1573 /*! \internal
1574 
1575  Sets the QCPainter::setAntialiasing state on the provided \a painter, depending on the \a
1576  localAntialiased value as well as the overrides \ref QCustomPlot::setAntialiasedElements and \ref
1577  QCustomPlot::setNotAntialiasedElements. Which override enum this function takes into account is
1578  controlled via \a overrideElement.
1579 */
1580 void QCPLayerable::applyAntialiasingHint(QCPPainter *painter, bool localAntialiased, QCP::AntialiasedElement overrideElement) const
1581 {
1582  if (mParentPlot && mParentPlot->notAntialiasedElements().testFlag(overrideElement))
1583  painter->setAntialiasing(false);
1584  else if (mParentPlot && mParentPlot->antialiasedElements().testFlag(overrideElement))
1585  painter->setAntialiasing(true);
1586  else
1587  painter->setAntialiasing(localAntialiased);
1588 }
1589 
1590 /*! \internal
1591 
1592  This function is called by \ref initializeParentPlot, to allow subclasses to react on the setting
1593  of a parent plot. This is the case when \c nullptr was passed as parent plot in the constructor,
1594  and the parent plot is set at a later time.
1595 
1596  For example, QCPLayoutElement/QCPLayout hierarchies may be created independently of any
1597  QCustomPlot at first. When they are then added to a layout inside the QCustomPlot, the top level
1598  element of the hierarchy gets its parent plot initialized with \ref initializeParentPlot. To
1599  propagate the parent plot to all the children of the hierarchy, the top level element then uses
1600  this function to pass the parent plot on to its child elements.
1601 
1602  The default implementation does nothing.
1603 
1604  \see initializeParentPlot
1605 */
1607 {
1608  Q_UNUSED(parentPlot)
1609 }
1610 
1611 /*! \internal
1612 
1613  Returns the selection category this layerable shall belong to. The selection category is used in
1614  conjunction with \ref QCustomPlot::setInteractions to control which objects are selectable and
1615  which aren't.
1616 
1617  Subclasses that don't fit any of the normal \ref QCP::Interaction values can use \ref
1618  QCP::iSelectOther. This is what the default implementation returns.
1619 
1620  \see QCustomPlot::setInteractions
1621 */
1623 {
1624  return QCP::iSelectOther;
1625 }
1626 
1627 /*! \internal
1628 
1629  Returns the clipping rectangle of this layerable object. By default, this is the viewport of the
1630  parent QCustomPlot. Specific subclasses may reimplement this function to provide different
1631  clipping rects.
1632 
1633  The returned clipping rect is set on the painter before the draw function of the respective
1634  object is called.
1635 */
1637 {
1638  if (mParentPlot)
1639  return mParentPlot->viewport();
1640  else
1641  return {};
1642 }
1643 
1644 /*! \internal
1645 
1646  This event is called when the layerable shall be selected, as a consequence of a click by the
1647  user. Subclasses should react to it by setting their selection state appropriately. The default
1648  implementation does nothing.
1649 
1650  \a event is the mouse event that caused the selection. \a additive indicates, whether the user
1651  was holding the multi-select-modifier while performing the selection (see \ref
1652  QCustomPlot::setMultiSelectModifier). if \a additive is true, the selection state must be toggled
1653  (i.e. become selected when unselected and unselected when selected).
1654 
1655  Every selectEvent is preceded by a call to \ref selectTest, which has returned positively (i.e.
1656  returned a value greater than 0 and less than the selection tolerance of the parent QCustomPlot).
1657  The \a details data you output from \ref selectTest is fed back via \a details here. You may
1658  use it to transport any kind of information from the selectTest to the possibly subsequent
1659  selectEvent. Usually \a details is used to transfer which part was clicked, if it is a layerable
1660  that has multiple individually selectable parts (like QCPAxis). This way selectEvent doesn't need
1661  to do the calculation again to find out which part was actually clicked.
1662 
1663  \a selectionStateChanged is an output parameter. If the pointer is non-null, this function must
1664  set the value either to true or false, depending on whether the selection state of this layerable
1665  was actually changed. For layerables that only are selectable as a whole and not in parts, this
1666  is simple: if \a additive is true, \a selectionStateChanged must also be set to true, because the
1667  selection toggles. If \a additive is false, \a selectionStateChanged is only set to true, if the
1668  layerable was previously unselected and now is switched to the selected state.
1669 
1670  \see selectTest, deselectEvent
1671 */
1672 void QCPLayerable::selectEvent(QMouseEvent *event, bool additive, const QVariant &details, bool *selectionStateChanged)
1673 {
1674  Q_UNUSED(event)
1675  Q_UNUSED(additive)
1676  Q_UNUSED(details)
1677  Q_UNUSED(selectionStateChanged)
1678 }
1679 
1680 /*! \internal
1681 
1682  This event is called when the layerable shall be deselected, either as consequence of a user
1683  interaction or a call to \ref QCustomPlot::deselectAll. Subclasses should react to it by
1684  unsetting their selection appropriately.
1685 
1686  just as in \ref selectEvent, the output parameter \a selectionStateChanged (if non-null), must
1687  return true or false when the selection state of this layerable has changed or not changed,
1688  respectively.
1689 
1690  \see selectTest, selectEvent
1691 */
1692 void QCPLayerable::deselectEvent(bool *selectionStateChanged)
1693 {
1694  Q_UNUSED(selectionStateChanged)
1695 }
1696 
1697 /*!
1698  This event gets called when the user presses a mouse button while the cursor is over the
1699  layerable. Whether a cursor is over the layerable is decided by a preceding call to \ref
1700  selectTest.
1701 
1702  The current pixel position of the cursor on the QCustomPlot widget is accessible via \c
1703  event->pos(). The parameter \a details contains layerable-specific details about the hit, which
1704  were generated in the previous call to \ref selectTest. For example, One-dimensional plottables
1705  like \ref QCPGraph or \ref QCPBars convey the clicked data point in the \a details parameter, as
1706  \ref QCPDataSelection packed as QVariant. Multi-part objects convey the specific \c
1707  SelectablePart that was hit (e.g. \ref QCPAxis::SelectablePart in the case of axes).
1708 
1709  QCustomPlot uses an event propagation system that works the same as Qt's system. If your
1710  layerable doesn't reimplement the \ref mousePressEvent or explicitly calls \c event->ignore() in
1711  its reimplementation, the event will be propagated to the next layerable in the stacking order.
1712 
1713  Once a layerable has accepted the \ref mousePressEvent, it is considered the mouse grabber and
1714  will receive all following calls to \ref mouseMoveEvent or \ref mouseReleaseEvent for this mouse
1715  interaction (a "mouse interaction" in this context ends with the release).
1716 
1717  The default implementation does nothing except explicitly ignoring the event with \c
1718  event->ignore().
1719 
1720  \see mouseMoveEvent, mouseReleaseEvent, mouseDoubleClickEvent, wheelEvent
1721 */
1723 {
1724  Q_UNUSED(details)
1725  event->ignore();
1726 }
1727 
1728 /*!
1729  This event gets called when the user moves the mouse while holding a mouse button, after this
1730  layerable has become the mouse grabber by accepting the preceding \ref mousePressEvent.
1731 
1732  The current pixel position of the cursor on the QCustomPlot widget is accessible via \c
1733  event->pos(). The parameter \a startPos indicates the position where the initial \ref
1734  mousePressEvent occurred, that started the mouse interaction.
1735 
1736  The default implementation does nothing.
1737 
1738  \see mousePressEvent, mouseReleaseEvent, mouseDoubleClickEvent, wheelEvent
1739 */
1740 void QCPLayerable::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
1741 {
1742  Q_UNUSED(startPos)
1743  event->ignore();
1744 }
1745 
1746 /*!
1747  This event gets called when the user releases the mouse button, after this layerable has become
1748  the mouse grabber by accepting the preceding \ref mousePressEvent.
1749 
1750  The current pixel position of the cursor on the QCustomPlot widget is accessible via \c
1751  event->pos(). The parameter \a startPos indicates the position where the initial \ref
1752  mousePressEvent occurred, that started the mouse interaction.
1753 
1754  The default implementation does nothing.
1755 
1756  \see mousePressEvent, mouseMoveEvent, mouseDoubleClickEvent, wheelEvent
1757 */
1759 {
1760  Q_UNUSED(startPos)
1761  event->ignore();
1762 }
1763 
1764 /*!
1765  This event gets called when the user presses the mouse button a second time in a double-click,
1766  while the cursor is over the layerable. Whether a cursor is over the layerable is decided by a
1767  preceding call to \ref selectTest.
1768 
1769  The \ref mouseDoubleClickEvent is called instead of the second \ref mousePressEvent. So in the
1770  case of a double-click, the event succession is
1771  <i>pressEvent &ndash; releaseEvent &ndash; doubleClickEvent &ndash; releaseEvent</i>.
1772 
1773  The current pixel position of the cursor on the QCustomPlot widget is accessible via \c
1774  event->pos(). The parameter \a details contains layerable-specific details about the hit, which
1775  were generated in the previous call to \ref selectTest. For example, One-dimensional plottables
1776  like \ref QCPGraph or \ref QCPBars convey the clicked data point in the \a details parameter, as
1777  \ref QCPDataSelection packed as QVariant. Multi-part objects convey the specific \c
1778  SelectablePart that was hit (e.g. \ref QCPAxis::SelectablePart in the case of axes).
1779 
1780  Similarly to \ref mousePressEvent, once a layerable has accepted the \ref mouseDoubleClickEvent,
1781  it is considered the mouse grabber and will receive all following calls to \ref mouseMoveEvent
1782  and \ref mouseReleaseEvent for this mouse interaction (a "mouse interaction" in this context ends
1783  with the release).
1784 
1785  The default implementation does nothing except explicitly ignoring the event with \c
1786  event->ignore().
1787 
1788  \see mousePressEvent, mouseMoveEvent, mouseReleaseEvent, wheelEvent
1789 */
1791 {
1792  Q_UNUSED(details)
1793  event->ignore();
1794 }
1795 
1796 /*!
1797  This event gets called when the user turns the mouse scroll wheel while the cursor is over the
1798  layerable. Whether a cursor is over the layerable is decided by a preceding call to \ref
1799  selectTest.
1800 
1801  The current pixel position of the cursor on the QCustomPlot widget is accessible via \c
1802  event->pos().
1803 
1804  The \c event->angleDelta() indicates how far the mouse wheel was turned, which is usually +/- 120
1805  for single rotation steps. However, if the mouse wheel is turned rapidly, multiple steps may
1806  accumulate to one event, making the delta larger. On the other hand, if the wheel has very smooth
1807  steps or none at all, the delta may be smaller.
1808 
1809  The default implementation does nothing.
1810 
1811  \see mousePressEvent, mouseMoveEvent, mouseReleaseEvent, mouseDoubleClickEvent
1812 */
1814 {
1815  event->ignore();
1816 }
1817 /* end of 'src/layer.cpp' */
1818 
1819 
1820 /* including file 'src/axis/range.cpp' */
1821 /* modified 2021-03-29T02:30:44, size 12221 */
1822 
1823 ////////////////////////////////////////////////////////////////////////////////////////////////////
1824 //////////////////// QCPRange
1825 ////////////////////////////////////////////////////////////////////////////////////////////////////
1826 /*! \class QCPRange
1827  \brief Represents the range an axis is encompassing.
1828 
1829  contains a \a lower and \a upper double value and provides convenience input, output and
1830  modification functions.
1831 
1832  \see QCPAxis::setRange
1833 */
1834 
1835 /* start of documentation of inline functions */
1836 
1837 /*! \fn double QCPRange::size() const
1838 
1839  Returns the size of the range, i.e. \a upper-\a lower
1840 */
1841 
1842 /*! \fn double QCPRange::center() const
1843 
1844  Returns the center of the range, i.e. (\a upper+\a lower)*0.5
1845 */
1846 
1847 /*! \fn void QCPRange::normalize()
1848 
1849  Makes sure \a lower is numerically smaller than \a upper. If this is not the case, the values are
1850  swapped.
1851 */
1852 
1853 /*! \fn bool QCPRange::contains(double value) const
1854 
1855  Returns true when \a value lies within or exactly on the borders of the range.
1856 */
1857 
1858 /*! \fn QCPRange &QCPRange::operator+=(const double& value)
1859 
1860  Adds \a value to both boundaries of the range.
1861 */
1862 
1863 /*! \fn QCPRange &QCPRange::operator-=(const double& value)
1864 
1865  Subtracts \a value from both boundaries of the range.
1866 */
1867 
1868 /*! \fn QCPRange &QCPRange::operator*=(const double& value)
1869 
1870  Multiplies both boundaries of the range by \a value.
1871 */
1872 
1873 /*! \fn QCPRange &QCPRange::operator/=(const double& value)
1874 
1875  Divides both boundaries of the range by \a value.
1876 */
1877 
1878 /* end of documentation of inline functions */
1879 
1880 /*!
1881  Minimum range size (\a upper - \a lower) the range changing functions will accept. Smaller
1882  intervals would cause errors due to the 11-bit exponent of double precision numbers,
1883  corresponding to a minimum magnitude of roughly 1e-308.
1884 
1885  \warning Do not use this constant to indicate "arbitrarily small" values in plotting logic (as
1886  values that will appear in the plot)! It is intended only as a bound to compare against, e.g. to
1887  prevent axis ranges from obtaining underflowing ranges.
1888 
1889  \see validRange, maxRange
1890 */
1891 const double QCPRange::minRange = 1e-280;
1892 
1893 /*!
1894  Maximum values (negative and positive) the range will accept in range-changing functions.
1895  Larger absolute values would cause errors due to the 11-bit exponent of double precision numbers,
1896  corresponding to a maximum magnitude of roughly 1e308.
1897 
1898  \warning Do not use this constant to indicate "arbitrarily large" values in plotting logic (as
1899  values that will appear in the plot)! It is intended only as a bound to compare against, e.g. to
1900  prevent axis ranges from obtaining overflowing ranges.
1901 
1902  \see validRange, minRange
1903 */
1904 const double QCPRange::maxRange = 1e250;
1905 
1906 /*!
1907  Constructs a range with \a lower and \a upper set to zero.
1908 */
1910  lower(0),
1911  upper(0)
1912 {
1913 }
1914 
1915 /*! \overload
1916 
1917  Constructs a range with the specified \a lower and \a upper values.
1918 
1919  The resulting range will be normalized (see \ref normalize), so if \a lower is not numerically
1920  smaller than \a upper, they will be swapped.
1921 */
1922 QCPRange::QCPRange(double lower, double upper) :
1923  lower(lower),
1924  upper(upper)
1925 {
1926  normalize();
1927 }
1928 
1929 /*! \overload
1930 
1931  Expands this range such that \a otherRange is contained in the new range. It is assumed that both
1932  this range and \a otherRange are normalized (see \ref normalize).
1933 
1934  If this range contains NaN as lower or upper bound, it will be replaced by the respective bound
1935  of \a otherRange.
1936 
1937  If \a otherRange is already inside the current range, this function does nothing.
1938 
1939  \see expanded
1940 */
1941 void QCPRange::expand(const QCPRange &otherRange)
1942 {
1943  if (lower > otherRange.lower || qIsNaN(lower))
1944  lower = otherRange.lower;
1945  if (upper < otherRange.upper || qIsNaN(upper))
1946  upper = otherRange.upper;
1947 }
1948 
1949 /*! \overload
1950 
1951  Expands this range such that \a includeCoord is contained in the new range. It is assumed that
1952  this range is normalized (see \ref normalize).
1953 
1954  If this range contains NaN as lower or upper bound, the respective bound will be set to \a
1955  includeCoord.
1956 
1957  If \a includeCoord is already inside the current range, this function does nothing.
1958 
1959  \see expand
1960 */
1961 void QCPRange::expand(double includeCoord)
1962 {
1963  if (lower > includeCoord || qIsNaN(lower))
1964  lower = includeCoord;
1965  if (upper < includeCoord || qIsNaN(upper))
1966  upper = includeCoord;
1967 }
1968 
1969 
1970 /*! \overload
1971 
1972  Returns an expanded range that contains this and \a otherRange. It is assumed that both this
1973  range and \a otherRange are normalized (see \ref normalize).
1974 
1975  If this range contains NaN as lower or upper bound, the returned range's bound will be taken from
1976  \a otherRange.
1977 
1978  \see expand
1979 */
1980 QCPRange QCPRange::expanded(const QCPRange &otherRange) const
1981 {
1982  QCPRange result = *this;
1983  result.expand(otherRange);
1984  return result;
1985 }
1986 
1987 /*! \overload
1988 
1989  Returns an expanded range that includes the specified \a includeCoord. It is assumed that this
1990  range is normalized (see \ref normalize).
1991 
1992  If this range contains NaN as lower or upper bound, the returned range's bound will be set to \a
1993  includeCoord.
1994 
1995  \see expand
1996 */
1997 QCPRange QCPRange::expanded(double includeCoord) const
1998 {
1999  QCPRange result = *this;
2000  result.expand(includeCoord);
2001  return result;
2002 }
2003 
2004 /*!
2005  Returns this range, possibly modified to not exceed the bounds provided as \a lowerBound and \a
2006  upperBound. If possible, the size of the current range is preserved in the process.
2007 
2008  If the range shall only be bounded at the lower side, you can set \a upperBound to \ref
2009  QCPRange::maxRange. If it shall only be bounded at the upper side, set \a lowerBound to -\ref
2010  QCPRange::maxRange.
2011 */
2012 QCPRange QCPRange::bounded(double lowerBound, double upperBound) const
2013 {
2014  if (lowerBound > upperBound)
2015  qSwap(lowerBound, upperBound);
2016 
2017  QCPRange result(lower, upper);
2018  if (result.lower < lowerBound)
2019  {
2020  result.lower = lowerBound;
2021  result.upper = lowerBound + size();
2022  if (result.upper > upperBound || qFuzzyCompare(size(), upperBound-lowerBound))
2023  result.upper = upperBound;
2024  } else if (result.upper > upperBound)
2025  {
2026  result.upper = upperBound;
2027  result.lower = upperBound - size();
2028  if (result.lower < lowerBound || qFuzzyCompare(size(), upperBound-lowerBound))
2029  result.lower = lowerBound;
2030  }
2031 
2032  return result;
2033 }
2034 
2035 /*!
2036  Returns a sanitized version of the range. Sanitized means for logarithmic scales, that
2037  the range won't span the positive and negative sign domain, i.e. contain zero. Further
2038  \a lower will always be numerically smaller (or equal) to \a upper.
2039 
2040  If the original range does span positive and negative sign domains or contains zero,
2041  the returned range will try to approximate the original range as good as possible.
2042  If the positive interval of the original range is wider than the negative interval, the
2043  returned range will only contain the positive interval, with lower bound set to \a rangeFac or
2044  \a rangeFac *\a upper, whichever is closer to zero. Same procedure is used if the negative interval
2045  is wider than the positive interval, this time by changing the \a upper bound.
2046 */
2048 {
2049  double rangeFac = 1e-3;
2050  QCPRange sanitizedRange(lower, upper);
2051  sanitizedRange.normalize();
2052  // can't have range spanning negative and positive values in log plot, so change range to fix it
2053  //if (qFuzzyCompare(sanitizedRange.lower+1, 1) && !qFuzzyCompare(sanitizedRange.upper+1, 1))
2054  if (sanitizedRange.lower == 0.0 && sanitizedRange.upper != 0.0)
2055  {
2056  // case lower is 0
2057  if (rangeFac < sanitizedRange.upper*rangeFac)
2058  sanitizedRange.lower = rangeFac;
2059  else
2060  sanitizedRange.lower = sanitizedRange.upper*rangeFac;
2061  } //else if (!qFuzzyCompare(lower+1, 1) && qFuzzyCompare(upper+1, 1))
2062  else if (sanitizedRange.lower != 0.0 && sanitizedRange.upper == 0.0)
2063  {
2064  // case upper is 0
2065  if (-rangeFac > sanitizedRange.lower*rangeFac)
2066  sanitizedRange.upper = -rangeFac;
2067  else
2068  sanitizedRange.upper = sanitizedRange.lower*rangeFac;
2069  } else if (sanitizedRange.lower < 0 && sanitizedRange.upper > 0)
2070  {
2071  // find out whether negative or positive interval is wider to decide which sign domain will be chosen
2072  if (-sanitizedRange.lower > sanitizedRange.upper)
2073  {
2074  // negative is wider, do same as in case upper is 0
2075  if (-rangeFac > sanitizedRange.lower*rangeFac)
2076  sanitizedRange.upper = -rangeFac;
2077  else
2078  sanitizedRange.upper = sanitizedRange.lower*rangeFac;
2079  } else
2080  {
2081  // positive is wider, do same as in case lower is 0
2082  if (rangeFac < sanitizedRange.upper*rangeFac)
2083  sanitizedRange.lower = rangeFac;
2084  else
2085  sanitizedRange.lower = sanitizedRange.upper*rangeFac;
2086  }
2087  }
2088  // due to normalization, case lower>0 && upper<0 should never occur, because that implies upper<lower
2089  return sanitizedRange;
2090 }
2091 
2092 /*!
2093  Returns a sanitized version of the range. Sanitized means for linear scales, that
2094  \a lower will always be numerically smaller (or equal) to \a upper.
2095 */
2097 {
2098  QCPRange sanitizedRange(lower, upper);
2099  sanitizedRange.normalize();
2100  return sanitizedRange;
2101 }
2102 
2103 /*!
2104  Checks, whether the specified range is within valid bounds, which are defined
2105  as QCPRange::maxRange and QCPRange::minRange.
2106  A valid range means:
2107  \li range bounds within -maxRange and maxRange
2108  \li range size above minRange
2109  \li range size below maxRange
2110 */
2111 bool QCPRange::validRange(double lower, double upper)
2112 {
2113  return (lower > -maxRange &&
2114  upper < maxRange &&
2115  qAbs(lower-upper) > minRange &&
2116  qAbs(lower-upper) < maxRange &&
2117  !(lower > 0 && qIsInf(upper/lower)) &&
2118  !(upper < 0 && qIsInf(lower/upper)));
2119 }
2120 
2121 /*!
2122  \overload
2123  Checks, whether the specified range is within valid bounds, which are defined
2124  as QCPRange::maxRange and QCPRange::minRange.
2125  A valid range means:
2126  \li range bounds within -maxRange and maxRange
2127  \li range size above minRange
2128  \li range size below maxRange
2129 */
2130 bool QCPRange::validRange(const QCPRange &range)
2131 {
2132  return (range.lower > -maxRange &&
2133  range.upper < maxRange &&
2134  qAbs(range.lower-range.upper) > minRange &&
2135  qAbs(range.lower-range.upper) < maxRange &&
2136  !(range.lower > 0 && qIsInf(range.upper/range.lower)) &&
2137  !(range.upper < 0 && qIsInf(range.lower/range.upper)));
2138 }
2139 /* end of 'src/axis/range.cpp' */
2140 
2141 
2142 /* including file 'src/selection.cpp' */
2143 /* modified 2021-03-29T02:30:44, size 21837 */
2144 
2145 ////////////////////////////////////////////////////////////////////////////////////////////////////
2146 //////////////////// QCPDataRange
2147 ////////////////////////////////////////////////////////////////////////////////////////////////////
2148 
2149 /*! \class QCPDataRange
2150  \brief Describes a data range given by begin and end index
2151 
2152  QCPDataRange holds two integers describing the begin (\ref setBegin) and end (\ref setEnd) index
2153  of a contiguous set of data points. The \a end index corresponds to the data point just after the
2154  last data point of the data range, like in standard iterators.
2155 
2156  Data Ranges are not bound to a certain plottable, thus they can be freely exchanged, created and
2157  modified. If a non-contiguous data set shall be described, the class \ref QCPDataSelection is
2158  used, which holds and manages multiple instances of \ref QCPDataRange. In most situations, \ref
2159  QCPDataSelection is thus used.
2160 
2161  Both \ref QCPDataRange and \ref QCPDataSelection offer convenience methods to work with them,
2162  e.g. \ref bounded, \ref expanded, \ref intersects, \ref intersection, \ref adjusted, \ref
2163  contains. Further, addition and subtraction operators (defined in \ref QCPDataSelection) can be
2164  used to join/subtract data ranges and data selections (or mixtures), to retrieve a corresponding
2165  \ref QCPDataSelection.
2166 
2167  %QCustomPlot's \ref dataselection "data selection mechanism" is based on \ref QCPDataSelection and
2168  QCPDataRange.
2169 
2170  \note Do not confuse \ref QCPDataRange with \ref QCPRange. A \ref QCPRange describes an interval
2171  in floating point plot coordinates, e.g. the current axis range.
2172 */
2173 
2174 /* start documentation of inline functions */
2175 
2176 /*! \fn int QCPDataRange::size() const
2177 
2178  Returns the number of data points described by this data range. This is equal to the end index
2179  minus the begin index.
2180 
2181  \see length
2182 */
2183 
2184 /*! \fn int QCPDataRange::length() const
2185 
2186  Returns the number of data points described by this data range. Equivalent to \ref size.
2187 */
2188 
2189 /*! \fn void QCPDataRange::setBegin(int begin)
2190 
2191  Sets the begin of this data range. The \a begin index points to the first data point that is part
2192  of the data range.
2193 
2194  No checks or corrections are made to ensure the resulting range is valid (\ref isValid).
2195 
2196  \see setEnd
2197 */
2198 
2199 /*! \fn void QCPDataRange::setEnd(int end)
2200 
2201  Sets the end of this data range. The \a end index points to the data point just after the last
2202  data point that is part of the data range.
2203 
2204  No checks or corrections are made to ensure the resulting range is valid (\ref isValid).
2205 
2206  \see setBegin
2207 */
2208 
2209 /*! \fn bool QCPDataRange::isValid() const
2210 
2211  Returns whether this range is valid. A valid range has a begin index greater or equal to 0, and
2212  an end index greater or equal to the begin index.
2213 
2214  \note Invalid ranges should be avoided and are never the result of any of QCustomPlot's methods
2215  (unless they are themselves fed with invalid ranges). Do not pass invalid ranges to QCustomPlot's
2216  methods. The invalid range is not inherently prevented in QCPDataRange, to allow temporary
2217  invalid begin/end values while manipulating the range. An invalid range is not necessarily empty
2218  (\ref isEmpty), since its \ref length can be negative and thus non-zero.
2219 */
2220 
2221 /*! \fn bool QCPDataRange::isEmpty() const
2222 
2223  Returns whether this range is empty, i.e. whether its begin index equals its end index.
2224 
2225  \see size, length
2226 */
2227 
2228 /*! \fn QCPDataRange QCPDataRange::adjusted(int changeBegin, int changeEnd) const
2229 
2230  Returns a data range where \a changeBegin and \a changeEnd were added to the begin and end
2231  indices, respectively.
2232 */
2233 
2234 /* end documentation of inline functions */
2235 
2236 /*!
2237  Creates an empty QCPDataRange, with begin and end set to 0.
2238 */
2240  mBegin(0),
2241  mEnd(0)
2242 {
2243 }
2244 
2245 /*!
2246  Creates a QCPDataRange, initialized with the specified \a begin and \a end.
2247 
2248  No checks or corrections are made to ensure the resulting range is valid (\ref isValid).
2249 */
2250 QCPDataRange::QCPDataRange(int begin, int end) :
2251  mBegin(begin),
2252  mEnd(end)
2253 {
2254 }
2255 
2256 /*!
2257  Returns a data range that matches this data range, except that parts exceeding \a other are
2258  excluded.
2259 
2260  This method is very similar to \ref intersection, with one distinction: If this range and the \a
2261  other range share no intersection, the returned data range will be empty with begin and end set
2262  to the respective boundary side of \a other, at which this range is residing. (\ref intersection
2263  would just return a range with begin and end set to 0.)
2264 */
2266 {
2267  QCPDataRange result(intersection(other));
2268  if (result.isEmpty()) // no intersection, preserve respective bounding side of otherRange as both begin and end of return value
2269  {
2270  if (mEnd <= other.mBegin)
2271  result = QCPDataRange(other.mBegin, other.mBegin);
2272  else
2273  result = QCPDataRange(other.mEnd, other.mEnd);
2274  }
2275  return result;
2276 }
2277 
2278 /*!
2279  Returns a data range that contains both this data range as well as \a other.
2280 */
2282 {
2283  return {qMin(mBegin, other.mBegin), qMax(mEnd, other.mEnd)};
2284 }
2285 
2286 /*!
2287  Returns the data range which is contained in both this data range and \a other.
2288 
2289  This method is very similar to \ref bounded, with one distinction: If this range and the \a other
2290  range share no intersection, the returned data range will be empty with begin and end set to 0.
2291  (\ref bounded would return a range with begin and end set to one of the boundaries of \a other,
2292  depending on which side this range is on.)
2293 
2294  \see QCPDataSelection::intersection
2295 */
2297 {
2298  QCPDataRange result(qMax(mBegin, other.mBegin), qMin(mEnd, other.mEnd));
2299  if (result.isValid())
2300  return result;
2301  else
2302  return {};
2303 }
2304 
2305 /*!
2306  Returns whether this data range and \a other share common data points.
2307 
2308  \see intersection, contains
2309 */
2310 bool QCPDataRange::intersects(const QCPDataRange &other) const
2311 {
2312  return !( (mBegin > other.mBegin && mBegin >= other.mEnd) ||
2313  (mEnd <= other.mBegin && mEnd < other.mEnd) );
2314 }
2315 
2316 /*!
2317  Returns whether all data points of \a other are also contained inside this data range.
2318 
2319  \see intersects
2320 */
2321 bool QCPDataRange::contains(const QCPDataRange &other) const
2322 {
2323  return mBegin <= other.mBegin && mEnd >= other.mEnd;
2324 }
2325 
2326 
2327 
2328 ////////////////////////////////////////////////////////////////////////////////////////////////////
2329 //////////////////// QCPDataSelection
2330 ////////////////////////////////////////////////////////////////////////////////////////////////////
2331 
2332 /*! \class QCPDataSelection
2333  \brief Describes a data set by holding multiple QCPDataRange instances
2334 
2335  QCPDataSelection manages multiple instances of QCPDataRange in order to represent any (possibly
2336  disjoint) set of data selection.
2337 
2338  The data selection can be modified with addition and subtraction operators which take
2339  QCPDataSelection and QCPDataRange instances, as well as methods such as \ref addDataRange and
2340  \ref clear. Read access is provided by \ref dataRange, \ref dataRanges, \ref dataRangeCount, etc.
2341 
2342  The method \ref simplify is used to join directly adjacent or even overlapping QCPDataRange
2343  instances. QCPDataSelection automatically simplifies when using the addition/subtraction
2344  operators. The only case when \ref simplify is left to the user, is when calling \ref
2345  addDataRange, with the parameter \a simplify explicitly set to false. This is useful if many data
2346  ranges will be added to the selection successively and the overhead for simplifying after each
2347  iteration shall be avoided. In this case, you should make sure to call \ref simplify after
2348  completing the operation.
2349 
2350  Use \ref enforceType to bring the data selection into a state complying with the constraints for
2351  selections defined in \ref QCP::SelectionType.
2352 
2353  %QCustomPlot's \ref dataselection "data selection mechanism" is based on QCPDataSelection and
2354  QCPDataRange.
2355 
2356  \section qcpdataselection-iterating Iterating over a data selection
2357 
2358  As an example, the following code snippet calculates the average value of a graph's data
2359  \ref QCPAbstractPlottable::selection "selection":
2360 
2361  \snippet documentation/doc-code-snippets/mainwindow.cpp qcpdataselection-iterating-1
2362 
2363 */
2364 
2365 /* start documentation of inline functions */
2366 
2367 /*! \fn int QCPDataSelection::dataRangeCount() const
2368 
2369  Returns the number of ranges that make up the data selection. The ranges can be accessed by \ref
2370  dataRange via their index.
2371 
2372  \see dataRange, dataPointCount
2373 */
2374 
2375 /*! \fn QList<QCPDataRange> QCPDataSelection::dataRanges() const
2376 
2377  Returns all data ranges that make up the data selection. If the data selection is simplified (the
2378  usual state of the selection, see \ref simplify), the ranges are sorted by ascending data point
2379  index.
2380 
2381  \see dataRange
2382 */
2383 
2384 /*! \fn bool QCPDataSelection::isEmpty() const
2385 
2386  Returns true if there are no data ranges, and thus no data points, in this QCPDataSelection
2387  instance.
2388 
2389  \see dataRangeCount
2390 */
2391 
2392 /* end documentation of inline functions */
2393 
2394 /*!
2395  Creates an empty QCPDataSelection.
2396 */
2398 {
2399 }
2400 
2401 /*!
2402  Creates a QCPDataSelection containing the provided \a range.
2403 */
2405 {
2406  mDataRanges.append(range);
2407 }
2408 
2409 /*!
2410  Returns true if this selection is identical (contains the same data ranges with the same begin
2411  and end indices) to \a other.
2412 
2413  Note that both data selections must be in simplified state (the usual state of the selection, see
2414  \ref simplify) for this operator to return correct results.
2415 */
2417 {
2418  if (mDataRanges.size() != other.mDataRanges.size())
2419  return false;
2420  for (int i=0; i<mDataRanges.size(); ++i)
2421  {
2422  if (mDataRanges.at(i) != other.mDataRanges.at(i))
2423  return false;
2424  }
2425  return true;
2426 }
2427 
2428 /*!
2429  Adds the data selection of \a other to this data selection, and then simplifies this data
2430  selection (see \ref simplify).
2431 */
2433 {
2434  mDataRanges << other.mDataRanges;
2435  simplify();
2436  return *this;
2437 }
2438 
2439 /*!
2440  Adds the data range \a other to this data selection, and then simplifies this data selection (see
2441  \ref simplify).
2442 */
2444 {
2445  addDataRange(other);
2446  return *this;
2447 }
2448 
2449 /*!
2450  Removes all data point indices that are described by \a other from this data selection.
2451 */
2453 {
2454  for (int i=0; i<other.dataRangeCount(); ++i)
2455  *this -= other.dataRange(i);
2456 
2457  return *this;
2458 }
2459 
2460 /*!
2461  Removes all data point indices that are described by \a other from this data selection.
2462 */
2464 {
2465  if (other.isEmpty() || isEmpty())
2466  return *this;
2467 
2468  simplify();
2469  int i=0;
2470  while (i < mDataRanges.size())
2471  {
2472  const int thisBegin = mDataRanges.at(i).begin();
2473  const int thisEnd = mDataRanges.at(i).end();
2474  if (thisBegin >= other.end())
2475  break; // since data ranges are sorted after the simplify() call, no ranges which contain other will come after this
2476 
2477  if (thisEnd > other.begin()) // ranges which don't fulfill this are entirely before other and can be ignored
2478  {
2479  if (thisBegin >= other.begin()) // range leading segment is encompassed
2480  {
2481  if (thisEnd <= other.end()) // range fully encompassed, remove completely
2482  {
2483  mDataRanges.removeAt(i);
2484  continue;
2485  } else // only leading segment is encompassed, trim accordingly
2486  mDataRanges[i].setBegin(other.end());
2487  } else // leading segment is not encompassed
2488  {
2489  if (thisEnd <= other.end()) // only trailing segment is encompassed, trim accordingly
2490  {
2491  mDataRanges[i].setEnd(other.begin());
2492  } else // other lies inside this range, so split range
2493  {
2494  mDataRanges[i].setEnd(other.begin());
2495  mDataRanges.insert(i+1, QCPDataRange(other.end(), thisEnd));
2496  break; // since data ranges are sorted (and don't overlap) after simplify() call, we're done here
2497  }
2498  }
2499  }
2500  ++i;
2501  }
2502 
2503  return *this;
2504 }
2505 
2506 /*!
2507  Returns the total number of data points contained in all data ranges that make up this data
2508  selection.
2509 */
2511 {
2512  int result = 0;
2513  foreach (QCPDataRange dataRange, mDataRanges)
2514  result += dataRange.length();
2515  return result;
2516 }
2517 
2518 /*!
2519  Returns the data range with the specified \a index.
2520 
2521  If the data selection is simplified (the usual state of the selection, see \ref simplify), the
2522  ranges are sorted by ascending data point index.
2523 
2524  \see dataRangeCount
2525 */
2527 {
2528  if (index >= 0 && index < mDataRanges.size())
2529  {
2530  return mDataRanges.at(index);
2531  } else
2532  {
2533  qDebug() << Q_FUNC_INFO << "index out of range:" << index;
2534  return {};
2535  }
2536 }
2537 
2538 /*!
2539  Returns a \ref QCPDataRange which spans the entire data selection, including possible
2540  intermediate segments which are not part of the original data selection.
2541 */
2543 {
2544  if (isEmpty())
2545  return {};
2546  else
2547  return {mDataRanges.first().begin(), mDataRanges.last().end()};
2548 }
2549 
2550 /*!
2551  Adds the given \a dataRange to this data selection. This is equivalent to the += operator but
2552  allows disabling immediate simplification by setting \a simplify to false. This can improve
2553  performance if adding a very large amount of data ranges successively. In this case, make sure to
2554  call \ref simplify manually, after the operation.
2555 */
2556 void QCPDataSelection::addDataRange(const QCPDataRange &dataRange, bool simplify)
2557 {
2558  mDataRanges.append(dataRange);
2559  if (simplify)
2560  this->simplify();
2561 }
2562 
2563 /*!
2564  Removes all data ranges. The data selection then contains no data points.
2565 
2566  \ref isEmpty
2567 */
2569 {
2570  mDataRanges.clear();
2571 }
2572 
2573 /*!
2574  Sorts all data ranges by range begin index in ascending order, and then joins directly adjacent
2575  or overlapping ranges. This can reduce the number of individual data ranges in the selection, and
2576  prevents possible double-counting when iterating over the data points held by the data ranges.
2577 
2578  This method is automatically called when using the addition/subtraction operators. The only case
2579  when \ref simplify is left to the user, is when calling \ref addDataRange, with the parameter \a
2580  simplify explicitly set to false.
2581 */
2583 {
2584  // remove any empty ranges:
2585  for (int i=mDataRanges.size()-1; i>=0; --i)
2586  {
2587  if (mDataRanges.at(i).isEmpty())
2588  mDataRanges.removeAt(i);
2589  }
2590  if (mDataRanges.isEmpty())
2591  return;
2592 
2593  // sort ranges by starting value, ascending:
2594  std::sort(mDataRanges.begin(), mDataRanges.end(), lessThanDataRangeBegin);
2595 
2596  // join overlapping/contiguous ranges:
2597  int i = 1;
2598  while (i < mDataRanges.size())
2599  {
2600  if (mDataRanges.at(i-1).end() >= mDataRanges.at(i).begin()) // range i overlaps/joins with i-1, so expand range i-1 appropriately and remove range i from list
2601  {
2602  mDataRanges[i-1].setEnd(qMax(mDataRanges.at(i-1).end(), mDataRanges.at(i).end()));
2603  mDataRanges.removeAt(i);
2604  } else
2605  ++i;
2606  }
2607 }
2608 
2609 /*!
2610  Makes sure this data selection conforms to the specified \a type selection type. Before the type
2611  is enforced, \ref simplify is called.
2612 
2613  Depending on \a type, enforcing means adding new data points that were previously not part of the
2614  selection, or removing data points from the selection. If the current selection already conforms
2615  to \a type, the data selection is not changed.
2616 
2617  \see QCP::SelectionType
2618 */
2620 {
2621  simplify();
2622  switch (type)
2623  {
2624  case QCP::stNone:
2625  {
2626  mDataRanges.clear();
2627  break;
2628  }
2629  case QCP::stWhole:
2630  {
2631  // whole selection isn't defined by data range, so don't change anything (is handled in plottable methods)
2632  break;
2633  }
2634  case QCP::stSingleData:
2635  {
2636  // reduce all data ranges to the single first data point:
2637  if (!mDataRanges.isEmpty())
2638  {
2639  if (mDataRanges.size() > 1)
2640  mDataRanges = QList<QCPDataRange>() << mDataRanges.first();
2641  if (mDataRanges.first().length() > 1)
2642  mDataRanges.first().setEnd(mDataRanges.first().begin()+1);
2643  }
2644  break;
2645  }
2646  case QCP::stDataRange:
2647  {
2648  if (!isEmpty())
2649  mDataRanges = QList<QCPDataRange>() << span();
2650  break;
2651  }
2653  {
2654  // this is the selection type that allows all concievable combinations of ranges, so do nothing
2655  break;
2656  }
2657  }
2658 }
2659 
2660 /*!
2661  Returns true if the data selection \a other is contained entirely in this data selection, i.e.
2662  all data point indices that are in \a other are also in this data selection.
2663 
2664  \see QCPDataRange::contains
2665 */
2667 {
2668  if (other.isEmpty()) return false;
2669 
2670  int otherIndex = 0;
2671  int thisIndex = 0;
2672  while (thisIndex < mDataRanges.size() && otherIndex < other.mDataRanges.size())
2673  {
2674  if (mDataRanges.at(thisIndex).contains(other.mDataRanges.at(otherIndex)))
2675  ++otherIndex;
2676  else
2677  ++thisIndex;
2678  }
2679  return thisIndex < mDataRanges.size(); // if thisIndex ran all the way to the end to find a containing range for the current otherIndex, other is not contained in this
2680 }
2681 
2682 /*!
2683  Returns a data selection containing the points which are both in this data selection and in the
2684  data range \a other.
2685 
2686  A common use case is to limit an unknown data selection to the valid range of a data container,
2687  using \ref QCPDataContainer::dataRange as \a other. One can then safely iterate over the returned
2688  data selection without exceeding the data container's bounds.
2689 */
2691 {
2692  QCPDataSelection result;
2693  foreach (QCPDataRange dataRange, mDataRanges)
2694  result.addDataRange(dataRange.intersection(other), false);
2695  result.simplify();
2696  return result;
2697 }
2698 
2699 /*!
2700  Returns a data selection containing the points which are both in this data selection and in the
2701  data selection \a other.
2702 */
2704 {
2705  QCPDataSelection result;
2706  for (int i=0; i<other.dataRangeCount(); ++i)
2707  result += intersection(other.dataRange(i));
2708  result.simplify();
2709  return result;
2710 }
2711 
2712 /*!
2713  Returns a data selection which is the exact inverse of this data selection, with \a outerRange
2714  defining the base range on which to invert. If \a outerRange is smaller than the \ref span of
2715  this data selection, it is expanded accordingly.
2716 
2717  For example, this method can be used to retrieve all unselected segments by setting \a outerRange
2718  to the full data range of the plottable, and calling this method on a data selection holding the
2719  selected segments.
2720 */
2722 {
2723  if (isEmpty())
2724  return QCPDataSelection(outerRange);
2725  QCPDataRange fullRange = outerRange.expanded(span());
2726 
2727  QCPDataSelection result;
2728  // first unselected segment:
2729  if (mDataRanges.first().begin() != fullRange.begin())
2730  result.addDataRange(QCPDataRange(fullRange.begin(), mDataRanges.first().begin()), false);
2731  // intermediate unselected segments:
2732  for (int i=1; i<mDataRanges.size(); ++i)
2733  result.addDataRange(QCPDataRange(mDataRanges.at(i-1).end(), mDataRanges.at(i).begin()), false);
2734  // last unselected segment:
2735  if (mDataRanges.last().end() != fullRange.end())
2736  result.addDataRange(QCPDataRange(mDataRanges.last().end(), fullRange.end()), false);
2737  result.simplify();
2738  return result;
2739 }
2740 /* end of 'src/selection.cpp' */
2741 
2742 
2743 /* including file 'src/selectionrect.cpp' */
2744 /* modified 2021-03-29T02:30:44, size 9215 */
2745 
2746 ////////////////////////////////////////////////////////////////////////////////////////////////////
2747 //////////////////// QCPSelectionRect
2748 ////////////////////////////////////////////////////////////////////////////////////////////////////
2749 
2750 /*! \class QCPSelectionRect
2751  \brief Provides rect/rubber-band data selection and range zoom interaction
2752 
2753  QCPSelectionRect is used by QCustomPlot when the \ref QCustomPlot::setSelectionRectMode is not
2754  \ref QCP::srmNone. When the user drags the mouse across the plot, the current selection rect
2755  instance (\ref QCustomPlot::setSelectionRect) is forwarded these events and makes sure an
2756  according rect shape is drawn. At the begin, during, and after completion of the interaction, it
2757  emits the corresponding signals \ref started, \ref changed, \ref canceled, and \ref accepted.
2758 
2759  The QCustomPlot instance connects own slots to the current selection rect instance, in order to
2760  react to an accepted selection rect interaction accordingly.
2761 
2762  \ref isActive can be used to check whether the selection rect is currently active. An ongoing
2763  selection interaction can be cancelled programmatically via calling \ref cancel at any time.
2764 
2765  The appearance of the selection rect can be controlled via \ref setPen and \ref setBrush.
2766 
2767  If you wish to provide custom behaviour, e.g. a different visual representation of the selection
2768  rect (\ref QCPSelectionRect::draw), you can subclass QCPSelectionRect and pass an instance of
2769  your subclass to \ref QCustomPlot::setSelectionRect.
2770 */
2771 
2772 /* start of documentation of inline functions */
2773 
2774 /*! \fn bool QCPSelectionRect::isActive() const
2775 
2776  Returns true if there is currently a selection going on, i.e. the user has started dragging a
2777  selection rect, but hasn't released the mouse button yet.
2778 
2779  \see cancel
2780 */
2781 
2782 /* end of documentation of inline functions */
2783 /* start documentation of signals */
2784 
2785 /*! \fn void QCPSelectionRect::started(QMouseEvent *event);
2786 
2787  This signal is emitted when a selection rect interaction was initiated, i.e. the user just
2788  started dragging the selection rect with the mouse.
2789 */
2790 
2791 /*! \fn void QCPSelectionRect::changed(const QRect &rect, QMouseEvent *event);
2792 
2793  This signal is emitted while the selection rect interaction is ongoing and the \a rect has
2794  changed its size due to the user moving the mouse.
2795 
2796  Note that \a rect may have a negative width or height, if the selection is being dragged to the
2797  upper or left side of the selection rect origin.
2798 */
2799 
2800 /*! \fn void QCPSelectionRect::canceled(const QRect &rect, QInputEvent *event);
2801 
2802  This signal is emitted when the selection interaction was cancelled. Note that \a event is \c
2803  nullptr if the selection interaction was cancelled programmatically, by a call to \ref cancel.
2804 
2805  The user may cancel the selection interaction by pressing the escape key. In this case, \a event
2806  holds the respective input event.
2807 
2808  Note that \a rect may have a negative width or height, if the selection is being dragged to the
2809  upper or left side of the selection rect origin.
2810 */
2811 
2812 /*! \fn void QCPSelectionRect::accepted(const QRect &rect, QMouseEvent *event);
2813 
2814  This signal is emitted when the selection interaction was completed by the user releasing the
2815  mouse button.
2816 
2817  Note that \a rect may have a negative width or height, if the selection is being dragged to the
2818  upper or left side of the selection rect origin.
2819 */
2820 
2821 /* end documentation of signals */
2822 
2823 /*!
2824  Creates a new QCPSelectionRect instance. To make QCustomPlot use the selection rect instance,
2825  pass it to \ref QCustomPlot::setSelectionRect. \a parentPlot should be set to the same
2826  QCustomPlot widget.
2827 */
2829  QCPLayerable(parentPlot),
2830  mPen(QBrush(Qt::gray), 0, Qt::DashLine),
2831  mBrush(Qt::NoBrush),
2832  mActive(false)
2833 {
2834 }
2835 
2836 QCPSelectionRect::~QCPSelectionRect()
2837 {
2838  cancel();
2839 }
2840 
2841 /*!
2842  A convenience function which returns the coordinate range of the provided \a axis, that this
2843  selection rect currently encompasses.
2844 */
2846 {
2847  if (axis)
2848  {
2849  if (axis->orientation() == Qt::Horizontal)
2850  return {axis->pixelToCoord(mRect.left()), axis->pixelToCoord(mRect.left()+mRect.width())};
2851  else
2852  return {axis->pixelToCoord(mRect.top()+mRect.height()), axis->pixelToCoord(mRect.top())};
2853  } else
2854  {
2855  qDebug() << Q_FUNC_INFO << "called with axis zero";
2856  return {};
2857  }
2858 }
2859 
2860 /*!
2861  Sets the pen that will be used to draw the selection rect outline.
2862 
2863  \see setBrush
2864 */
2866 {
2867  mPen = pen;
2868 }
2869 
2870 /*!
2871  Sets the brush that will be used to fill the selection rect. By default the selection rect is not
2872  filled, i.e. \a brush is <tt>Qt::NoBrush</tt>.
2873 
2874  \see setPen
2875 */
2877 {
2878  mBrush = brush;
2879 }
2880 
2881 /*!
2882  If there is currently a selection interaction going on (\ref isActive), the interaction is
2883  canceled. The selection rect will emit the \ref canceled signal.
2884 */
2886 {
2887  if (mActive)
2888  {
2889  mActive = false;
2890  emit canceled(mRect, nullptr);
2891  }
2892 }
2893 
2894 /*! \internal
2895 
2896  This method is called by QCustomPlot to indicate that a selection rect interaction was initiated.
2897  The default implementation sets the selection rect to active, initializes the selection rect
2898  geometry and emits the \ref started signal.
2899 */
2901 {
2902  mActive = true;
2903  mRect = QRect(event->pos(), event->pos());
2904  emit started(event);
2905 }
2906 
2907 /*! \internal
2908 
2909  This method is called by QCustomPlot to indicate that an ongoing selection rect interaction needs
2910  to update its geometry. The default implementation updates the rect and emits the \ref changed
2911  signal.
2912 */
2914 {
2915  mRect.setBottomRight(event->pos());
2916  emit changed(mRect, event);
2917  layer()->replot();
2918 }
2919 
2920 /*! \internal
2921 
2922  This method is called by QCustomPlot to indicate that an ongoing selection rect interaction has
2923  finished by the user releasing the mouse button. The default implementation deactivates the
2924  selection rect and emits the \ref accepted signal.
2925 */
2927 {
2928  mRect.setBottomRight(event->pos());
2929  mActive = false;
2930  emit accepted(mRect, event);
2931 }
2932 
2933 /*! \internal
2934 
2935  This method is called by QCustomPlot when a key has been pressed by the user while the selection
2936  rect interaction is active. The default implementation allows to \ref cancel the interaction by
2937  hitting the escape key.
2938 */
2940 {
2941  if (event->key() == Qt::Key_Escape && mActive)
2942  {
2943  mActive = false;
2944  emit canceled(mRect, event);
2945  }
2946 }
2947 
2948 /* inherits documentation from base class */
2950 {
2951  applyAntialiasingHint(painter, mAntialiased, QCP::aeOther);
2952 }
2953 
2954 /*! \internal
2955 
2956  If the selection rect is active (\ref isActive), draws the selection rect defined by \a mRect.
2957 
2958  \seebaseclassmethod
2959 */
2961 {
2962  if (mActive)
2963  {
2964  painter->setPen(mPen);
2965  painter->setBrush(mBrush);
2966  painter->drawRect(mRect);
2967  }
2968 }
2969 /* end of 'src/selectionrect.cpp' */
2970 
2971 
2972 /* including file 'src/layout.cpp' */
2973 /* modified 2021-03-29T02:30:44, size 78863 */
2974 
2975 ////////////////////////////////////////////////////////////////////////////////////////////////////
2976 //////////////////// QCPMarginGroup
2977 ////////////////////////////////////////////////////////////////////////////////////////////////////
2978 
2979 /*! \class QCPMarginGroup
2980  \brief A margin group allows synchronization of margin sides if working with multiple layout elements.
2981 
2982  QCPMarginGroup allows you to tie a margin side of two or more layout elements together, such that
2983  they will all have the same size, based on the largest required margin in the group.
2984 
2985  \n
2986  \image html QCPMarginGroup.png "Demonstration of QCPMarginGroup"
2987  \n
2988 
2989  In certain situations it is desirable that margins at specific sides are synchronized across
2990  layout elements. For example, if one QCPAxisRect is below another one in a grid layout, it will
2991  provide a cleaner look to the user if the left and right margins of the two axis rects are of the
2992  same size. The left axis of the top axis rect will then be at the same horizontal position as the
2993  left axis of the lower axis rect, making them appear aligned. The same applies for the right
2994  axes. This is what QCPMarginGroup makes possible.
2995 
2996  To add/remove a specific side of a layout element to/from a margin group, use the \ref
2997  QCPLayoutElement::setMarginGroup method. To completely break apart the margin group, either call
2998  \ref clear, or just delete the margin group.
2999 
3000  \section QCPMarginGroup-example Example
3001 
3002  First create a margin group:
3003  \snippet documentation/doc-code-snippets/mainwindow.cpp qcpmargingroup-creation-1
3004  Then set this group on the layout element sides:
3005  \snippet documentation/doc-code-snippets/mainwindow.cpp qcpmargingroup-creation-2
3006  Here, we've used the first two axis rects of the plot and synchronized their left margins with
3007  each other and their right margins with each other.
3008 */
3009 
3010 /* start documentation of inline functions */
3011 
3012 /*! \fn QList<QCPLayoutElement*> QCPMarginGroup::elements(QCP::MarginSide side) const
3013 
3014  Returns a list of all layout elements that have their margin \a side associated with this margin
3015  group.
3016 */
3017 
3018 /* end documentation of inline functions */
3019 
3020 /*!
3021  Creates a new QCPMarginGroup instance in \a parentPlot.
3022 */
3024  QObject(parentPlot),
3025  mParentPlot(parentPlot)
3026 {
3031 }
3032 
3033 QCPMarginGroup::~QCPMarginGroup()
3034 {
3035  clear();
3036 }
3037 
3038 /*!
3039  Returns whether this margin group is empty. If this function returns true, no layout elements use
3040  this margin group to synchronize margin sides.
3041 */
3043 {
3045  while (it.hasNext())
3046  {
3047  it.next();
3048  if (!it.value().isEmpty())
3049  return false;
3050  }
3051  return true;
3052 }
3053 
3054 /*!
3055  Clears this margin group. The synchronization of the margin sides that use this margin group is
3056  lifted and they will use their individual margin sizes again.
3057 */
3059 {
3060  // make all children remove themselves from this margin group:
3062  while (it.hasNext())
3063  {
3064  it.next();
3066  for (int i=elements.size()-1; i>=0; --i)
3067  elements.at(i)->setMarginGroup(it.key(), nullptr); // removes itself from mChildren via removeChild
3068  }
3069 }
3070 
3071 /*! \internal
3072 
3073  Returns the synchronized common margin for \a side. This is the margin value that will be used by
3074  the layout element on the respective side, if it is part of this margin group.
3075 
3076  The common margin is calculated by requesting the automatic margin (\ref
3077  QCPLayoutElement::calculateAutoMargin) of each element associated with \a side in this margin
3078  group, and choosing the largest returned value. (QCPLayoutElement::minimumMargins is taken into
3079  account, too.)
3080 */
3082 {
3083  // query all automatic margins of the layout elements in this margin group side and find maximum:
3084  int result = 0;
3085  foreach (QCPLayoutElement *el, mChildren.value(side))
3086  {
3087  if (!el->autoMargins().testFlag(side))
3088  continue;
3089  int m = qMax(el->calculateAutoMargin(side), QCP::getMarginValue(el->minimumMargins(), side));
3090  if (m > result)
3091  result = m;
3092  }
3093  return result;
3094 }
3095 
3096 /*! \internal
3097 
3098  Adds \a element to the internal list of child elements, for the margin \a side.
3099 
3100  This function does not modify the margin group property of \a element.
3101 */
3103 {
3104  if (!mChildren[side].contains(element))
3105  mChildren[side].append(element);
3106  else
3107  qDebug() << Q_FUNC_INFO << "element is already child of this margin group side" << reinterpret_cast<quintptr>(element);
3108 }
3109 
3110 /*! \internal
3111 
3112  Removes \a element from the internal list of child elements, for the margin \a side.
3113 
3114  This function does not modify the margin group property of \a element.
3115 */
3117 {
3118  if (!mChildren[side].removeOne(element))
3119  qDebug() << Q_FUNC_INFO << "element is not child of this margin group side" << reinterpret_cast<quintptr>(element);
3120 }
3121 
3122 
3123 ////////////////////////////////////////////////////////////////////////////////////////////////////
3124 //////////////////// QCPLayoutElement
3125 ////////////////////////////////////////////////////////////////////////////////////////////////////
3126 
3127 /*! \class QCPLayoutElement
3128  \brief The abstract base class for all objects that form \ref thelayoutsystem "the layout system".
3129 
3130  This is an abstract base class. As such, it can't be instantiated directly, rather use one of its subclasses.
3131 
3132  A Layout element is a rectangular object which can be placed in layouts. It has an outer rect
3133  (QCPLayoutElement::outerRect) and an inner rect (\ref QCPLayoutElement::rect). The difference
3134  between outer and inner rect is called its margin. The margin can either be set to automatic or
3135  manual (\ref setAutoMargins) on a per-side basis. If a side is set to manual, that margin can be
3136  set explicitly with \ref setMargins and will stay fixed at that value. If it's set to automatic,
3137  the layout element subclass will control the value itself (via \ref calculateAutoMargin).
3138 
3139  Layout elements can be placed in layouts (base class QCPLayout) like QCPLayoutGrid. The top level
3140  layout is reachable via \ref QCustomPlot::plotLayout, and is a \ref QCPLayoutGrid. Since \ref
3141  QCPLayout itself derives from \ref QCPLayoutElement, layouts can be nested.
3142 
3143  Thus in QCustomPlot one can divide layout elements into two categories: The ones that are
3144  invisible by themselves, because they don't draw anything. Their only purpose is to manage the
3145  position and size of other layout elements. This category of layout elements usually use
3146  QCPLayout as base class. Then there is the category of layout elements which actually draw
3147  something. For example, QCPAxisRect, QCPLegend and QCPTextElement are of this category. This does
3148  not necessarily mean that the latter category can't have child layout elements. QCPLegend for
3149  instance, actually derives from QCPLayoutGrid and the individual legend items are child layout
3150  elements in the grid layout.
3151 */
3152 
3153 /* start documentation of inline functions */
3154 
3155 /*! \fn QCPLayout *QCPLayoutElement::layout() const
3156 
3157  Returns the parent layout of this layout element.
3158 */
3159 
3160 /*! \fn QRect QCPLayoutElement::rect() const
3161 
3162  Returns the inner rect of this layout element. The inner rect is the outer rect (\ref outerRect, \ref
3163  setOuterRect) shrinked by the margins (\ref setMargins, \ref setAutoMargins).
3164 
3165  In some cases, the area between outer and inner rect is left blank. In other cases the margin
3166  area is used to display peripheral graphics while the main content is in the inner rect. This is
3167  where automatic margin calculation becomes interesting because it allows the layout element to
3168  adapt the margins to the peripheral graphics it wants to draw. For example, \ref QCPAxisRect
3169  draws the axis labels and tick labels in the margin area, thus needs to adjust the margins (if
3170  \ref setAutoMargins is enabled) according to the space required by the labels of the axes.
3171 
3172  \see outerRect
3173 */
3174 
3175 /*! \fn QRect QCPLayoutElement::outerRect() const
3176 
3177  Returns the outer rect of this layout element. The outer rect is the inner rect expanded by the
3178  margins (\ref setMargins, \ref setAutoMargins). The outer rect is used (and set via \ref
3179  setOuterRect) by the parent \ref QCPLayout to control the size of this layout element.
3180 
3181  \see rect
3182 */
3183 
3184 /* end documentation of inline functions */
3185 
3186 /*!
3187  Creates an instance of QCPLayoutElement and sets default values.
3188 */
3190  QCPLayerable(parentPlot), // parenthood is changed as soon as layout element gets inserted into a layout (except for top level layout)
3191  mParentLayout(nullptr),
3192  mMinimumSize(),
3193  mMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX),
3194  mSizeConstraintRect(scrInnerRect),
3195  mRect(0, 0, 0, 0),
3196  mOuterRect(0, 0, 0, 0),
3197  mMargins(0, 0, 0, 0),
3198  mMinimumMargins(0, 0, 0, 0),
3199  mAutoMargins(QCP::msAll)
3200 {
3201 }
3202 
3203 QCPLayoutElement::~QCPLayoutElement()
3204 {
3205  setMarginGroup(QCP::msAll, nullptr); // unregister at margin groups, if there are any
3206  // unregister at layout:
3207  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
3208  mParentLayout->take(this);
3209 }
3210 
3211 /*!
3212  Sets the outer rect of this layout element. If the layout element is inside a layout, the layout
3213  sets the position and size of this layout element using this function.
3214 
3215  Calling this function externally has no effect, since the layout will overwrite any changes to
3216  the outer rect upon the next replot.
3217 
3218  The layout element will adapt its inner \ref rect by applying the margins inward to the outer rect.
3219 
3220  \see rect
3221 */
3223 {
3224  if (mOuterRect != rect)
3225  {
3226  mOuterRect = rect;
3227  mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom());
3228  }
3229 }
3230 
3231 /*!
3232  Sets the margins of this layout element. If \ref setAutoMargins is disabled for some or all
3233  sides, this function is used to manually set the margin on those sides. Sides that are still set
3234  to be handled automatically are ignored and may have any value in \a margins.
3235 
3236  The margin is the distance between the outer rect (controlled by the parent layout via \ref
3237  setOuterRect) and the inner \ref rect (which usually contains the main content of this layout
3238  element).
3239 
3240  \see setAutoMargins
3241 */
3243 {
3244  if (mMargins != margins)
3245  {
3246  mMargins = margins;
3247  mRect = mOuterRect.adjusted(mMargins.left(), mMargins.top(), -mMargins.right(), -mMargins.bottom());
3248  }
3249 }
3250 
3251 /*!
3252  If \ref setAutoMargins is enabled on some or all margins, this function is used to provide
3253  minimum values for those margins.
3254 
3255  The minimum values are not enforced on margin sides that were set to be under manual control via
3256  \ref setAutoMargins.
3257 
3258  \see setAutoMargins
3259 */
3261 {
3262  if (mMinimumMargins != margins)
3263  {
3264  mMinimumMargins = margins;
3265  }
3266 }
3267 
3268 /*!
3269  Sets on which sides the margin shall be calculated automatically. If a side is calculated
3270  automatically, a minimum margin value may be provided with \ref setMinimumMargins. If a side is
3271  set to be controlled manually, the value may be specified with \ref setMargins.
3272 
3273  Margin sides that are under automatic control may participate in a \ref QCPMarginGroup (see \ref
3274  setMarginGroup), to synchronize (align) it with other layout elements in the plot.
3275 
3276  \see setMinimumMargins, setMargins, QCP::MarginSide
3277 */
3279 {
3280  mAutoMargins = sides;
3281 }
3282 
3283 /*!
3284  Sets the minimum size of this layout element. A parent layout tries to respect the \a size here
3285  by changing row/column sizes in the layout accordingly.
3286 
3287  If the parent layout size is not sufficient to satisfy all minimum size constraints of its child
3288  layout elements, the layout may set a size that is actually smaller than \a size. QCustomPlot
3289  propagates the layout's size constraints to the outside by setting its own minimum QWidget size
3290  accordingly, so violations of \a size should be exceptions.
3291 
3292  Whether this constraint applies to the inner or the outer rect can be specified with \ref
3293  setSizeConstraintRect (see \ref rect and \ref outerRect).
3294 */
3296 {
3297  if (mMinimumSize != size)
3298  {
3299  mMinimumSize = size;
3300  if (mParentLayout)
3301  mParentLayout->sizeConstraintsChanged();
3302  }
3303 }
3304 
3305 /*! \overload
3306 
3307  Sets the minimum size of this layout element.
3308 
3309  Whether this constraint applies to the inner or the outer rect can be specified with \ref
3310  setSizeConstraintRect (see \ref rect and \ref outerRect).
3311 */
3312 void QCPLayoutElement::setMinimumSize(int width, int height)
3313 {
3314  setMinimumSize(QSize(width, height));
3315 }
3316 
3317 /*!
3318  Sets the maximum size of this layout element. A parent layout tries to respect the \a size here
3319  by changing row/column sizes in the layout accordingly.
3320 
3321  Whether this constraint applies to the inner or the outer rect can be specified with \ref
3322  setSizeConstraintRect (see \ref rect and \ref outerRect).
3323 */
3325 {
3326  if (mMaximumSize != size)
3327  {
3328  mMaximumSize = size;
3329  if (mParentLayout)
3330  mParentLayout->sizeConstraintsChanged();
3331  }
3332 }
3333 
3334 /*! \overload
3335 
3336  Sets the maximum size of this layout element.
3337 
3338  Whether this constraint applies to the inner or the outer rect can be specified with \ref
3339  setSizeConstraintRect (see \ref rect and \ref outerRect).
3340 */
3341 void QCPLayoutElement::setMaximumSize(int width, int height)
3342 {
3343  setMaximumSize(QSize(width, height));
3344 }
3345 
3346 /*!
3347  Sets to which rect of a layout element the size constraints apply. Size constraints can be set
3348  via \ref setMinimumSize and \ref setMaximumSize.
3349 
3350  The outer rect (\ref outerRect) includes the margins (e.g. in the case of a QCPAxisRect the axis
3351  labels), whereas the inner rect (\ref rect) does not.
3352 
3353  \see setMinimumSize, setMaximumSize
3354 */
3356 {
3357  if (mSizeConstraintRect != constraintRect)
3358  {
3359  mSizeConstraintRect = constraintRect;
3360  if (mParentLayout)
3361  mParentLayout->sizeConstraintsChanged();
3362  }
3363 }
3364 
3365 /*!
3366  Sets the margin \a group of the specified margin \a sides.
3367 
3368  Margin groups allow synchronizing specified margins across layout elements, see the documentation
3369  of \ref QCPMarginGroup.
3370 
3371  To unset the margin group of \a sides, set \a group to \c nullptr.
3372 
3373  Note that margin groups only work for margin sides that are set to automatic (\ref
3374  setAutoMargins).
3375 
3376  \see QCP::MarginSide
3377 */
3379 {
3380  QVector<QCP::MarginSide> sideVector;
3381  if (sides.testFlag(QCP::msLeft)) sideVector.append(QCP::msLeft);
3382  if (sides.testFlag(QCP::msRight)) sideVector.append(QCP::msRight);
3383  if (sides.testFlag(QCP::msTop)) sideVector.append(QCP::msTop);
3384  if (sides.testFlag(QCP::msBottom)) sideVector.append(QCP::msBottom);
3385 
3386  foreach (QCP::MarginSide side, sideVector)
3387  {
3388  if (marginGroup(side) != group)
3389  {
3390  QCPMarginGroup *oldGroup = marginGroup(side);
3391  if (oldGroup) // unregister at old group
3392  oldGroup->removeChild(side, this);
3393 
3394  if (!group) // if setting to 0, remove hash entry. Else set hash entry to new group and register there
3395  {
3396  mMarginGroups.remove(side);
3397  } else // setting to a new group
3398  {
3399  mMarginGroups[side] = group;
3400  group->addChild(side, this);
3401  }
3402  }
3403  }
3404 }
3405 
3406 /*!
3407  Updates the layout element and sub-elements. This function is automatically called before every
3408  replot by the parent layout element. It is called multiple times, once for every \ref
3409  UpdatePhase. The phases are run through in the order of the enum values. For details about what
3410  happens at the different phases, see the documentation of \ref UpdatePhase.
3411 
3412  Layout elements that have child elements should call the \ref update method of their child
3413  elements, and pass the current \a phase unchanged.
3414 
3415  The default implementation executes the automatic margin mechanism in the \ref upMargins phase.
3416  Subclasses should make sure to call the base class implementation.
3417 */
3419 {
3420  if (phase == upMargins)
3421  {
3422  if (mAutoMargins != QCP::msNone)
3423  {
3424  // set the margins of this layout element according to automatic margin calculation, either directly or via a margin group:
3425  QMargins newMargins = mMargins;
3427  foreach (QCP::MarginSide side, allMarginSides)
3428  {
3429  if (mAutoMargins.testFlag(side)) // this side's margin shall be calculated automatically
3430  {
3431  if (mMarginGroups.contains(side))
3432  QCP::setMarginValue(newMargins, side, mMarginGroups[side]->commonMargin(side)); // this side is part of a margin group, so get the margin value from that group
3433  else
3434  QCP::setMarginValue(newMargins, side, calculateAutoMargin(side)); // this side is not part of a group, so calculate the value directly
3435  // apply minimum margin restrictions:
3436  if (QCP::getMarginValue(newMargins, side) < QCP::getMarginValue(mMinimumMargins, side))
3437  QCP::setMarginValue(newMargins, side, QCP::getMarginValue(mMinimumMargins, side));
3438  }
3439  }
3440  setMargins(newMargins);
3441  }
3442  }
3443 }
3444 
3445 /*!
3446  Returns the suggested minimum size this layout element (the \ref outerRect) may be compressed to,
3447  if no manual minimum size is set.
3448 
3449  if a minimum size (\ref setMinimumSize) was not set manually, parent layouts use the returned size
3450  (usually indirectly through \ref QCPLayout::getFinalMinimumOuterSize) to determine the minimum
3451  allowed size of this layout element.
3452 
3453  A manual minimum size is considered set if it is non-zero.
3454 
3455  The default implementation simply returns the sum of the horizontal margins for the width and the
3456  sum of the vertical margins for the height. Reimplementations may use their detailed knowledge
3457  about the layout element's content to provide size hints.
3458 */
3460 {
3461  return {mMargins.left()+mMargins.right(), mMargins.top()+mMargins.bottom()};
3462 }
3463 
3464 /*!
3465  Returns the suggested maximum size this layout element (the \ref outerRect) may be expanded to,
3466  if no manual maximum size is set.
3467 
3468  if a maximum size (\ref setMaximumSize) was not set manually, parent layouts use the returned
3469  size (usually indirectly through \ref QCPLayout::getFinalMaximumOuterSize) to determine the
3470  maximum allowed size of this layout element.
3471 
3472  A manual maximum size is considered set if it is smaller than Qt's \c QWIDGETSIZE_MAX.
3473 
3474  The default implementation simply returns \c QWIDGETSIZE_MAX for both width and height, implying
3475  no suggested maximum size. Reimplementations may use their detailed knowledge about the layout
3476  element's content to provide size hints.
3477 */
3479 {
3480  return {QWIDGETSIZE_MAX, QWIDGETSIZE_MAX};
3481 }
3482 
3483 /*!
3484  Returns a list of all child elements in this layout element. If \a recursive is true, all
3485  sub-child elements are included in the list, too.
3486 
3487  \warning There may be \c nullptr entries in the returned list. For example, QCPLayoutGrid may
3488  have empty cells which yield \c nullptr at the respective index.
3489 */
3491 {
3492  Q_UNUSED(recursive)
3493  return QList<QCPLayoutElement*>();
3494 }
3495 
3496 /*!
3497  Layout elements are sensitive to events inside their outer rect. If \a pos is within the outer
3498  rect, this method returns a value corresponding to 0.99 times the parent plot's selection
3499  tolerance. However, layout elements are not selectable by default. So if \a onlySelectable is
3500  true, -1.0 is returned.
3501 
3502  See \ref QCPLayerable::selectTest for a general explanation of this virtual method.
3503 
3504  QCPLayoutElement subclasses may reimplement this method to provide more specific selection test
3505  behaviour.
3506 */
3507 double QCPLayoutElement::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
3508 {
3509  Q_UNUSED(details)
3510 
3511  if (onlySelectable)
3512  return -1;
3513 
3514  if (QRectF(mOuterRect).contains(pos))
3515  {
3516  if (mParentPlot)
3517  return mParentPlot->selectionTolerance()*0.99;
3518  else
3519  {
3520  qDebug() << Q_FUNC_INFO << "parent plot not defined";
3521  return -1;
3522  }
3523  } else
3524  return -1;
3525 }
3526 
3527 /*! \internal
3528 
3529  propagates the parent plot initialization to all child elements, by calling \ref
3530  QCPLayerable::initializeParentPlot on them.
3531 */
3533 {
3534  foreach (QCPLayoutElement *el, elements(false))
3535  {
3536  if (!el->parentPlot())
3537  el->initializeParentPlot(parentPlot);
3538  }
3539 }
3540 
3541 /*! \internal
3542 
3543  Returns the margin size for this \a side. It is used if automatic margins is enabled for this \a
3544  side (see \ref setAutoMargins). If a minimum margin was set with \ref setMinimumMargins, the
3545  returned value will not be smaller than the specified minimum margin.
3546 
3547  The default implementation just returns the respective manual margin (\ref setMargins) or the
3548  minimum margin, whichever is larger.
3549 */
3551 {
3552  return qMax(QCP::getMarginValue(mMargins, side), QCP::getMarginValue(mMinimumMargins, side));
3553 }
3554 
3555 /*! \internal
3556 
3557  This virtual method is called when this layout element was moved to a different QCPLayout, or
3558  when this layout element has changed its logical position (e.g. row and/or column) within the
3559  same QCPLayout. Subclasses may use this to react accordingly.
3560 
3561  Since this method is called after the completion of the move, you can access the new parent
3562  layout via \ref layout().
3563 
3564  The default implementation does nothing.
3565 */
3567 {
3568 }
3569 
3570 ////////////////////////////////////////////////////////////////////////////////////////////////////
3571 //////////////////// QCPLayout
3572 ////////////////////////////////////////////////////////////////////////////////////////////////////
3573 
3574 /*! \class QCPLayout
3575  \brief The abstract base class for layouts
3576 
3577  This is an abstract base class for layout elements whose main purpose is to define the position
3578  and size of other child layout elements. In most cases, layouts don't draw anything themselves
3579  (but there are exceptions to this, e.g. QCPLegend).
3580 
3581  QCPLayout derives from QCPLayoutElement, and thus can itself be nested in other layouts.
3582 
3583  QCPLayout introduces a common interface for accessing and manipulating the child elements. Those
3584  functions are most notably \ref elementCount, \ref elementAt, \ref takeAt, \ref take, \ref
3585  simplify, \ref removeAt, \ref remove and \ref clear. Individual subclasses may add more functions
3586  to this interface which are more specialized to the form of the layout. For example, \ref
3587  QCPLayoutGrid adds functions that take row and column indices to access cells of the layout grid
3588  more conveniently.
3589 
3590  Since this is an abstract base class, you can't instantiate it directly. Rather use one of its
3591  subclasses like QCPLayoutGrid or QCPLayoutInset.
3592 
3593  For a general introduction to the layout system, see the dedicated documentation page \ref
3594  thelayoutsystem "The Layout System".
3595 */
3596 
3597 /* start documentation of pure virtual functions */
3598 
3599 /*! \fn virtual int QCPLayout::elementCount() const = 0
3600 
3601  Returns the number of elements/cells in the layout.
3602 
3603  \see elements, elementAt
3604 */
3605 
3606 /*! \fn virtual QCPLayoutElement* QCPLayout::elementAt(int index) const = 0
3607 
3608  Returns the element in the cell with the given \a index. If \a index is invalid, returns \c
3609  nullptr.
3610 
3611  Note that even if \a index is valid, the respective cell may be empty in some layouts (e.g.
3612  QCPLayoutGrid), so this function may return \c nullptr in those cases. You may use this function
3613  to check whether a cell is empty or not.
3614 
3615  \see elements, elementCount, takeAt
3616 */
3617 
3618 /*! \fn virtual QCPLayoutElement* QCPLayout::takeAt(int index) = 0
3619 
3620  Removes the element with the given \a index from the layout and returns it.
3621 
3622  If the \a index is invalid or the cell with that index is empty, returns \c nullptr.
3623 
3624  Note that some layouts don't remove the respective cell right away but leave an empty cell after
3625  successful removal of the layout element. To collapse empty cells, use \ref simplify.
3626 
3627  \see elementAt, take
3628 */
3629 
3630 /*! \fn virtual bool QCPLayout::take(QCPLayoutElement* element) = 0
3631 
3632  Removes the specified \a element from the layout and returns true on success.
3633 
3634  If the \a element isn't in this layout, returns false.
3635 
3636  Note that some layouts don't remove the respective cell right away but leave an empty cell after
3637  successful removal of the layout element. To collapse empty cells, use \ref simplify.
3638 
3639  \see takeAt
3640 */
3641 
3642 /* end documentation of pure virtual functions */
3643 
3644 /*!
3645  Creates an instance of QCPLayout and sets default values. Note that since QCPLayout
3646  is an abstract base class, it can't be instantiated directly.
3647 */
3649 {
3650 }
3651 
3652 /*!
3653  If \a phase is \ref upLayout, calls \ref updateLayout, which subclasses may reimplement to
3654  reposition and resize their cells.
3655 
3656  Finally, the call is propagated down to all child \ref QCPLayoutElement "QCPLayoutElements".
3657 
3658  For details about this method and the update phases, see the documentation of \ref
3659  QCPLayoutElement::update.
3660 */
3662 {
3663  QCPLayoutElement::update(phase);
3664 
3665  // set child element rects according to layout:
3666  if (phase == upLayout)
3667  updateLayout();
3668 
3669  // propagate update call to child elements:
3670  const int elCount = elementCount();
3671  for (int i=0; i<elCount; ++i)
3672  {
3673  if (QCPLayoutElement *el = elementAt(i))
3674  el->update(phase);
3675  }
3676 }
3677 
3678 /* inherits documentation from base class */
3680 {
3681  const int c = elementCount();
3682  QList<QCPLayoutElement*> result;
3683 #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
3684  result.reserve(c);
3685 #endif
3686  for (int i=0; i<c; ++i)
3687  result.append(elementAt(i));
3688  if (recursive)
3689  {
3690  for (int i=0; i<c; ++i)
3691  {
3692  if (result.at(i))
3693  result << result.at(i)->elements(recursive);
3694  }
3695  }
3696  return result;
3697 }
3698 
3699 /*!
3700  Simplifies the layout by collapsing empty cells. The exact behavior depends on subclasses, the
3701  default implementation does nothing.
3702 
3703  Not all layouts need simplification. For example, QCPLayoutInset doesn't use explicit
3704  simplification while QCPLayoutGrid does.
3705 */
3707 {
3708 }
3709 
3710 /*!
3711  Removes and deletes the element at the provided \a index. Returns true on success. If \a index is
3712  invalid or points to an empty cell, returns false.
3713 
3714  This function internally uses \ref takeAt to remove the element from the layout and then deletes
3715  the returned element. Note that some layouts don't remove the respective cell right away but leave an
3716  empty cell after successful removal of the layout element. To collapse empty cells, use \ref
3717  simplify.
3718 
3719  \see remove, takeAt
3720 */
3721 bool QCPLayout::removeAt(int index)
3722 {
3723  if (QCPLayoutElement *el = takeAt(index))
3724  {
3725  delete el;
3726  return true;
3727  } else
3728  return false;
3729 }
3730 
3731 /*!
3732  Removes and deletes the provided \a element. Returns true on success. If \a element is not in the
3733  layout, returns false.
3734 
3735  This function internally uses \ref takeAt to remove the element from the layout and then deletes
3736  the element. Note that some layouts don't remove the respective cell right away but leave an
3737  empty cell after successful removal of the layout element. To collapse empty cells, use \ref
3738  simplify.
3739 
3740  \see removeAt, take
3741 */
3743 {
3744  if (take(element))
3745  {
3746  delete element;
3747  return true;
3748  } else
3749  return false;
3750 }
3751 
3752 /*!
3753  Removes and deletes all layout elements in this layout. Finally calls \ref simplify to make sure
3754  all empty cells are collapsed.
3755 
3756  \see remove, removeAt
3757 */
3759 {
3760  for (int i=elementCount()-1; i>=0; --i)
3761  {
3762  if (elementAt(i))
3763  removeAt(i);
3764  }
3765  simplify();
3766 }
3767 
3768 /*!
3769  Subclasses call this method to report changed (minimum/maximum) size constraints.
3770 
3771  If the parent of this layout is again a QCPLayout, forwards the call to the parent's \ref
3772  sizeConstraintsChanged. If the parent is a QWidget (i.e. is the \ref QCustomPlot::plotLayout of
3773  QCustomPlot), calls QWidget::updateGeometry, so if the QCustomPlot widget is inside a Qt QLayout,
3774  it may update itself and resize cells accordingly.
3775 */
3777 {
3778  if (QWidget *w = qobject_cast<QWidget*>(parent()))
3779  w->updateGeometry();
3780  else if (QCPLayout *l = qobject_cast<QCPLayout*>(parent()))
3781  l->sizeConstraintsChanged();
3782 }
3783 
3784 /*! \internal
3785 
3786  Subclasses reimplement this method to update the position and sizes of the child elements/cells
3787  via calling their \ref QCPLayoutElement::setOuterRect. The default implementation does nothing.
3788 
3789  The geometry used as a reference is the inner \ref rect of this layout. Child elements should stay
3790  within that rect.
3791 
3792  \ref getSectionSizes may help with the reimplementation of this function.
3793 
3794  \see update
3795 */
3797 {
3798 }
3799 
3800 
3801 /*! \internal
3802 
3803  Associates \a el with this layout. This is done by setting the \ref QCPLayoutElement::layout, the
3804  \ref QCPLayerable::parentLayerable and the QObject parent to this layout.
3805 
3806  Further, if \a el didn't previously have a parent plot, calls \ref
3807  QCPLayerable::initializeParentPlot on \a el to set the paret plot.
3808 
3809  This method is used by subclass specific methods that add elements to the layout. Note that this
3810  method only changes properties in \a el. The removal from the old layout and the insertion into
3811  the new layout must be done additionally.
3812 */
3814 {
3815  if (el)
3816  {
3817  el->mParentLayout = this;
3818  el->setParentLayerable(this);
3819  el->setParent(this);
3820  if (!el->parentPlot())
3821  el->initializeParentPlot(mParentPlot);
3822  el->layoutChanged();
3823  } else
3824  qDebug() << Q_FUNC_INFO << "Null element passed";
3825 }
3826 
3827 /*! \internal
3828 
3829  Disassociates \a el from this layout. This is done by setting the \ref QCPLayoutElement::layout
3830  and the \ref QCPLayerable::parentLayerable to zero. The QObject parent is set to the parent
3831  QCustomPlot.
3832 
3833  This method is used by subclass specific methods that remove elements from the layout (e.g. \ref
3834  take or \ref takeAt). Note that this method only changes properties in \a el. The removal from
3835  the old layout must be done additionally.
3836 */
3838 {
3839  if (el)
3840  {
3841  el->mParentLayout = nullptr;
3842  el->setParentLayerable(nullptr);
3843  el->setParent(mParentPlot);
3844  // Note: Don't initializeParentPlot(0) here, because layout element will stay in same parent plot
3845  } else
3846  qDebug() << Q_FUNC_INFO << "Null element passed";
3847 }
3848 
3849 /*! \internal
3850 
3851  This is a helper function for the implementation of \ref updateLayout in subclasses.
3852 
3853  It calculates the sizes of one-dimensional sections with provided constraints on maximum section
3854  sizes, minimum section sizes, relative stretch factors and the final total size of all sections.
3855 
3856  The QVector entries refer to the sections. Thus all QVectors must have the same size.
3857 
3858  \a maxSizes gives the maximum allowed size of each section. If there shall be no maximum size
3859  imposed, set all vector values to Qt's QWIDGETSIZE_MAX.
3860 
3861  \a minSizes gives the minimum allowed size of each section. If there shall be no minimum size
3862  imposed, set all vector values to zero. If the \a minSizes entries add up to a value greater than
3863  \a totalSize, sections will be scaled smaller than the proposed minimum sizes. (In other words,
3864  not exceeding the allowed total size is taken to be more important than not going below minimum
3865  section sizes.)
3866 
3867  \a stretchFactors give the relative proportions of the sections to each other. If all sections
3868  shall be scaled equally, set all values equal. If the first section shall be double the size of
3869  each individual other section, set the first number of \a stretchFactors to double the value of
3870  the other individual values (e.g. {2, 1, 1, 1}).
3871 
3872  \a totalSize is the value that the final section sizes will add up to. Due to rounding, the
3873  actual sum may differ slightly. If you want the section sizes to sum up to exactly that value,
3874  you could distribute the remaining difference on the sections.
3875 
3876  The return value is a QVector containing the section sizes.
3877 */
3878 QVector<int> QCPLayout::getSectionSizes(QVector<int> maxSizes, QVector<int> minSizes, QVector<double> stretchFactors, int totalSize) const
3879 {
3880  if (maxSizes.size() != minSizes.size() || minSizes.size() != stretchFactors.size())
3881  {
3882  qDebug() << Q_FUNC_INFO << "Passed vector sizes aren't equal:" << maxSizes << minSizes << stretchFactors;
3883  return QVector<int>();
3884  }
3885  if (stretchFactors.isEmpty())
3886  return QVector<int>();
3887  int sectionCount = stretchFactors.size();
3888  QVector<double> sectionSizes(sectionCount);
3889  // if provided total size is forced smaller than total minimum size, ignore minimum sizes (squeeze sections):
3890  int minSizeSum = 0;
3891  for (int i=0; i<sectionCount; ++i)
3892  minSizeSum += minSizes.at(i);
3893  if (totalSize < minSizeSum)
3894  {
3895  // new stretch factors are minimum sizes and minimum sizes are set to zero:
3896  for (int i=0; i<sectionCount; ++i)
3897  {
3898  stretchFactors[i] = minSizes.at(i);
3899  minSizes[i] = 0;
3900  }
3901  }
3902 
3903  QList<int> minimumLockedSections;
3904  QList<int> unfinishedSections;
3905  for (int i=0; i<sectionCount; ++i)
3906  unfinishedSections.append(i);
3907  double freeSize = totalSize;
3908 
3909  int outerIterations = 0;
3910  while (!unfinishedSections.isEmpty() && outerIterations < sectionCount*2) // the iteration check ist just a failsafe in case something really strange happens
3911  {
3912  ++outerIterations;
3913  int innerIterations = 0;
3914  while (!unfinishedSections.isEmpty() && innerIterations < sectionCount*2) // the iteration check ist just a failsafe in case something really strange happens
3915  {
3916  ++innerIterations;
3917  // find section that hits its maximum next:
3918  int nextId = -1;
3919  double nextMax = 1e12;
3920  foreach (int secId, unfinishedSections)
3921  {
3922  double hitsMaxAt = (maxSizes.at(secId)-sectionSizes.at(secId))/stretchFactors.at(secId);
3923  if (hitsMaxAt < nextMax)
3924  {
3925  nextMax = hitsMaxAt;
3926  nextId = secId;
3927  }
3928  }
3929  // 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
3930  // actually hits its maximum, without exceeding the total size when we add up all sections)
3931  double stretchFactorSum = 0;
3932  foreach (int secId, unfinishedSections)
3933  stretchFactorSum += stretchFactors.at(secId);
3934  double nextMaxLimit = freeSize/stretchFactorSum;
3935  if (nextMax < nextMaxLimit) // next maximum is actually hit, move forward to that point and fix the size of that section
3936  {
3937  foreach (int secId, unfinishedSections)
3938  {
3939  sectionSizes[secId] += nextMax*stretchFactors.at(secId); // increment all sections
3940  freeSize -= nextMax*stretchFactors.at(secId);
3941  }
3942  unfinishedSections.removeOne(nextId); // exclude the section that is now at maximum from further changes
3943  } else // next maximum isn't hit, just distribute rest of free space on remaining sections
3944  {
3945  foreach (int secId, unfinishedSections)
3946  sectionSizes[secId] += nextMaxLimit*stretchFactors.at(secId); // increment all sections
3947  unfinishedSections.clear();
3948  }
3949  }
3950  if (innerIterations == sectionCount*2)
3951  qDebug() << Q_FUNC_INFO << "Exceeded maximum expected inner iteration count, layouting aborted. Input was:" << maxSizes << minSizes << stretchFactors << totalSize;
3952 
3953  // now check whether the resulting section sizes violate minimum restrictions:
3954  bool foundMinimumViolation = false;
3955  for (int i=0; i<sectionSizes.size(); ++i)
3956  {
3957  if (minimumLockedSections.contains(i))
3958  continue;
3959  if (sectionSizes.at(i) < minSizes.at(i)) // section violates minimum
3960  {
3961  sectionSizes[i] = minSizes.at(i); // set it to minimum
3962  foundMinimumViolation = true; // make sure we repeat the whole optimization process
3963  minimumLockedSections.append(i);
3964  }
3965  }
3966  if (foundMinimumViolation)
3967  {
3968  freeSize = totalSize;
3969  for (int i=0; i<sectionCount; ++i)
3970  {
3971  if (!minimumLockedSections.contains(i)) // only put sections that haven't hit their minimum back into the pool
3972  unfinishedSections.append(i);
3973  else
3974  freeSize -= sectionSizes.at(i); // remove size of minimum locked sections from available space in next round
3975  }
3976  // reset all section sizes to zero that are in unfinished sections (all others have been set to their minimum):
3977  foreach (int secId, unfinishedSections)
3978  sectionSizes[secId] = 0;
3979  }
3980  }
3981  if (outerIterations == sectionCount*2)
3982  qDebug() << Q_FUNC_INFO << "Exceeded maximum expected outer iteration count, layouting aborted. Input was:" << maxSizes << minSizes << stretchFactors << totalSize;
3983 
3984  QVector<int> result(sectionCount);
3985  for (int i=0; i<sectionCount; ++i)
3986  result[i] = qRound(sectionSizes.at(i));
3987  return result;
3988 }
3989 
3990 /*! \internal
3991 
3992  This is a helper function for the implementation of subclasses.
3993 
3994  It returns the minimum size that should finally be used for the outer rect of the passed layout
3995  element \a el.
3996 
3997  It takes into account whether a manual minimum size is set (\ref
3998  QCPLayoutElement::setMinimumSize), which size constraint is set (\ref
3999  QCPLayoutElement::setSizeConstraintRect), as well as the minimum size hint, if no manual minimum
4000  size was set (\ref QCPLayoutElement::minimumOuterSizeHint).
4001 */
4003 {
4004  QSize minOuterHint = el->minimumOuterSizeHint();
4005  QSize minOuter = el->minimumSize(); // depending on sizeConstraitRect this might be with respect to inner rect, so possibly add margins in next four lines (preserving unset minimum of 0)
4006  if (minOuter.width() > 0 && el->sizeConstraintRect() == QCPLayoutElement::scrInnerRect)
4007  minOuter.rwidth() += el->margins().left() + el->margins().right();
4008  if (minOuter.height() > 0 && el->sizeConstraintRect() == QCPLayoutElement::scrInnerRect)
4009  minOuter.rheight() += el->margins().top() + el->margins().bottom();
4010 
4011  return {minOuter.width() > 0 ? minOuter.width() : minOuterHint.width(),
4012  minOuter.height() > 0 ? minOuter.height() : minOuterHint.height()};
4013 }
4014 
4015 /*! \internal
4016 
4017  This is a helper function for the implementation of subclasses.
4018 
4019  It returns the maximum size that should finally be used for the outer rect of the passed layout
4020  element \a el.
4021 
4022  It takes into account whether a manual maximum size is set (\ref
4023  QCPLayoutElement::setMaximumSize), which size constraint is set (\ref
4024  QCPLayoutElement::setSizeConstraintRect), as well as the maximum size hint, if no manual maximum
4025  size was set (\ref QCPLayoutElement::maximumOuterSizeHint).
4026 */
4028 {
4029  QSize maxOuterHint = el->maximumOuterSizeHint();
4030  QSize maxOuter = el->maximumSize(); // depending on sizeConstraitRect this might be with respect to inner rect, so possibly add margins in next four lines (preserving unset maximum of QWIDGETSIZE_MAX)
4031  if (maxOuter.width() < QWIDGETSIZE_MAX && el->sizeConstraintRect() == QCPLayoutElement::scrInnerRect)
4032  maxOuter.rwidth() += el->margins().left() + el->margins().right();
4033  if (maxOuter.height() < QWIDGETSIZE_MAX && el->sizeConstraintRect() == QCPLayoutElement::scrInnerRect)
4034  maxOuter.rheight() += el->margins().top() + el->margins().bottom();
4035 
4036  return {maxOuter.width() < QWIDGETSIZE_MAX ? maxOuter.width() : maxOuterHint.width(),
4037  maxOuter.height() < QWIDGETSIZE_MAX ? maxOuter.height() : maxOuterHint.height()};
4038 }
4039 
4040 
4041 ////////////////////////////////////////////////////////////////////////////////////////////////////
4042 //////////////////// QCPLayoutGrid
4043 ////////////////////////////////////////////////////////////////////////////////////////////////////
4044 
4045 /*! \class QCPLayoutGrid
4046  \brief A layout that arranges child elements in a grid
4047 
4048  Elements are laid out in a grid with configurable stretch factors (\ref setColumnStretchFactor,
4049  \ref setRowStretchFactor) and spacing (\ref setColumnSpacing, \ref setRowSpacing).
4050 
4051  Elements can be added to cells via \ref addElement. The grid is expanded if the specified row or
4052  column doesn't exist yet. Whether a cell contains a valid layout element can be checked with \ref
4053  hasElement, that element can be retrieved with \ref element. If rows and columns that only have
4054  empty cells shall be removed, call \ref simplify. Removal of elements is either done by just
4055  adding the element to a different layout or by using the QCPLayout interface \ref take or \ref
4056  remove.
4057 
4058  If you use \ref addElement(QCPLayoutElement*) without explicit parameters for \a row and \a
4059  column, the grid layout will choose the position according to the current \ref setFillOrder and
4060  the wrapping (\ref setWrap).
4061 
4062  Row and column insertion can be performed with \ref insertRow and \ref insertColumn.
4063 */
4064 
4065 /* start documentation of inline functions */
4066 
4067 /*! \fn int QCPLayoutGrid::rowCount() const
4068 
4069  Returns the number of rows in the layout.
4070 
4071  \see columnCount
4072 */
4073 
4074 /*! \fn int QCPLayoutGrid::columnCount() const
4075 
4076  Returns the number of columns in the layout.
4077 
4078  \see rowCount
4079 */
4080 
4081 /* end documentation of inline functions */
4082 
4083 /*!
4084  Creates an instance of QCPLayoutGrid and sets default values.
4085 */
4087  mColumnSpacing(5),
4088  mRowSpacing(5),
4089  mWrap(0),
4090  mFillOrder(foColumnsFirst)
4091 {
4092 }
4093 
4094 QCPLayoutGrid::~QCPLayoutGrid()
4095 {
4096  // clear all child layout elements. This is important because only the specific layouts know how
4097  // to handle removing elements (clear calls virtual removeAt method to do that).
4098  clear();
4099 }
4100 
4101 /*!
4102  Returns the element in the cell in \a row and \a column.
4103 
4104  Returns \c nullptr if either the row/column is invalid or if the cell is empty. In those cases, a
4105  qDebug message is printed. To check whether a cell exists and isn't empty, use \ref hasElement.
4106 
4107  \see addElement, hasElement
4108 */
4109 QCPLayoutElement *QCPLayoutGrid::element(int row, int column) const
4110 {
4111  if (row >= 0 && row < mElements.size())
4112  {
4113  if (column >= 0 && column < mElements.first().size())
4114  {
4115  if (QCPLayoutElement *result = mElements.at(row).at(column))
4116  return result;
4117  else
4118  qDebug() << Q_FUNC_INFO << "Requested cell is empty. Row:" << row << "Column:" << column;
4119  } else
4120  qDebug() << Q_FUNC_INFO << "Invalid column. Row:" << row << "Column:" << column;
4121  } else
4122  qDebug() << Q_FUNC_INFO << "Invalid row. Row:" << row << "Column:" << column;
4123  return nullptr;
4124 }
4125 
4126 
4127 /*! \overload
4128 
4129  Adds the \a element to cell with \a row and \a column. If \a element is already in a layout, it
4130  is first removed from there. If \a row or \a column don't exist yet, the layout is expanded
4131  accordingly.
4132 
4133  Returns true if the element was added successfully, i.e. if the cell at \a row and \a column
4134  didn't already have an element.
4135 
4136  Use the overload of this method without explicit row/column index to place the element according
4137  to the configured fill order and wrapping settings.
4138 
4139  \see element, hasElement, take, remove
4140 */
4141 bool QCPLayoutGrid::addElement(int row, int column, QCPLayoutElement *element)
4142 {
4143  if (!hasElement(row, column))
4144  {
4145  if (element && element->layout()) // remove from old layout first
4146  element->layout()->take(element);
4147  expandTo(row+1, column+1);
4148  mElements[row][column] = element;
4149  if (element)
4151  return true;
4152  } else
4153  qDebug() << Q_FUNC_INFO << "There is already an element in the specified row/column:" << row << column;
4154  return false;
4155 }
4156 
4157 /*! \overload
4158 
4159  Adds the \a element to the next empty cell according to the current fill order (\ref
4160  setFillOrder) and wrapping (\ref setWrap). If \a element is already in a layout, it is first
4161  removed from there. If necessary, the layout is expanded to hold the new element.
4162 
4163  Returns true if the element was added successfully.
4164 
4165  \see setFillOrder, setWrap, element, hasElement, take, remove
4166 */
4168 {
4169  int rowIndex = 0;
4170  int colIndex = 0;
4171  if (mFillOrder == foColumnsFirst)
4172  {
4173  while (hasElement(rowIndex, colIndex))
4174  {
4175  ++colIndex;
4176  if (colIndex >= mWrap && mWrap > 0)
4177  {
4178  colIndex = 0;
4179  ++rowIndex;
4180  }
4181  }
4182  } else
4183  {
4184  while (hasElement(rowIndex, colIndex))
4185  {
4186  ++rowIndex;
4187  if (rowIndex >= mWrap && mWrap > 0)
4188  {
4189  rowIndex = 0;
4190  ++colIndex;
4191  }
4192  }
4193  }
4194  return addElement(rowIndex, colIndex, element);
4195 }
4196 
4197 /*!
4198  Returns whether the cell at \a row and \a column exists and contains a valid element, i.e. isn't
4199  empty.
4200 
4201  \see element
4202 */
4203 bool QCPLayoutGrid::hasElement(int row, int column)
4204 {
4205  if (row >= 0 && row < rowCount() && column >= 0 && column < columnCount())
4206  return mElements.at(row).at(column);
4207  else
4208  return false;
4209 }
4210 
4211 /*!
4212  Sets the stretch \a factor of \a column.
4213 
4214  Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond
4215  their minimum and maximum widths/heights, regardless of the stretch factor. (see \ref
4216  QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize, \ref
4217  QCPLayoutElement::setSizeConstraintRect.)
4218 
4219  The default stretch factor of newly created rows/columns is 1.
4220 
4221  \see setColumnStretchFactors, setRowStretchFactor
4222 */
4223 void QCPLayoutGrid::setColumnStretchFactor(int column, double factor)
4224 {
4225  if (column >= 0 && column < columnCount())
4226  {
4227  if (factor > 0)
4228  mColumnStretchFactors[column] = factor;
4229  else
4230  qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor;
4231  } else
4232  qDebug() << Q_FUNC_INFO << "Invalid column:" << column;
4233 }
4234 
4235 /*!
4236  Sets the stretch \a factors of all columns. \a factors must have the size \ref columnCount.
4237 
4238  Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond
4239  their minimum and maximum widths/heights, regardless of the stretch factor. (see \ref
4240  QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize, \ref
4241  QCPLayoutElement::setSizeConstraintRect.)
4242 
4243  The default stretch factor of newly created rows/columns is 1.
4244 
4245  \see setColumnStretchFactor, setRowStretchFactors
4246 */
4248 {
4249  if (factors.size() == mColumnStretchFactors.size())
4250  {
4251  mColumnStretchFactors = factors;
4252  for (int i=0; i<mColumnStretchFactors.size(); ++i)
4253  {
4254  if (mColumnStretchFactors.at(i) <= 0)
4255  {
4256  qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << mColumnStretchFactors.at(i);
4257  mColumnStretchFactors[i] = 1;
4258  }
4259  }
4260  } else
4261  qDebug() << Q_FUNC_INFO << "Column count not equal to passed stretch factor count:" << factors;
4262 }
4263 
4264 /*!
4265  Sets the stretch \a factor of \a row.
4266 
4267  Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond
4268  their minimum and maximum widths/heights, regardless of the stretch factor. (see \ref
4269  QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize, \ref
4270  QCPLayoutElement::setSizeConstraintRect.)
4271 
4272  The default stretch factor of newly created rows/columns is 1.
4273 
4274  \see setColumnStretchFactors, setRowStretchFactor
4275 */
4276 void QCPLayoutGrid::setRowStretchFactor(int row, double factor)
4277 {
4278  if (row >= 0 && row < rowCount())
4279  {
4280  if (factor > 0)
4281  mRowStretchFactors[row] = factor;
4282  else
4283  qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << factor;
4284  } else
4285  qDebug() << Q_FUNC_INFO << "Invalid row:" << row;
4286 }
4287 
4288 /*!
4289  Sets the stretch \a factors of all rows. \a factors must have the size \ref rowCount.
4290 
4291  Stretch factors control the relative sizes of rows and columns. Cells will not be resized beyond
4292  their minimum and maximum widths/heights, regardless of the stretch factor. (see \ref
4293  QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize, \ref
4294  QCPLayoutElement::setSizeConstraintRect.)
4295 
4296  The default stretch factor of newly created rows/columns is 1.
4297 
4298  \see setRowStretchFactor, setColumnStretchFactors
4299 */
4301 {
4302  if (factors.size() == mRowStretchFactors.size())
4303  {
4304  mRowStretchFactors = factors;
4305  for (int i=0; i<mRowStretchFactors.size(); ++i)
4306  {
4307  if (mRowStretchFactors.at(i) <= 0)
4308  {
4309  qDebug() << Q_FUNC_INFO << "Invalid stretch factor, must be positive:" << mRowStretchFactors.at(i);
4310  mRowStretchFactors[i] = 1;
4311  }
4312  }
4313  } else
4314  qDebug() << Q_FUNC_INFO << "Row count not equal to passed stretch factor count:" << factors;
4315 }
4316 
4317 /*!
4318  Sets the gap that is left blank between columns to \a pixels.
4319 
4320  \see setRowSpacing
4321 */
4323 {
4324  mColumnSpacing = pixels;
4325 }
4326 
4327 /*!
4328  Sets the gap that is left blank between rows to \a pixels.
4329 
4330  \see setColumnSpacing
4331 */
4333 {
4334  mRowSpacing = pixels;
4335 }
4336 
4337 /*!
4338  Sets the maximum number of columns or rows that are used, before new elements added with \ref
4339  addElement(QCPLayoutElement*) will start to fill the next row or column, respectively. It depends
4340  on \ref setFillOrder, whether rows or columns are wrapped.
4341 
4342  If \a count is set to zero, no wrapping will ever occur.
4343 
4344  If you wish to re-wrap the elements currently in the layout, call \ref setFillOrder with \a
4345  rearrange set to true (the actual fill order doesn't need to be changed for the rearranging to be
4346  done).
4347 
4348  Note that the method \ref addElement(int row, int column, QCPLayoutElement *element) with
4349  explicitly stated row and column is not subject to wrapping and can place elements even beyond
4350  the specified wrapping point.
4351 
4352  \see setFillOrder
4353 */
4354 void QCPLayoutGrid::setWrap(int count)
4355 {
4356  mWrap = qMax(0, count);
4357 }
4358 
4359 /*!
4360  Sets the filling order and wrapping behaviour that is used when adding new elements with the
4361  method \ref addElement(QCPLayoutElement*).
4362 
4363  The specified \a order defines whether rows or columns are filled first. Using \ref setWrap, you
4364  can control at which row/column count wrapping into the next column/row will occur. If you set it
4365  to zero, no wrapping will ever occur. Changing the fill order also changes the meaning of the
4366  linear index used e.g. in \ref elementAt and \ref takeAt. The default fill order for \ref
4367  QCPLayoutGrid is \ref foColumnsFirst.
4368 
4369  If you want to have all current elements arranged in the new order, set \a rearrange to true. The
4370  elements will be rearranged in a way that tries to preserve their linear index. However, empty
4371  cells are skipped during build-up of the new cell order, which shifts the succeeding element's
4372  index. The rearranging is performed even if the specified \a order is already the current fill
4373  order. Thus this method can be used to re-wrap the current elements.
4374 
4375  If \a rearrange is false, the current element arrangement is not changed, which means the
4376  linear indexes change (because the linear index is dependent on the fill order).
4377 
4378  Note that the method \ref addElement(int row, int column, QCPLayoutElement *element) with
4379  explicitly stated row and column is not subject to wrapping and can place elements even beyond
4380  the specified wrapping point.
4381 
4382  \see setWrap, addElement(QCPLayoutElement*)
4383 */
4384 void QCPLayoutGrid::setFillOrder(FillOrder order, bool rearrange)
4385 {
4386  // if rearranging, take all elements via linear index of old fill order:
4387  const int elCount = elementCount();
4388  QVector<QCPLayoutElement*> tempElements;
4389  if (rearrange)
4390  {
4391  tempElements.reserve(elCount);
4392  for (int i=0; i<elCount; ++i)
4393  {
4394  if (elementAt(i))
4395  tempElements.append(takeAt(i));
4396  }
4397  simplify();
4398  }
4399  // change fill order as requested:
4400  mFillOrder = order;
4401  // if rearranging, re-insert via linear index according to new fill order:
4402  if (rearrange)
4403  {
4404  foreach (QCPLayoutElement *tempElement, tempElements)
4405  addElement(tempElement);
4406  }
4407 }
4408 
4409 /*!
4410  Expands the layout to have \a newRowCount rows and \a newColumnCount columns. So the last valid
4411  row index will be \a newRowCount-1, the last valid column index will be \a newColumnCount-1.
4412 
4413  If the current column/row count is already larger or equal to \a newColumnCount/\a newRowCount,
4414  this function does nothing in that dimension.
4415 
4416  Newly created cells are empty, new rows and columns have the stretch factor 1.
4417 
4418  Note that upon a call to \ref addElement, the layout is expanded automatically to contain the
4419  specified row and column, using this function.
4420 
4421  \see simplify
4422 */
4423 void QCPLayoutGrid::expandTo(int newRowCount, int newColumnCount)
4424 {
4425  // add rows as necessary:
4426  while (rowCount() < newRowCount)
4427  {
4428  mElements.append(QList<QCPLayoutElement*>());
4429  mRowStretchFactors.append(1);
4430  }
4431  // go through rows and expand columns as necessary:
4432  int newColCount = qMax(columnCount(), newColumnCount);
4433  for (int i=0; i<rowCount(); ++i)
4434  {
4435  while (mElements.at(i).size() < newColCount)
4436  mElements[i].append(nullptr);
4437  }
4438  while (mColumnStretchFactors.size() < newColCount)
4439  mColumnStretchFactors.append(1);
4440 }
4441 
4442 /*!
4443  Inserts a new row with empty cells at the row index \a newIndex. Valid values for \a newIndex
4444  range from 0 (inserts a row at the top) to \a rowCount (appends a row at the bottom).
4445 
4446  \see insertColumn
4447 */
4448 void QCPLayoutGrid::insertRow(int newIndex)
4449 {
4450  if (mElements.isEmpty() || mElements.first().isEmpty()) // if grid is completely empty, add first cell
4451  {
4452  expandTo(1, 1);
4453  return;
4454  }
4455 
4456  if (newIndex < 0)
4457  newIndex = 0;
4458  if (newIndex > rowCount())
4459  newIndex = rowCount();
4460 
4461  mRowStretchFactors.insert(newIndex, 1);
4462  QList<QCPLayoutElement*> newRow;
4463  for (int col=0; col<columnCount(); ++col)
4464  newRow.append(nullptr);
4465  mElements.insert(newIndex, newRow);
4466 }
4467 
4468 /*!
4469  Inserts a new column with empty cells at the column index \a newIndex. Valid values for \a
4470  newIndex range from 0 (inserts a column at the left) to \a columnCount (appends a column at the
4471  right).
4472 
4473  \see insertRow
4474 */
4476 {
4477  if (mElements.isEmpty() || mElements.first().isEmpty()) // if grid is completely empty, add first cell
4478  {
4479  expandTo(1, 1);
4480  return;
4481  }
4482 
4483  if (newIndex < 0)
4484  newIndex = 0;
4485  if (newIndex > columnCount())
4486  newIndex = columnCount();
4487 
4488  mColumnStretchFactors.insert(newIndex, 1);
4489  for (int row=0; row<rowCount(); ++row)
4490  mElements[row].insert(newIndex, nullptr);
4491 }
4492 
4493 /*!
4494  Converts the given \a row and \a column to the linear index used by some methods of \ref
4495  QCPLayoutGrid and \ref QCPLayout.
4496 
4497  The way the cells are indexed depends on \ref setFillOrder. If it is \ref foRowsFirst, the
4498  indices increase left to right and then top to bottom. If it is \ref foColumnsFirst, the indices
4499  increase top to bottom and then left to right.
4500 
4501  For the returned index to be valid, \a row and \a column must be valid indices themselves, i.e.
4502  greater or equal to zero and smaller than the current \ref rowCount/\ref columnCount.
4503 
4504  \see indexToRowCol
4505 */
4506 int QCPLayoutGrid::rowColToIndex(int row, int column) const
4507 {
4508  if (row >= 0 && row < rowCount())
4509  {
4510  if (column >= 0 && column < columnCount())
4511  {
4512  switch (mFillOrder)
4513  {
4514  case foRowsFirst: return column*rowCount() + row;
4515  case foColumnsFirst: return row*columnCount() + column;
4516  }
4517  } else
4518  qDebug() << Q_FUNC_INFO << "row index out of bounds:" << row;
4519  } else
4520  qDebug() << Q_FUNC_INFO << "column index out of bounds:" << column;
4521  return 0;
4522 }
4523 
4524 /*!
4525  Converts the linear index to row and column indices and writes the result to \a row and \a
4526  column.
4527 
4528  The way the cells are indexed depends on \ref setFillOrder. If it is \ref foRowsFirst, the
4529  indices increase left to right and then top to bottom. If it is \ref foColumnsFirst, the indices
4530  increase top to bottom and then left to right.
4531 
4532  If there are no cells (i.e. column or row count is zero), sets \a row and \a column to -1.
4533 
4534  For the retrieved \a row and \a column to be valid, the passed \a index must be valid itself,
4535  i.e. greater or equal to zero and smaller than the current \ref elementCount.
4536 
4537  \see rowColToIndex
4538 */
4539 void QCPLayoutGrid::indexToRowCol(int index, int &row, int &column) const
4540 {
4541  row = -1;
4542  column = -1;
4543  const int nCols = columnCount();
4544  const int nRows = rowCount();
4545  if (nCols == 0 || nRows == 0)
4546  return;
4547  if (index < 0 || index >= elementCount())
4548  {
4549  qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
4550  return;
4551  }
4552 
4553  switch (mFillOrder)
4554  {
4555  case foRowsFirst:
4556  {
4557  column = index / nRows;
4558  row = index % nRows;
4559  break;
4560  }
4561  case foColumnsFirst:
4562  {
4563  row = index / nCols;
4564  column = index % nCols;
4565  break;
4566  }
4567  }
4568 }
4569 
4570 /* inherits documentation from base class */
4572 {
4573  QVector<int> minColWidths, minRowHeights, maxColWidths, maxRowHeights;
4574  getMinimumRowColSizes(&minColWidths, &minRowHeights);
4575  getMaximumRowColSizes(&maxColWidths, &maxRowHeights);
4576 
4577  int totalRowSpacing = (rowCount()-1) * mRowSpacing;
4578  int totalColSpacing = (columnCount()-1) * mColumnSpacing;
4579  QVector<int> colWidths = getSectionSizes(maxColWidths, minColWidths, mColumnStretchFactors.toVector(), mRect.width()-totalColSpacing);
4580  QVector<int> rowHeights = getSectionSizes(maxRowHeights, minRowHeights, mRowStretchFactors.toVector(), mRect.height()-totalRowSpacing);
4581 
4582  // go through cells and set rects accordingly:
4583  int yOffset = mRect.top();
4584  for (int row=0; row<rowCount(); ++row)
4585  {
4586  if (row > 0)
4587  yOffset += rowHeights.at(row-1)+mRowSpacing;
4588  int xOffset = mRect.left();
4589  for (int col=0; col<columnCount(); ++col)
4590  {
4591  if (col > 0)
4592  xOffset += colWidths.at(col-1)+mColumnSpacing;
4593  if (mElements.at(row).at(col))
4594  mElements.at(row).at(col)->setOuterRect(QRect(xOffset, yOffset, colWidths.at(col), rowHeights.at(row)));
4595  }
4596  }
4597 }
4598 
4599 /*!
4600  \seebaseclassmethod
4601 
4602  Note that the association of the linear \a index to the row/column based cells depends on the
4603  current setting of \ref setFillOrder.
4604 
4605  \see rowColToIndex
4606 */
4608 {
4609  if (index >= 0 && index < elementCount())
4610  {
4611  int row, col;
4612  indexToRowCol(index, row, col);
4613  return mElements.at(row).at(col);
4614  } else
4615  return nullptr;
4616 }
4617 
4618 /*!
4619  \seebaseclassmethod
4620 
4621  Note that the association of the linear \a index to the row/column based cells depends on the
4622  current setting of \ref setFillOrder.
4623 
4624  \see rowColToIndex
4625 */
4627 {
4628  if (QCPLayoutElement *el = elementAt(index))
4629  {
4630  releaseElement(el);
4631  int row, col;
4632  indexToRowCol(index, row, col);
4633  mElements[row][col] = nullptr;
4634  return el;
4635  } else
4636  {
4637  qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index;
4638  return nullptr;
4639  }
4640 }
4641 
4642 /* inherits documentation from base class */
4644 {
4645  if (element)
4646  {
4647  for (int i=0; i<elementCount(); ++i)
4648  {
4649  if (elementAt(i) == element)
4650  {
4651  takeAt(i);
4652  return true;
4653  }
4654  }
4655  qDebug() << Q_FUNC_INFO << "Element not in this layout, couldn't take";
4656  } else
4657  qDebug() << Q_FUNC_INFO << "Can't take nullptr element";
4658  return false;
4659 }
4660 
4661 /* inherits documentation from base class */
4663 {
4664  QList<QCPLayoutElement*> result;
4665  const int elCount = elementCount();
4666 #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
4667  result.reserve(elCount);
4668 #endif
4669  for (int i=0; i<elCount; ++i)
4670  result.append(elementAt(i));
4671  if (recursive)
4672  {
4673  for (int i=0; i<elCount; ++i)
4674  {
4675  if (result.at(i))
4676  result << result.at(i)->elements(recursive);
4677  }
4678  }
4679  return result;
4680 }
4681 
4682 /*!
4683  Simplifies the layout by collapsing rows and columns which only contain empty cells.
4684 */
4686 {
4687  // remove rows with only empty cells:
4688  for (int row=rowCount()-1; row>=0; --row)
4689  {
4690  bool hasElements = false;
4691  for (int col=0; col<columnCount(); ++col)
4692  {
4693  if (mElements.at(row).at(col))
4694  {
4695  hasElements = true;
4696  break;
4697  }
4698  }
4699  if (!hasElements)
4700  {
4701  mRowStretchFactors.removeAt(row);
4702  mElements.removeAt(row);
4703  if (mElements.isEmpty()) // removed last element, also remove stretch factor (wouldn't happen below because also columnCount changed to 0 now)
4704  mColumnStretchFactors.clear();
4705  }
4706  }
4707 
4708  // remove columns with only empty cells:
4709  for (int col=columnCount()-1; col>=0; --col)
4710  {
4711  bool hasElements = false;
4712  for (int row=0; row<rowCount(); ++row)
4713  {
4714  if (mElements.at(row).at(col))
4715  {
4716  hasElements = true;
4717  break;
4718  }
4719  }
4720  if (!hasElements)
4721  {
4722  mColumnStretchFactors.removeAt(col);
4723  for (int row=0; row<rowCount(); ++row)
4724  mElements[row].removeAt(col);
4725  }
4726  }
4727 }
4728 
4729 /* inherits documentation from base class */
4731 {
4732  QVector<int> minColWidths, minRowHeights;
4733  getMinimumRowColSizes(&minColWidths, &minRowHeights);
4734  QSize result(0, 0);
4735  foreach (int w, minColWidths)
4736  result.rwidth() += w;
4737  foreach (int h, minRowHeights)
4738  result.rheight() += h;
4739  result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing;
4740  result.rheight() += qMax(0, rowCount()-1) * mRowSpacing;
4741  result.rwidth() += mMargins.left()+mMargins.right();
4742  result.rheight() += mMargins.top()+mMargins.bottom();
4743  return result;
4744 }
4745 
4746 /* inherits documentation from base class */
4748 {
4749  QVector<int> maxColWidths, maxRowHeights;
4750  getMaximumRowColSizes(&maxColWidths, &maxRowHeights);
4751 
4752  QSize result(0, 0);
4753  foreach (int w, maxColWidths)
4754  result.setWidth(qMin(result.width()+w, QWIDGETSIZE_MAX));
4755  foreach (int h, maxRowHeights)
4756  result.setHeight(qMin(result.height()+h, QWIDGETSIZE_MAX));
4757  result.rwidth() += qMax(0, columnCount()-1) * mColumnSpacing;
4758  result.rheight() += qMax(0, rowCount()-1) * mRowSpacing;
4759  result.rwidth() += mMargins.left()+mMargins.right();
4760  result.rheight() += mMargins.top()+mMargins.bottom();
4761  if (result.height() > QWIDGETSIZE_MAX)
4762  result.setHeight(QWIDGETSIZE_MAX);
4763  if (result.width() > QWIDGETSIZE_MAX)
4764  result.setWidth(QWIDGETSIZE_MAX);
4765  return result;
4766 }
4767 
4768 /*! \internal
4769 
4770  Places the minimum column widths and row heights into \a minColWidths and \a minRowHeights
4771  respectively.
4772 
4773  The minimum height of a row is the largest minimum height of any element's outer rect in that
4774  row. The minimum width of a column is the largest minimum width of any element's outer rect in
4775  that column.
4776 
4777  This is a helper function for \ref updateLayout.
4778 
4779  \see getMaximumRowColSizes
4780 */
4781 void QCPLayoutGrid::getMinimumRowColSizes(QVector<int> *minColWidths, QVector<int> *minRowHeights) const
4782 {
4783  *minColWidths = QVector<int>(columnCount(), 0);
4784  *minRowHeights = QVector<int>(rowCount(), 0);
4785  for (int row=0; row<rowCount(); ++row)
4786  {
4787  for (int col=0; col<columnCount(); ++col)
4788  {
4789  if (QCPLayoutElement *el = mElements.at(row).at(col))
4790  {
4791  QSize minSize = getFinalMinimumOuterSize(el);
4792  if (minColWidths->at(col) < minSize.width())
4793  (*minColWidths)[col] = minSize.width();
4794  if (minRowHeights->at(row) < minSize.height())
4795  (*minRowHeights)[row] = minSize.height();
4796  }
4797  }
4798  }
4799 }
4800 
4801 /*! \internal
4802 
4803  Places the maximum column widths and row heights into \a maxColWidths and \a maxRowHeights
4804  respectively.
4805 
4806  The maximum height of a row is the smallest maximum height of any element's outer rect in that
4807  row. The maximum width of a column is the smallest maximum width of any element's outer rect in
4808  that column.
4809 
4810  This is a helper function for \ref updateLayout.
4811 
4812  \see getMinimumRowColSizes
4813 */
4814 void QCPLayoutGrid::getMaximumRowColSizes(QVector<int> *maxColWidths, QVector<int> *maxRowHeights) const
4815 {
4816  *maxColWidths = QVector<int>(columnCount(), QWIDGETSIZE_MAX);
4817  *maxRowHeights = QVector<int>(rowCount(), QWIDGETSIZE_MAX);
4818  for (int row=0; row<rowCount(); ++row)
4819  {
4820  for (int col=0; col<columnCount(); ++col)
4821  {
4822  if (QCPLayoutElement *el = mElements.at(row).at(col))
4823  {
4824  QSize maxSize = getFinalMaximumOuterSize(el);
4825  if (maxColWidths->at(col) > maxSize.width())
4826  (*maxColWidths)[col] = maxSize.width();
4827  if (maxRowHeights->at(row) > maxSize.height())
4828  (*maxRowHeights)[row] = maxSize.height();
4829  }
4830  }
4831  }
4832 }
4833 
4834 
4835 ////////////////////////////////////////////////////////////////////////////////////////////////////
4836 //////////////////// QCPLayoutInset
4837 ////////////////////////////////////////////////////////////////////////////////////////////////////
4838 /*! \class QCPLayoutInset
4839  \brief A layout that places child elements aligned to the border or arbitrarily positioned
4840 
4841  Elements are placed either aligned to the border or at arbitrary position in the area of the
4842  layout. Which placement applies is controlled with the \ref InsetPlacement (\ref
4843  setInsetPlacement).
4844 
4845  Elements are added via \ref addElement(QCPLayoutElement *element, Qt::Alignment alignment) or
4846  addElement(QCPLayoutElement *element, const QRectF &rect). If the first method is used, the inset
4847  placement will default to \ref ipBorderAligned and the element will be aligned according to the
4848  \a alignment parameter. The second method defaults to \ref ipFree and allows placing elements at
4849  arbitrary position and size, defined by \a rect.
4850 
4851  The alignment or rect can be set via \ref setInsetAlignment or \ref setInsetRect, respectively.
4852 
4853  This is the layout that every QCPAxisRect has as \ref QCPAxisRect::insetLayout.
4854 */
4855 
4856 /* start documentation of inline functions */
4857 
4858 /*! \fn virtual void QCPLayoutInset::simplify()
4859 
4860  The QCPInsetLayout does not need simplification since it can never have empty cells due to its
4861  linear index structure. This method does nothing.
4862 */
4863 
4864 /* end documentation of inline functions */
4865 
4866 /*!
4867  Creates an instance of QCPLayoutInset and sets default values.
4868 */
4870 {
4871 }
4872 
4873 QCPLayoutInset::~QCPLayoutInset()
4874 {
4875  // clear all child layout elements. This is important because only the specific layouts know how
4876  // to handle removing elements (clear calls virtual removeAt method to do that).
4877  clear();
4878 }
4879 
4880 /*!
4881  Returns the placement type of the element with the specified \a index.
4882 */
4884 {
4885  if (elementAt(index))
4886  return mInsetPlacement.at(index);
4887  else
4888  {
4889  qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
4890  return ipFree;
4891  }
4892 }
4893 
4894 /*!
4895  Returns the alignment of the element with the specified \a index. The alignment only has a
4896  meaning, if the inset placement (\ref setInsetPlacement) is \ref ipBorderAligned.
4897 */
4899 {
4900  if (elementAt(index))
4901  return mInsetAlignment.at(index);
4902  else
4903  {
4904  qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
4905 #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
4906  return nullptr;
4907 #else
4908  return {};
4909 #endif
4910  }
4911 }
4912 
4913 /*!
4914  Returns the rect of the element with the specified \a index. The rect only has a
4915  meaning, if the inset placement (\ref setInsetPlacement) is \ref ipFree.
4916 */
4918 {
4919  if (elementAt(index))
4920  return mInsetRect.at(index);
4921  else
4922  {
4923  qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
4924  return {};
4925  }
4926 }
4927 
4928 /*!
4929  Sets the inset placement type of the element with the specified \a index to \a placement.
4930 
4931  \see InsetPlacement
4932 */
4934 {
4935  if (elementAt(index))
4936  mInsetPlacement[index] = placement;
4937  else
4938  qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
4939 }
4940 
4941 /*!
4942  If the inset placement (\ref setInsetPlacement) is \ref ipBorderAligned, this function
4943  is used to set the alignment of the element with the specified \a index to \a alignment.
4944 
4945  \a alignment is an or combination of the following alignment flags: Qt::AlignLeft,
4946  Qt::AlignHCenter, Qt::AlighRight, Qt::AlignTop, Qt::AlignVCenter, Qt::AlignBottom. Any other
4947  alignment flags will be ignored.
4948 */
4950 {
4951  if (elementAt(index))
4952  mInsetAlignment[index] = alignment;
4953  else
4954  qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
4955 }
4956 
4957 /*!
4958  If the inset placement (\ref setInsetPlacement) is \ref ipFree, this function is used to set the
4959  position and size of the element with the specified \a index to \a rect.
4960 
4961  \a rect is given in fractions of the whole inset layout rect. So an inset with rect (0, 0, 1, 1)
4962  will span the entire layout. An inset with rect (0.6, 0.1, 0.35, 0.35) will be in the top right
4963  corner of the layout, with 35% width and height of the parent layout.
4964 
4965  Note that the minimum and maximum sizes of the embedded element (\ref
4966  QCPLayoutElement::setMinimumSize, \ref QCPLayoutElement::setMaximumSize) are enforced.
4967 */
4968 void QCPLayoutInset::setInsetRect(int index, const QRectF &rect)
4969 {
4970  if (elementAt(index))
4971  mInsetRect[index] = rect;
4972  else
4973  qDebug() << Q_FUNC_INFO << "Invalid element index:" << index;
4974 }
4975 
4976 /* inherits documentation from base class */
4978 {
4979  for (int i=0; i<mElements.size(); ++i)
4980  {
4981  QCPLayoutElement *el = mElements.at(i);
4982  QRect insetRect;
4983  QSize finalMinSize = getFinalMinimumOuterSize(el);
4984  QSize finalMaxSize = getFinalMaximumOuterSize(el);
4985  if (mInsetPlacement.at(i) == ipFree)
4986  {
4987  insetRect = QRect(int( rect().x()+rect().width()*mInsetRect.at(i).x() ),
4988  int( rect().y()+rect().height()*mInsetRect.at(i).y() ),
4989  int( rect().width()*mInsetRect.at(i).width() ),
4990  int( rect().height()*mInsetRect.at(i).height() ));
4991  if (insetRect.size().width() < finalMinSize.width())
4992  insetRect.setWidth(finalMinSize.width());
4993  if (insetRect.size().height() < finalMinSize.height())
4994  insetRect.setHeight(finalMinSize.height());
4995  if (insetRect.size().width() > finalMaxSize.width())
4996  insetRect.setWidth(finalMaxSize.width());
4997  if (insetRect.size().height() > finalMaxSize.height())
4998  insetRect.setHeight(finalMaxSize.height());
4999  } else if (mInsetPlacement.at(i) == ipBorderAligned)
5000  {
5001  insetRect.setSize(finalMinSize);
5002  Qt::Alignment al = mInsetAlignment.at(i);
5003  if (al.testFlag(Qt::AlignLeft)) insetRect.moveLeft(rect().x());
5004  else if (al.testFlag(Qt::AlignRight)) insetRect.moveRight(rect().x()+rect().width());
5005  else insetRect.moveLeft(int( rect().x()+rect().width()*0.5-finalMinSize.width()*0.5 )); // default to Qt::AlignHCenter
5006  if (al.testFlag(Qt::AlignTop)) insetRect.moveTop(rect().y());
5007  else if (al.testFlag(Qt::AlignBottom)) insetRect.moveBottom(rect().y()+rect().height());
5008  else insetRect.moveTop(int( rect().y()+rect().height()*0.5-finalMinSize.height()*0.5 )); // default to Qt::AlignVCenter
5009  }
5010  mElements.at(i)->setOuterRect(insetRect);
5011  }
5012 }
5013 
5014 /* inherits documentation from base class */
5016 {
5017  return mElements.size();
5018 }
5019 
5020 /* inherits documentation from base class */
5022 {
5023  if (index >= 0 && index < mElements.size())
5024  return mElements.at(index);
5025  else
5026  return nullptr;
5027 }
5028 
5029 /* inherits documentation from base class */
5031 {
5032  if (QCPLayoutElement *el = elementAt(index))
5033  {
5034  releaseElement(el);
5035  mElements.removeAt(index);
5036  mInsetPlacement.removeAt(index);
5037  mInsetAlignment.removeAt(index);
5038  mInsetRect.removeAt(index);
5039  return el;
5040  } else
5041  {
5042  qDebug() << Q_FUNC_INFO << "Attempt to take invalid index:" << index;
5043  return nullptr;
5044  }
5045 }
5046 
5047 /* inherits documentation from base class */
5049 {
5050  if (element)
5051  {
5052  for (int i=0; i<elementCount(); ++i)
5053  {
5054  if (elementAt(i) == element)
5055  {
5056  takeAt(i);
5057  return true;
5058  }
5059  }
5060  qDebug() << Q_FUNC_INFO << "Element not in this layout, couldn't take";
5061  } else
5062  qDebug() << Q_FUNC_INFO << "Can't take nullptr element";
5063  return false;
5064 }
5065 
5066 /*!
5067  The inset layout is sensitive to events only at areas where its (visible) child elements are
5068  sensitive. If the selectTest method of any of the child elements returns a positive number for \a
5069  pos, this method returns a value corresponding to 0.99 times the parent plot's selection
5070  tolerance. The inset layout is not selectable itself by default. So if \a onlySelectable is true,
5071  -1.0 is returned.
5072 
5073  See \ref QCPLayerable::selectTest for a general explanation of this virtual method.
5074 */
5075 double QCPLayoutInset::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
5076 {
5077  Q_UNUSED(details)
5078  if (onlySelectable)
5079  return -1;
5080 
5081  foreach (QCPLayoutElement *el, mElements)
5082  {
5083  // inset layout shall only return positive selectTest, if actually an inset object is at pos
5084  // else it would block the entire underlying QCPAxisRect with its surface.
5085  if (el->realVisibility() && el->selectTest(pos, onlySelectable) >= 0)
5086  return mParentPlot->selectionTolerance()*0.99;
5087  }
5088  return -1;
5089 }
5090 
5091 /*!
5092  Adds the specified \a element to the layout as an inset aligned at the border (\ref
5093  setInsetAlignment is initialized with \ref ipBorderAligned). The alignment is set to \a
5094  alignment.
5095 
5096  \a alignment is an or combination of the following alignment flags: Qt::AlignLeft,
5097  Qt::AlignHCenter, Qt::AlighRight, Qt::AlignTop, Qt::AlignVCenter, Qt::AlignBottom. Any other
5098  alignment flags will be ignored.
5099 
5100  \see addElement(QCPLayoutElement *element, const QRectF &rect)
5101 */
5103 {
5104  if (element)
5105  {
5106  if (element->layout()) // remove from old layout first
5107  element->layout()->take(element);
5108  mElements.append(element);
5109  mInsetPlacement.append(ipBorderAligned);
5110  mInsetAlignment.append(alignment);
5111  mInsetRect.append(QRectF(0.6, 0.6, 0.4, 0.4));
5112  adoptElement(element);
5113  } else
5114  qDebug() << Q_FUNC_INFO << "Can't add nullptr element";
5115 }
5116 
5117 /*!
5118  Adds the specified \a element to the layout as an inset with free positioning/sizing (\ref
5119  setInsetAlignment is initialized with \ref ipFree). The position and size is set to \a
5120  rect.
5121 
5122  \a rect is given in fractions of the whole inset layout rect. So an inset with rect (0, 0, 1, 1)
5123  will span the entire layout. An inset with rect (0.6, 0.1, 0.35, 0.35) will be in the top right
5124  corner of the layout, with 35% width and height of the parent layout.
5125 
5126  \see addElement(QCPLayoutElement *element, Qt::Alignment alignment)
5127 */
5129 {
5130  if (element)
5131  {
5132  if (element->layout()) // remove from old layout first
5133  element->layout()->take(element);
5134  mElements.append(element);
5135  mInsetPlacement.append(ipFree);
5136  mInsetAlignment.append(Qt::AlignRight|Qt::AlignTop);
5137  mInsetRect.append(rect);
5138  adoptElement(element);
5139  } else
5140  qDebug() << Q_FUNC_INFO << "Can't add nullptr element";
5141 }
5142 /* end of 'src/layout.cpp' */
5143 
5144 
5145 /* including file 'src/lineending.cpp' */
5146 /* modified 2021-03-29T02:30:44, size 11189 */
5147 
5148 ////////////////////////////////////////////////////////////////////////////////////////////////////
5149 //////////////////// QCPLineEnding
5150 ////////////////////////////////////////////////////////////////////////////////////////////////////
5151 
5152 /*! \class QCPLineEnding
5153  \brief Handles the different ending decorations for line-like items
5154 
5155  \image html QCPLineEnding.png "The various ending styles currently supported"
5156 
5157  For every ending a line-like item has, an instance of this class exists. For example, QCPItemLine
5158  has two endings which can be set with QCPItemLine::setHead and QCPItemLine::setTail.
5159 
5160  The styles themselves are defined via the enum QCPLineEnding::EndingStyle. Most decorations can
5161  be modified regarding width and length, see \ref setWidth and \ref setLength. The direction of
5162  the ending decoration (e.g. direction an arrow is pointing) is controlled by the line-like item.
5163  For example, when both endings of a QCPItemLine are set to be arrows, they will point to opposite
5164  directions, e.g. "outward". This can be changed by \ref setInverted, which would make the
5165  respective arrow point inward.
5166 
5167  Note that due to the overloaded QCPLineEnding constructor, you may directly specify a
5168  QCPLineEnding::EndingStyle where actually a QCPLineEnding is expected, e.g.
5169  \snippet documentation/doc-code-snippets/mainwindow.cpp qcplineending-sethead
5170 */
5171 
5172 /*!
5173  Creates a QCPLineEnding instance with default values (style \ref esNone).
5174 */
5176  mStyle(esNone),
5177  mWidth(8),
5178  mLength(10),
5179  mInverted(false)
5180 {
5181 }
5182 
5183 /*!
5184  Creates a QCPLineEnding instance with the specified values.
5185 */
5186 QCPLineEnding::QCPLineEnding(QCPLineEnding::EndingStyle style, double width, double length, bool inverted) :
5187  mStyle(style),
5188  mWidth(width),
5189  mLength(length),
5190  mInverted(inverted)
5191 {
5192 }
5193 
5194 /*!
5195  Sets the style of the ending decoration.
5196 */
5198 {
5199  mStyle = style;
5200 }
5201 
5202 /*!
5203  Sets the width of the ending decoration, if the style supports it. On arrows, for example, the
5204  width defines the size perpendicular to the arrow's pointing direction.
5205 
5206  \see setLength
5207 */
5208 void QCPLineEnding::setWidth(double width)
5209 {
5210  mWidth = width;
5211 }
5212 
5213 /*!
5214  Sets the length of the ending decoration, if the style supports it. On arrows, for example, the
5215  length defines the size in pointing direction.
5216 
5217  \see setWidth
5218 */
5219 void QCPLineEnding::setLength(double length)
5220 {
5221  mLength = length;
5222 }
5223 
5224 /*!
5225  Sets whether the ending decoration shall be inverted. For example, an arrow decoration will point
5226  inward when \a inverted is set to true.
5227 
5228  Note that also the \a width direction is inverted. For symmetrical ending styles like arrows or
5229  discs, this doesn't make a difference. However, asymmetric styles like \ref esHalfBar are
5230  affected by it, which can be used to control to which side the half bar points to.
5231 */
5232 void QCPLineEnding::setInverted(bool inverted)
5233 {
5234  mInverted = inverted;
5235 }
5236 
5237 /*! \internal
5238 
5239  Returns the maximum pixel radius the ending decoration might cover, starting from the position
5240  the decoration is drawn at (typically a line ending/\ref QCPItemPosition of an item).
5241 
5242  This is relevant for clipping. Only omit painting of the decoration when the position where the
5243  decoration is supposed to be drawn is farther away from the clipping rect than the returned
5244  distance.
5245 */
5247 {
5248  switch (mStyle)
5249  {
5250  case esNone:
5251  return 0;
5252 
5253  case esFlatArrow:
5254  case esSpikeArrow:
5255  case esLineArrow:
5256  case esSkewedBar:
5257  return qSqrt(mWidth*mWidth+mLength*mLength); // items that have width and length
5258 
5259  case esDisc:
5260  case esSquare:
5261  case esDiamond:
5262  case esBar:
5263  case esHalfBar:
5264  return mWidth*1.42; // items that only have a width -> width*sqrt(2)
5265 
5266  }
5267  return 0;
5268 }
5269 
5270 /*!
5271  Starting from the origin of this line ending (which is style specific), returns the length
5272  covered by the line ending symbol, in backward direction.
5273 
5274  For example, the \ref esSpikeArrow has a shorter real length than a \ref esFlatArrow, even if
5275  both have the same \ref setLength value, because the spike arrow has an inward curved back, which
5276  reduces the length along its center axis (the drawing origin for arrows is at the tip).
5277 
5278  This function is used for precise, style specific placement of line endings, for example in
5279  QCPAxes.
5280 */
5282 {
5283  switch (mStyle)
5284  {
5285  case esNone:
5286  case esLineArrow:
5287  case esSkewedBar:
5288  case esBar:
5289  case esHalfBar:
5290  return 0;
5291 
5292  case esFlatArrow:
5293  return mLength;
5294 
5295  case esDisc:
5296  case esSquare:
5297  case esDiamond:
5298  return mWidth*0.5;
5299 
5300  case esSpikeArrow:
5301  return mLength*0.8;
5302  }
5303  return 0;
5304 }
5305 
5306 /*! \internal
5307 
5308  Draws the line ending with the specified \a painter at the position \a pos. The direction of the
5309  line ending is controlled with \a dir.
5310 */
5311 void QCPLineEnding::draw(QCPPainter *painter, const QCPVector2D &pos, const QCPVector2D &dir) const
5312 {
5313  if (mStyle == esNone)
5314  return;
5315 
5316  QCPVector2D lengthVec = dir.normalized() * mLength*(mInverted ? -1 : 1);
5317  if (lengthVec.isNull())
5318  lengthVec = QCPVector2D(1, 0);
5319  QCPVector2D widthVec = dir.normalized().perpendicular() * mWidth*0.5*(mInverted ? -1 : 1);
5320 
5321  QPen penBackup = painter->pen();
5322  QBrush brushBackup = painter->brush();
5323  QPen miterPen = penBackup;
5324  miterPen.setJoinStyle(Qt::MiterJoin); // to make arrow heads spikey
5325  QBrush brush(painter->pen().color(), Qt::SolidPattern);
5326  switch (mStyle)
5327  {
5328  case esNone: break;
5329  case esFlatArrow:
5330  {
5331  QPointF points[3] = {pos.toPointF(),
5332  (pos-lengthVec+widthVec).toPointF(),
5333  (pos-lengthVec-widthVec).toPointF()
5334  };
5335  painter->setPen(miterPen);
5336  painter->setBrush(brush);
5337  painter->drawConvexPolygon(points, 3);
5338  painter->setBrush(brushBackup);
5339  painter->setPen(penBackup);
5340  break;
5341  }
5342  case esSpikeArrow:
5343  {
5344  QPointF points[4] = {pos.toPointF(),
5345  (pos-lengthVec+widthVec).toPointF(),
5346  (pos-lengthVec*0.8).toPointF(),
5347  (pos-lengthVec-widthVec).toPointF()
5348  };
5349  painter->setPen(miterPen);
5350  painter->setBrush(brush);
5351  painter->drawConvexPolygon(points, 4);
5352  painter->setBrush(brushBackup);
5353  painter->setPen(penBackup);
5354  break;
5355  }
5356  case esLineArrow:
5357  {
5358  QPointF points[3] = {(pos-lengthVec+widthVec).toPointF(),
5359  pos.toPointF(),
5360  (pos-lengthVec-widthVec).toPointF()
5361  };
5362  painter->setPen(miterPen);
5363  painter->drawPolyline(points, 3);
5364  painter->setPen(penBackup);
5365  break;
5366  }
5367  case esDisc:
5368  {
5369  painter->setBrush(brush);
5370  painter->drawEllipse(pos.toPointF(), mWidth*0.5, mWidth*0.5);
5371  painter->setBrush(brushBackup);
5372  break;
5373  }
5374  case esSquare:
5375  {
5376  QCPVector2D widthVecPerp = widthVec.perpendicular();
5377  QPointF points[4] = {(pos-widthVecPerp+widthVec).toPointF(),
5378  (pos-widthVecPerp-widthVec).toPointF(),
5379  (pos+widthVecPerp-widthVec).toPointF(),
5380  (pos+widthVecPerp+widthVec).toPointF()
5381  };
5382  painter->setPen(miterPen);
5383  painter->setBrush(brush);
5384  painter->drawConvexPolygon(points, 4);
5385  painter->setBrush(brushBackup);
5386  painter->setPen(penBackup);
5387  break;
5388  }
5389  case esDiamond:
5390  {
5391  QCPVector2D widthVecPerp = widthVec.perpendicular();
5392  QPointF points[4] = {(pos-widthVecPerp).toPointF(),
5393  (pos-widthVec).toPointF(),
5394  (pos+widthVecPerp).toPointF(),
5395  (pos+widthVec).toPointF()
5396  };
5397  painter->setPen(miterPen);
5398  painter->setBrush(brush);
5399  painter->drawConvexPolygon(points, 4);
5400  painter->setBrush(brushBackup);
5401  painter->setPen(penBackup);
5402  break;
5403  }
5404  case esBar:
5405  {
5406  painter->drawLine((pos+widthVec).toPointF(), (pos-widthVec).toPointF());
5407  break;
5408  }
5409  case esHalfBar:
5410  {
5411  painter->drawLine((pos+widthVec).toPointF(), pos.toPointF());
5412  break;
5413  }
5414  case esSkewedBar:
5415  {
5416  QCPVector2D shift;
5417  if (!qFuzzyIsNull(painter->pen().widthF()) || painter->modes().testFlag(QCPPainter::pmNonCosmetic))
5418  shift = dir.normalized()*qMax(qreal(1.0), painter->pen().widthF())*qreal(0.5);
5419  // if drawing with thick (non-cosmetic) pen, shift bar a little in line direction to prevent line from sticking through bar slightly
5420  painter->drawLine((pos+widthVec+lengthVec*0.2*(mInverted?-1:1)+shift).toPointF(),
5421  (pos-widthVec-lengthVec*0.2*(mInverted?-1:1)+shift).toPointF());
5422  break;
5423  }
5424  }
5425 }
5426 
5427 /*! \internal
5428  \overload
5429 
5430  Draws the line ending. The direction is controlled with the \a angle parameter in radians.
5431 */
5432 void QCPLineEnding::draw(QCPPainter *painter, const QCPVector2D &pos, double angle) const
5433 {
5434  draw(painter, pos, QCPVector2D(qCos(angle), qSin(angle)));
5435 }
5436 /* end of 'src/lineending.cpp' */
5437 
5438 
5439 /* including file 'src/axis/labelpainter.cpp' */
5440 /* modified 2021-03-29T02:30:44, size 27296 */
5441 
5442 
5443 ////////////////////////////////////////////////////////////////////////////////////////////////////
5444 //////////////////// QCPLabelPainterPrivate
5445 ////////////////////////////////////////////////////////////////////////////////////////////////////
5446 
5447 /*! \class QCPLabelPainterPrivate
5448 
5449  \internal
5450  \brief (Private)
5451 
5452  This is a private class and not part of the public QCustomPlot interface.
5453 
5454 */
5455 
5456 const QChar QCPLabelPainterPrivate::SymbolDot(183);
5457 const QChar QCPLabelPainterPrivate::SymbolCross(215);
5458 
5459 /*!
5460  Constructs a QCPLabelPainterPrivate instance. Make sure to not create a new
5461  instance on every redraw, to utilize the caching mechanisms.
5462 
5463  the \a parentPlot does not take ownership of the label painter. Make sure
5464  to delete it appropriately.
5465 */
5467  mAnchorMode(amRectangular),
5468  mAnchorSide(asLeft),
5469  mAnchorReferenceType(artNormal),
5470  mColor(Qt::black),
5471  mPadding(0),
5472  mRotation(0),
5473  mSubstituteExponent(true),
5474  mMultiplicationSymbol(QChar(215)),
5475  mAbbreviateDecimalPowers(false),
5476  mParentPlot(parentPlot),
5477  mLabelCache(16)
5478 {
5479  analyzeFontMetrics();
5480 }
5481 
5482 QCPLabelPainterPrivate::~QCPLabelPainterPrivate()
5483 {
5484 }
5485 
5486 void QCPLabelPainterPrivate::setAnchorSide(AnchorSide side)
5487 {
5488  mAnchorSide = side;
5489 }
5490 
5491 void QCPLabelPainterPrivate::setAnchorMode(AnchorMode mode)
5492 {
5493  mAnchorMode = mode;
5494 }
5495 
5496 void QCPLabelPainterPrivate::setAnchorReference(const QPointF &pixelPoint)
5497 {
5498  mAnchorReference = pixelPoint;
5499 }
5500 
5501 void QCPLabelPainterPrivate::setAnchorReferenceType(AnchorReferenceType type)
5502 {
5503  mAnchorReferenceType = type;
5504 }
5505 
5506 void QCPLabelPainterPrivate::setFont(const QFont &font)
5507 {
5508  if (mFont != font)
5509  {
5510  mFont = font;
5511  analyzeFontMetrics();
5512  }
5513 }
5514 
5515 void QCPLabelPainterPrivate::setColor(const QColor &color)
5516 {
5517  mColor = color;
5518 }
5519 
5520 void QCPLabelPainterPrivate::setPadding(int padding)
5521 {
5522  mPadding = padding;
5523 }
5524 
5525 void QCPLabelPainterPrivate::setRotation(double rotation)
5526 {
5527  mRotation = qBound(-90.0, rotation, 90.0);
5528 }
5529 
5530 void QCPLabelPainterPrivate::setSubstituteExponent(bool enabled)
5531 {
5532  mSubstituteExponent = enabled;
5533 }
5534 
5535 void QCPLabelPainterPrivate::setMultiplicationSymbol(QChar symbol)
5536 {
5537  mMultiplicationSymbol = symbol;
5538 }
5539 
5540 void QCPLabelPainterPrivate::setAbbreviateDecimalPowers(bool enabled)
5541 {
5542  mAbbreviateDecimalPowers = enabled;
5543 }
5544 
5545 void QCPLabelPainterPrivate::setCacheSize(int labelCount)
5546 {
5547  mLabelCache.setMaxCost(labelCount);
5548 }
5549 
5550 int QCPLabelPainterPrivate::cacheSize() const
5551 {
5552  return mLabelCache.maxCost();
5553 }
5554 
5555 void QCPLabelPainterPrivate::drawTickLabel(QCPPainter *painter, const QPointF &tickPos, const QString &text)
5556 {
5557  double realRotation = mRotation;
5558 
5559  AnchorSide realSide = mAnchorSide;
5560  // for circular axes, the anchor side is determined depending on the quadrant of tickPos with respect to mCircularReference
5561  if (mAnchorMode == amSkewedUpright)
5562  {
5563  realSide = skewedAnchorSide(tickPos, 0.2, 0.3);
5564  } else if (mAnchorMode == amSkewedRotated) // in this mode every label is individually rotated to match circle tangent
5565  {
5566  realSide = skewedAnchorSide(tickPos, 0, 0);
5567  realRotation += QCPVector2D(tickPos-mAnchorReference).angle()/M_PI*180.0;
5568  if (realRotation > 90) realRotation -= 180;
5569  else if (realRotation < -90) realRotation += 180;
5570  }
5571 
5572  realSide = rotationCorrectedSide(realSide, realRotation); // rotation angles may change the true anchor side of the label
5573  drawLabelMaybeCached(painter, mFont, mColor, getAnchorPos(tickPos), realSide, realRotation, text);
5574 }
5575 
5576 /*! \internal
5577 
5578  Returns the size ("margin" in QCPAxisRect context, so measured perpendicular to the axis backbone
5579  direction) needed to fit the axis.
5580 */
5581 /* TODO: needed?
5582 int QCPLabelPainterPrivate::size() const
5583 {
5584  int result = 0;
5585  // get length of tick marks pointing outwards:
5586  if (!tickPositions.isEmpty())
5587  result += qMax(0, qMax(tickLengthOut, subTickLengthOut));
5588 
5589  // calculate size of tick labels:
5590  if (tickLabelSide == QCPAxis::lsOutside)
5591  {
5592  QSize tickLabelsSize(0, 0);
5593  if (!tickLabels.isEmpty())
5594  {
5595  for (int i=0; i<tickLabels.size(); ++i)
5596  getMaxTickLabelSize(tickLabelFont, tickLabels.at(i), &tickLabelsSize);
5597  result += QCPAxis::orientation(type) == Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width();
5598  result += tickLabelPadding;
5599  }
5600  }
5601 
5602  // calculate size of axis label (only height needed, because left/right labels are rotated by 90 degrees):
5603  if (!label.isEmpty())
5604  {
5605  QFontMetrics fontMetrics(labelFont);
5606  QRect bounds;
5607  bounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter | Qt::AlignVCenter, label);
5608  result += bounds.height() + labelPadding;
5609  }
5610 
5611  return result;
5612 }
5613 */
5614 
5615 /*! \internal
5616 
5617  Clears the internal label cache. Upon the next \ref draw, all labels will be created new. This
5618  method is called automatically if any parameters have changed that invalidate the cached labels,
5619  such as font, color, etc. Usually you won't need to call this method manually.
5620 */
5622 {
5623  mLabelCache.clear();
5624 }
5625 
5626 /*! \internal
5627 
5628  Returns a hash that allows uniquely identifying whether the label parameters have changed such
5629  that the cached labels must be refreshed (\ref clearCache). It is used in \ref draw. If the
5630  return value of this method hasn't changed since the last redraw, the respective label parameters
5631  haven't changed and cached labels may be used.
5632 */
5634 {
5635  QByteArray result;
5636  result.append(QByteArray::number(mParentPlot->bufferDevicePixelRatio()));
5637  result.append(QByteArray::number(mRotation));
5638  //result.append(QByteArray::number((int)tickLabelSide)); TODO: check whether this is really a cache-invalidating property
5639  result.append(QByteArray::number((int)mSubstituteExponent));
5640  result.append(QString(mMultiplicationSymbol).toUtf8());
5641  result.append(mColor.name().toLatin1()+QByteArray::number(mColor.alpha(), 16));
5642  result.append(mFont.toString().toLatin1());
5643  return result;
5644 }
5645 
5646 /*! \internal
5647 
5648  Draws a single tick label with the provided \a painter, utilizing the internal label cache to
5649  significantly speed up drawing of labels that were drawn in previous calls. The tick label is
5650  always bound to an axis, the distance to the axis is controllable via \a distanceToAxis in
5651  pixels. The pixel position in the axis direction is passed in the \a position parameter. Hence
5652  for the bottom axis, \a position would indicate the horizontal pixel position (not coordinate),
5653  at which the label should be drawn.
5654 
5655  In order to later draw the axis label in a place that doesn't overlap with the tick labels, the
5656  largest tick label size is needed. This is acquired by passing a \a tickLabelsSize to the \ref
5657  drawTickLabel calls during the process of drawing all tick labels of one axis. In every call, \a
5658  tickLabelsSize is expanded, if the drawn label exceeds the value \a tickLabelsSize currently
5659  holds.
5660 
5661  The label is drawn with the font and pen that are currently set on the \a painter. To draw
5662  superscripted powers, the font is temporarily made smaller by a fixed factor (see \ref
5663  getTickLabelData).
5664 */
5665 void QCPLabelPainterPrivate::drawLabelMaybeCached(QCPPainter *painter, const QFont &font, const QColor &color, const QPointF &pos, AnchorSide side, double rotation, const QString &text)
5666 {
5667  // warning: if you change anything here, also adapt getMaxTickLabelSize() accordingly!
5668  if (text.isEmpty()) return;
5669  QSize finalSize;
5670 
5671  if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && !painter->modes().testFlag(QCPPainter::pmNoCaching)) // label caching enabled
5672  {
5673  QByteArray key = cacheKey(text, color, rotation, side);
5674  CachedLabel *cachedLabel = mLabelCache.take(QString::fromUtf8(key)); // attempt to take label from cache (don't use object() because we want ownership/prevent deletion during our operations, we re-insert it afterwards)
5675  if (!cachedLabel) // no cached label existed, create it
5676  {
5677  LabelData labelData = getTickLabelData(font, color, rotation, side, text);
5678  cachedLabel = createCachedLabel(labelData);
5679  }
5680  // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels):
5681  bool labelClippedByBorder = false;
5682  /*
5683  if (tickLabelSide == QCPAxis::lsOutside)
5684  {
5685  if (QCPAxis::orientation(type) == Qt::Horizontal)
5686  labelClippedByBorder = labelAnchor.x()+cachedLabel->offset.x()+cachedLabel->pixmap.width()/mParentPlot->bufferDevicePixelRatio() > viewportRect.right() || labelAnchor.x()+cachedLabel->offset.x() < viewportRect.left();
5687  else
5688  labelClippedByBorder = labelAnchor.y()+cachedLabel->offset.y()+cachedLabel->pixmap.height()/mParentPlot->bufferDevicePixelRatio() > viewportRect.bottom() || labelAnchor.y()+cachedLabel->offset.y() < viewportRect.top();
5689  }
5690  */
5691  if (!labelClippedByBorder)
5692  {
5693  painter->drawPixmap(pos+cachedLabel->offset, cachedLabel->pixmap);
5694  finalSize = cachedLabel->pixmap.size()/mParentPlot->bufferDevicePixelRatio(); // TODO: collect this in a member rect list?
5695  }
5696  mLabelCache.insert(QString::fromUtf8(key), cachedLabel);
5697  } else // label caching disabled, draw text directly on surface:
5698  {
5699  LabelData labelData = getTickLabelData(font, color, rotation, side, text);
5700  // if label would be partly clipped by widget border on sides, don't draw it (only for outside tick labels):
5701  bool labelClippedByBorder = false;
5702  /*
5703  if (tickLabelSide == QCPAxis::lsOutside)
5704  {
5705  if (QCPAxis::orientation(type) == Qt::Horizontal)
5706  labelClippedByBorder = finalPosition.x()+(labelData.rotatedTotalBounds.width()+labelData.rotatedTotalBounds.left()) > viewportRect.right() || finalPosition.x()+labelData.rotatedTotalBounds.left() < viewportRect.left();
5707  else
5708  labelClippedByBorder = finalPosition.y()+(labelData.rotatedTotalBounds.height()+labelData.rotatedTotalBounds.top()) > viewportRect.bottom() || finalPosition.y()+labelData.rotatedTotalBounds.top() < viewportRect.top();
5709  }
5710  */
5711  if (!labelClippedByBorder)
5712  {
5713  drawText(painter, pos, labelData);
5714  finalSize = labelData.rotatedTotalBounds.size();
5715  }
5716  }
5717  /*
5718  // expand passed tickLabelsSize if current tick label is larger:
5719  if (finalSize.width() > tickLabelsSize->width())
5720  tickLabelsSize->setWidth(finalSize.width());
5721  if (finalSize.height() > tickLabelsSize->height())
5722  tickLabelsSize->setHeight(finalSize.height());
5723  */
5724 }
5725 
5726 QPointF QCPLabelPainterPrivate::getAnchorPos(const QPointF &tickPos)
5727 {
5728  switch (mAnchorMode)
5729  {
5730  case amRectangular:
5731  {
5732  switch (mAnchorSide)
5733  {
5734  case asLeft: return tickPos+QPointF(mPadding, 0);
5735  case asRight: return tickPos+QPointF(-mPadding, 0);
5736  case asTop: return tickPos+QPointF(0, mPadding);
5737  case asBottom: return tickPos+QPointF(0, -mPadding);
5738  case asTopLeft: return tickPos+QPointF(mPadding*M_SQRT1_2, mPadding*M_SQRT1_2);
5739  case asTopRight: return tickPos+QPointF(-mPadding*M_SQRT1_2, mPadding*M_SQRT1_2);
5740  case asBottomRight: return tickPos+QPointF(-mPadding*M_SQRT1_2, -mPadding*M_SQRT1_2);
5741  case asBottomLeft: return tickPos+QPointF(mPadding*M_SQRT1_2, -mPadding*M_SQRT1_2);
5742  }
5743  break; // To appease the compiler. All possible values in above case.
5744  }
5745  case amSkewedUpright:
5746  case amSkewedRotated:
5747  {
5748  QCPVector2D anchorNormal(tickPos-mAnchorReference);
5749  if (mAnchorReferenceType == artTangent)
5750  anchorNormal = anchorNormal.perpendicular();
5751  anchorNormal.normalize();
5752  return tickPos+(anchorNormal*mPadding).toPointF();
5753  }
5754  }
5755  return tickPos;
5756 }
5757 
5758 /*! \internal
5759 
5760  This is a \ref placeTickLabel helper function.
5761 
5762  Draws the tick label specified in \a labelData with \a painter at the pixel positions \a x and \a
5763  y. This function is used by \ref placeTickLabel to create new tick labels for the cache, or to
5764  directly draw the labels on the QCustomPlot surface when label caching is disabled, i.e. when
5765  QCP::phCacheLabels plotting hint is not set.
5766 */
5767 void QCPLabelPainterPrivate::drawText(QCPPainter *painter, const QPointF &pos, const LabelData &labelData) const
5768 {
5769  // backup painter settings that we're about to change:
5770  QTransform oldTransform = painter->transform();
5771  QFont oldFont = painter->font();
5772  QPen oldPen = painter->pen();
5773 
5774  // transform painter to position/rotation:
5775  painter->translate(pos);
5776  painter->setTransform(labelData.transform, true);
5777 
5778  // draw text:
5779  painter->setFont(labelData.baseFont);
5780  painter->setPen(QPen(labelData.color));
5781  if (!labelData.expPart.isEmpty()) // use superscripted exponent typesetting
5782  {
5783  painter->drawText(0, 0, 0, 0, Qt::TextDontClip, labelData.basePart);
5784  if (!labelData.suffixPart.isEmpty())
5785  painter->drawText(labelData.baseBounds.width()+1+labelData.expBounds.width(), 0, 0, 0, Qt::TextDontClip, labelData.suffixPart);
5786  painter->setFont(labelData.expFont);
5787  painter->drawText(labelData.baseBounds.width()+1, 0, labelData.expBounds.width(), labelData.expBounds.height(), Qt::TextDontClip, labelData.expPart);
5788  } else
5789  {
5790  painter->drawText(0, 0, labelData.totalBounds.width(), labelData.totalBounds.height(), Qt::TextDontClip | Qt::AlignHCenter, labelData.basePart);
5791  }
5792 
5793  /* Debug code to draw label bounding boxes, baseline, and capheight
5794  painter->save();
5795  painter->setPen(QPen(QColor(0, 0, 0, 150)));
5796  painter->drawRect(labelData.totalBounds);
5797  const int baseline = labelData.totalBounds.height()-mLetterDescent;
5798  painter->setPen(QPen(QColor(255, 0, 0, 150)));
5799  painter->drawLine(QLineF(0, baseline, labelData.totalBounds.width(), baseline));
5800  painter->setPen(QPen(QColor(0, 0, 255, 150)));
5801  painter->drawLine(QLineF(0, baseline-mLetterCapHeight, labelData.totalBounds.width(), baseline-mLetterCapHeight));
5802  painter->restore();
5803  */
5804 
5805  // reset painter settings to what it was before:
5806  painter->setTransform(oldTransform);
5807  painter->setFont(oldFont);
5808  painter->setPen(oldPen);
5809 }
5810 
5811 /*! \internal
5812 
5813  This is a \ref placeTickLabel helper function.
5814 
5815  Transforms the passed \a text and \a font to a tickLabelData structure that can then be further
5816  processed by \ref getTickLabelDrawOffset and \ref drawTickLabel. It splits the text into base and
5817  exponent if necessary (member substituteExponent) and calculates appropriate bounding boxes.
5818 */
5819 QCPLabelPainterPrivate::LabelData QCPLabelPainterPrivate::getTickLabelData(const QFont &font, const QColor &color, double rotation, AnchorSide side, const QString &text) const
5820 {
5821  LabelData result;
5822  result.rotation = rotation;
5823  result.side = side;
5824  result.color = color;
5825 
5826  // determine whether beautiful decimal powers should be used
5827  bool useBeautifulPowers = false;
5828  int ePos = -1; // first index of exponent part, text before that will be basePart, text until eLast will be expPart
5829  int eLast = -1; // last index of exponent part, rest of text after this will be suffixPart
5830  if (mSubstituteExponent)
5831  {
5832  ePos = text.indexOf(QLatin1Char('e'));
5833  if (ePos > 0 && text.at(ePos-1).isDigit())
5834  {
5835  eLast = ePos;
5836  while (eLast+1 < text.size() && (text.at(eLast+1) == QLatin1Char('+') || text.at(eLast+1) == QLatin1Char('-') || text.at(eLast+1).isDigit()))
5837  ++eLast;
5838  if (eLast > ePos) // only if also to right of 'e' is a digit/+/- interpret it as beautifiable power
5839  useBeautifulPowers = true;
5840  }
5841  }
5842 
5843  // calculate text bounding rects and do string preparation for beautiful decimal powers:
5844  result.baseFont = font;
5845  if (result.baseFont.pointSizeF() > 0) // might return -1 if specified with setPixelSize, in that case we can't do correction in next line
5846  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
5847 
5848  QFontMetrics baseFontMetrics(result.baseFont);
5849  if (useBeautifulPowers)
5850  {
5851  // split text into parts of number/symbol that will be drawn normally and part that will be drawn as exponent:
5852  result.basePart = text.left(ePos);
5853  result.suffixPart = text.mid(eLast+1); // also drawn normally but after exponent
5854  // in log scaling, we want to turn "1*10^n" into "10^n", else add multiplication sign and decimal base:
5855  if (mAbbreviateDecimalPowers && result.basePart == QLatin1String("1"))
5856  result.basePart = QLatin1String("10");
5857  else
5858  result.basePart += QString(mMultiplicationSymbol) + QLatin1String("10");
5859  result.expPart = text.mid(ePos+1, eLast-ePos);
5860  // clip "+" and leading zeros off expPart:
5861  while (result.expPart.length() > 2 && result.expPart.at(1) == QLatin1Char('0')) // length > 2 so we leave one zero when numberFormatChar is 'e'
5862  result.expPart.remove(1, 1);
5863  if (!result.expPart.isEmpty() && result.expPart.at(0) == QLatin1Char('+'))
5864  result.expPart.remove(0, 1);
5865  // prepare smaller font for exponent:
5866  result.expFont = font;
5867  if (result.expFont.pointSize() > 0)
5868  result.expFont.setPointSize(result.expFont.pointSize()*0.75);
5869  else
5870  result.expFont.setPixelSize(result.expFont.pixelSize()*0.75);
5871  // calculate bounding rects of base part(s), exponent part and total one:
5872  result.baseBounds = baseFontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.basePart);
5873  result.expBounds = QFontMetrics(result.expFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.expPart);
5874  if (!result.suffixPart.isEmpty())
5875  result.suffixBounds = QFontMetrics(result.baseFont).boundingRect(0, 0, 0, 0, Qt::TextDontClip, result.suffixPart);
5876  result.totalBounds = result.baseBounds.adjusted(0, 0, result.expBounds.width()+result.suffixBounds.width()+2, 0); // +2 consists of the 1 pixel spacing between base and exponent (see drawTickLabel) and an extra pixel to include AA
5877  } else // useBeautifulPowers == false
5878  {
5879  result.basePart = text;
5880  result.totalBounds = baseFontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter, result.basePart);
5881  }
5882  result.totalBounds.moveTopLeft(QPoint(0, 0));
5883  applyAnchorTransform(result);
5884  result.rotatedTotalBounds = result.transform.mapRect(result.totalBounds);
5885 
5886  return result;
5887 }
5888 
5889 void QCPLabelPainterPrivate::applyAnchorTransform(LabelData &labelData) const
5890 {
5891  if (!qFuzzyIsNull(labelData.rotation))
5892  labelData.transform.rotate(labelData.rotation); // rotates effectively clockwise (due to flipped y axis of painter vs widget coordinate system)
5893 
5894  // from now on we translate in rotated label-local coordinate system.
5895  // shift origin of coordinate system to appropriate point on label:
5896  labelData.transform.translate(0, -labelData.totalBounds.height()+mLetterDescent+mLetterCapHeight); // shifts origin to true top of capital (or number) characters
5897 
5898  if (labelData.side == asLeft || labelData.side == asRight) // anchor is centered vertically
5899  labelData.transform.translate(0, -mLetterCapHeight/2.0);
5900  else if (labelData.side == asTop || labelData.side == asBottom) // anchor is centered horizontally
5901  labelData.transform.translate(-labelData.totalBounds.width()/2.0, 0);
5902 
5903  if (labelData.side == asTopRight || labelData.side == asRight || labelData.side == asBottomRight) // anchor is at right
5904  labelData.transform.translate(-labelData.totalBounds.width(), 0);
5905  if (labelData.side == asBottomLeft || labelData.side == asBottom || labelData.side == asBottomRight) // anchor is at bottom (no elseif!)
5906  labelData.transform.translate(0, -mLetterCapHeight);
5907 }
5908 
5909 /*! \internal
5910 
5911  Simulates the steps done by \ref placeTickLabel by calculating bounding boxes of the text label
5912  to be drawn, depending on number format etc. Since only the largest tick label is wanted for the
5913  margin calculation, the passed \a tickLabelsSize is only expanded, if it's currently set to a
5914  smaller width/height.
5915 */
5916 /*
5917 void QCPLabelPainterPrivate::getMaxTickLabelSize(const QFont &font, const QString &text, QSize *tickLabelsSize) const
5918 {
5919  // note: this function must return the same tick label sizes as the placeTickLabel function.
5920  QSize finalSize;
5921  if (mParentPlot->plottingHints().testFlag(QCP::phCacheLabels) && mLabelCache.contains(text)) // label caching enabled and have cached label
5922  {
5923  const CachedLabel *cachedLabel = mLabelCache.object(text);
5924  finalSize = cachedLabel->pixmap.size()/mParentPlot->bufferDevicePixelRatio();
5925  } else // label caching disabled or no label with this text cached:
5926  {
5927  // TODO: LabelData labelData = getTickLabelData(font, text);
5928  // TODO: finalSize = labelData.rotatedTotalBounds.size();
5929  }
5930 
5931  // expand passed tickLabelsSize if current tick label is larger:
5932  if (finalSize.width() > tickLabelsSize->width())
5933  tickLabelsSize->setWidth(finalSize.width());
5934  if (finalSize.height() > tickLabelsSize->height())
5935  tickLabelsSize->setHeight(finalSize.height());
5936 }
5937 */
5938 
5939 QCPLabelPainterPrivate::CachedLabel *QCPLabelPainterPrivate::createCachedLabel(const LabelData &labelData) const
5940 {
5941  CachedLabel *result = new CachedLabel;
5942 
5943  // allocate pixmap with the correct size and pixel ratio:
5944  if (!qFuzzyCompare(1.0, mParentPlot->bufferDevicePixelRatio()))
5945  {
5946  result->pixmap = QPixmap(labelData.rotatedTotalBounds.size()*mParentPlot->bufferDevicePixelRatio());
5947 #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
5948 # ifdef QCP_DEVICEPIXELRATIO_FLOAT
5949  result->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatioF());
5950 # else
5951  result->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatio());
5952 # endif
5953 #endif
5954  } else
5955  result->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
5956  result->pixmap.fill(Qt::transparent);
5957 
5958  // draw the label into the pixmap
5959  // offset is between label anchor and topleft of cache pixmap, so pixmap can be drawn at pos+offset to make the label anchor appear at pos.
5960  // We use rotatedTotalBounds.topLeft() because rotatedTotalBounds is in a coordinate system where the label anchor is at (0, 0)
5961  result->offset = labelData.rotatedTotalBounds.topLeft();
5962  QCPPainter cachePainter(&result->pixmap);
5963  drawText(&cachePainter, -result->offset, labelData);
5964  return result;
5965 }
5966 
5967 QByteArray QCPLabelPainterPrivate::cacheKey(const