qwt_plot_layout.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_plot_layout.h"
11 #include "qwt_text.h"
12 #include "qwt_text_label.h"
13 #include "qwt_scale_widget.h"
14 #include "qwt_abstract_legend.h"
15 #include "qwt_math.h"
16 
17 #include <qmargins.h>
18 
20 {
21 public:
22  void init( const QwtPlot *, const QRectF &rect );
23 
24  struct t_legendData
25  {
29  QSize hint;
30  } legend;
31 
32  struct t_titleData
33  {
36  } title;
37 
38  struct t_footerData
39  {
42  } footer;
43 
44  struct t_scaleData
45  {
46  bool isEnabled;
48  QFont scaleFont;
49  int start;
50  int end;
52  double tickOffset;
55 
56  struct t_canvasData
57  {
58  int contentsMargins[ QwtPlot::axisCnt ];
59 
60  } canvas;
61 };
62 
63 /*
64  Extract all layout relevant data from the plot components
65 */
66 void QwtPlotLayout::LayoutData::init( const QwtPlot *plot, const QRectF &rect )
67 {
68  // legend
69 
70  if ( plot->legend() )
71  {
72  legend.frameWidth = plot->legend()->frameWidth();
74  plot->legend()->scrollExtent( Qt::Horizontal );
76  plot->legend()->scrollExtent( Qt::Vertical );
77 
78  const QSize hint = plot->legend()->sizeHint();
79 
80  const int w = qMin( hint.width(), qwtFloor( rect.width() ) );
81 
82  int h = plot->legend()->heightForWidth( w );
83  if ( h <= 0 )
84  h = hint.height();
85 
86  legend.hint = QSize( w, h );
87  }
88 
89  // title
90 
91  title.frameWidth = 0;
92  title.text = QwtText();
93 
94  if ( plot->titleLabel() )
95  {
96  const QwtTextLabel *label = plot->titleLabel();
97  title.text = label->text();
99  title.text.setFont( label->font() );
100 
101  title.frameWidth = plot->titleLabel()->frameWidth();
102  }
103 
104  // footer
105 
106  footer.frameWidth = 0;
107  footer.text = QwtText();
108 
109  if ( plot->footerLabel() )
110  {
111  const QwtTextLabel *label = plot->footerLabel();
112  footer.text = label->text();
114  footer.text.setFont( label->font() );
115 
116  footer.frameWidth = plot->footerLabel()->frameWidth();
117  }
118 
119  // scales
120 
121  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
122  {
123  if ( plot->axisEnabled( axis ) )
124  {
125  const QwtScaleWidget *scaleWidget = plot->axisWidget( axis );
126 
127  scale[axis].isEnabled = true;
128 
129  scale[axis].scaleWidget = scaleWidget;
130 
131  scale[axis].scaleFont = scaleWidget->font();
132 
133  scale[axis].start = scaleWidget->startBorderDist();
134  scale[axis].end = scaleWidget->endBorderDist();
135 
136  scale[axis].baseLineOffset = scaleWidget->margin();
137  scale[axis].tickOffset = scaleWidget->margin();
138  if ( scaleWidget->scaleDraw()->hasComponent(
140  {
141  scale[axis].tickOffset +=
142  scaleWidget->scaleDraw()->maxTickLength();
143  }
144 
145  scale[axis].dimWithoutTitle = scaleWidget->dimForLength(
146  QWIDGETSIZE_MAX, scale[axis].scaleFont );
147 
148  if ( !scaleWidget->title().isEmpty() )
149  {
150  scale[axis].dimWithoutTitle -=
151  scaleWidget->titleHeightForWidth( QWIDGETSIZE_MAX );
152  }
153  }
154  else
155  {
156  scale[axis].isEnabled = false;
157  scale[axis].start = 0;
158  scale[axis].end = 0;
159  scale[axis].baseLineOffset = 0;
160  scale[axis].tickOffset = 0.0;
161  scale[axis].dimWithoutTitle = 0;
162  }
163  }
164 
165  // canvas
166 
167  const QMargins m = plot->canvas()->contentsMargins();
168 
169  canvas.contentsMargins[ QwtPlot::yLeft ] = m.left();
170  canvas.contentsMargins[ QwtPlot::xTop ] = m.top();
171  canvas.contentsMargins[ QwtPlot::yRight ] = m.right();
172  canvas.contentsMargins[ QwtPlot::xBottom ] = m.bottom();
173 }
174 
176 {
177 public:
179  spacing( 5 )
180  {
181  }
182 
183  QRectF titleRect;
184  QRectF footerRect;
185  QRectF legendRect;
187  QRectF canvasRect;
188 
190 
192  double legendRatio;
193  unsigned int spacing;
195  bool alignCanvasToScales[QwtPlot::axisCnt];
196 };
197 
203 {
204  d_data = new PrivateData;
205 
207  setCanvasMargin( 4 );
208  setAlignCanvasToScales( false );
209 
210  invalidate();
211 }
212 
215 {
216  delete d_data;
217 }
218 
232 void QwtPlotLayout::setCanvasMargin( int margin, int axis )
233 {
234  if ( margin < -1 )
235  margin = -1;
236 
237  if ( axis == -1 )
238  {
239  for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
240  d_data->canvasMargin[axis] = margin;
241  }
242  else if ( axis >= 0 && axis < QwtPlot::axisCnt )
243  d_data->canvasMargin[axis] = margin;
244 }
245 
251 int QwtPlotLayout::canvasMargin( int axisId ) const
252 {
253  if ( axisId < 0 || axisId >= QwtPlot::axisCnt )
254  return 0;
255 
256  return d_data->canvasMargin[axisId];
257 }
258 
266 {
267  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
268  d_data->alignCanvasToScales[axis] = on;
269 }
270 
288 void QwtPlotLayout::setAlignCanvasToScale( int axisId, bool on )
289 {
290  if ( axisId >= 0 && axisId < QwtPlot::axisCnt )
291  d_data->alignCanvasToScales[axisId] = on;
292 }
293 
303 bool QwtPlotLayout::alignCanvasToScale( int axisId ) const
304 {
305  if ( axisId < 0 || axisId >= QwtPlot::axisCnt )
306  return false;
307 
308  return d_data->alignCanvasToScales[ axisId ];
309 }
310 
319 {
320  d_data->spacing = qMax( 0, spacing );
321 }
322 
328 {
329  return d_data->spacing;
330 }
331 
346 {
347  if ( ratio > 1.0 )
348  ratio = 1.0;
349 
350  switch ( pos )
351  {
352  case QwtPlot::TopLegend:
354  {
355  if ( ratio <= 0.0 )
356  ratio = 0.33;
357  d_data->legendRatio = ratio;
358  d_data->legendPos = pos;
359  break;
360  }
361  case QwtPlot::LeftLegend:
363  {
364  if ( ratio <= 0.0 )
365  ratio = 0.5;
366  d_data->legendRatio = ratio;
367  d_data->legendPos = pos;
368  break;
369  }
370  default:
371  break;
372  }
373 }
374 
384 {
385  setLegendPosition( pos, 0.0 );
386 }
387 
394 {
395  return d_data->legendPos;
396 }
397 
407 void QwtPlotLayout::setLegendRatio( double ratio )
408 {
409  setLegendPosition( legendPosition(), ratio );
410 }
411 
417 {
418  return d_data->legendRatio;
419 }
420 
429 void QwtPlotLayout::setTitleRect( const QRectF &rect )
430 {
431  d_data->titleRect = rect;
432 }
433 
439 {
440  return d_data->titleRect;
441 }
442 
451 void QwtPlotLayout::setFooterRect( const QRectF &rect )
452 {
453  d_data->footerRect = rect;
454 }
455 
461 {
462  return d_data->footerRect;
463 }
464 
475 void QwtPlotLayout::setLegendRect( const QRectF &rect )
476 {
477  d_data->legendRect = rect;
478 }
479 
485 {
486  return d_data->legendRect;
487 }
488 
500 void QwtPlotLayout::setScaleRect( int axis, const QRectF &rect )
501 {
502  if ( axis >= 0 && axis < QwtPlot::axisCnt )
503  d_data->scaleRect[axis] = rect;
504 }
505 
511 QRectF QwtPlotLayout::scaleRect( int axis ) const
512 {
513  if ( axis < 0 || axis >= QwtPlot::axisCnt )
514  {
515  static QRectF dummyRect;
516  return dummyRect;
517  }
518  return d_data->scaleRect[axis];
519 }
520 
529 void QwtPlotLayout::setCanvasRect( const QRectF &rect )
530 {
531  d_data->canvasRect = rect;
532 }
533 
539 {
540  return d_data->canvasRect;
541 }
542 
548 {
550  = d_data->legendRect = d_data->canvasRect = QRect();
551 
552  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
553  d_data->scaleRect[axis] = QRect();
554 }
555 
562 QSize QwtPlotLayout::minimumSizeHint( const QwtPlot *plot ) const
563 {
564  class ScaleData
565  {
566  public:
567  ScaleData()
568  {
569  w = h = minLeft = minRight = tickOffset = 0;
570  }
571 
572  int w;
573  int h;
574  int minLeft;
575  int minRight;
576  int tickOffset;
577  } scaleData[QwtPlot::axisCnt];
578 
579  int canvasBorder[QwtPlot::axisCnt];
580 
581  const int fw = plot->canvas()->contentsMargins().left();
582 
583  int axis;
584  for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
585  {
586  if ( plot->axisEnabled( axis ) )
587  {
588  const QwtScaleWidget *scl = plot->axisWidget( axis );
589  ScaleData &sd = scaleData[axis];
590 
591  const QSize hint = scl->minimumSizeHint();
592  sd.w = hint.width();
593  sd.h = hint.height();
594  scl->getBorderDistHint( sd.minLeft, sd.minRight );
595  sd.tickOffset = scl->margin();
597  sd.tickOffset += qwtCeil( scl->scaleDraw()->maxTickLength() );
598  }
599 
600  canvasBorder[axis] = fw + d_data->canvasMargin[axis] + 1;
601  }
602 
603 
604  for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
605  {
606  ScaleData &sd = scaleData[axis];
607  if ( sd.w && ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) )
608  {
609  if ( ( sd.minLeft > canvasBorder[QwtPlot::yLeft] )
610  && scaleData[QwtPlot::yLeft].w )
611  {
612  int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft];
613  if ( shiftLeft > scaleData[QwtPlot::yLeft].w )
614  shiftLeft = scaleData[QwtPlot::yLeft].w;
615 
616  sd.w -= shiftLeft;
617  }
618  if ( ( sd.minRight > canvasBorder[QwtPlot::yRight] )
619  && scaleData[QwtPlot::yRight].w )
620  {
621  int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight];
622  if ( shiftRight > scaleData[QwtPlot::yRight].w )
623  shiftRight = scaleData[QwtPlot::yRight].w;
624 
625  sd.w -= shiftRight;
626  }
627  }
628 
629  if ( sd.h && ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) )
630  {
631  if ( ( sd.minLeft > canvasBorder[QwtPlot::xBottom] ) &&
632  scaleData[QwtPlot::xBottom].h )
633  {
634  int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom];
635  if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset )
636  shiftBottom = scaleData[QwtPlot::xBottom].tickOffset;
637 
638  sd.h -= shiftBottom;
639  }
640  if ( ( sd.minLeft > canvasBorder[QwtPlot::xTop] ) &&
641  scaleData[QwtPlot::xTop].h )
642  {
643  int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop];
644  if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset )
645  shiftTop = scaleData[QwtPlot::xTop].tickOffset;
646 
647  sd.h -= shiftTop;
648  }
649  }
650  }
651 
652  const QWidget *canvas = plot->canvas();
653 
654  const QMargins m = canvas->contentsMargins();
655 
656  const QSize minCanvasSize = canvas->minimumSize();
657 
658  int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w;
659  int cw = qMax( scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w )
660  + m.left() + 1 + m.right() + 1;
661  w += qMax( cw, minCanvasSize.width() );
662 
663  int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h;
664  int ch = qMax( scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h )
665  + m.top() + 1 + m.bottom() + 1;
666  h += qMax( ch, minCanvasSize.height() );
667 
668  const QwtTextLabel *labels[2];
669  labels[0] = plot->titleLabel();
670  labels[1] = plot->footerLabel();
671 
672  for ( int i = 0; i < 2; i++ )
673  {
674  const QwtTextLabel *label = labels[i];
675  if ( label && !label->text().isEmpty() )
676  {
677  // If only QwtPlot::yLeft or QwtPlot::yRight is showing,
678  // we center on the plot canvas.
679  const bool centerOnCanvas = !( plot->axisEnabled( QwtPlot::yLeft )
680  && plot->axisEnabled( QwtPlot::yRight ) );
681 
682  int labelW = w;
683  if ( centerOnCanvas )
684  {
685  labelW -= scaleData[QwtPlot::yLeft].w
686  + scaleData[QwtPlot::yRight].w;
687  }
688 
689  int labelH = label->heightForWidth( labelW );
690  if ( labelH > labelW ) // Compensate for a long title
691  {
692  w = labelW = labelH;
693  if ( centerOnCanvas )
694  {
695  w += scaleData[QwtPlot::yLeft].w
696  + scaleData[QwtPlot::yRight].w;
697  }
698 
699  labelH = label->heightForWidth( labelW );
700  }
701  h += labelH + d_data->spacing;
702  }
703  }
704 
705  // Compute the legend contribution
706 
707  const QwtAbstractLegend *legend = plot->legend();
708  if ( legend && !legend->isEmpty() )
709  {
712  {
713  int legendW = legend->sizeHint().width();
714  int legendH = legend->heightForWidth( legendW );
715 
716  if ( legend->frameWidth() > 0 )
717  w += d_data->spacing;
718 
719  if ( legendH > h )
720  legendW += legend->scrollExtent( Qt::Horizontal );
721 
722  if ( d_data->legendRatio < 1.0 )
723  legendW = qMin( legendW, int( w / ( 1.0 - d_data->legendRatio ) ) );
724 
725  w += legendW + d_data->spacing;
726  }
727  else
728  {
729  int legendW = qMin( legend->sizeHint().width(), w );
730  int legendH = legend->heightForWidth( legendW );
731 
732  if ( legend->frameWidth() > 0 )
733  h += d_data->spacing;
734 
735  if ( d_data->legendRatio < 1.0 )
736  legendH = qMin( legendH, int( h / ( 1.0 - d_data->legendRatio ) ) );
737 
738  h += legendH + d_data->spacing;
739  }
740  }
741 
742  return QSize( w, h );
743 }
744 
755  const QRectF &rect ) const
756 {
757  const QSize hint( d_data->layoutData.legend.hint );
758 
759  int dim;
762  {
763  // We don't allow vertical legends to take more than
764  // half of the available space.
765 
766  dim = qMin( hint.width(), int( rect.width() * d_data->legendRatio ) );
767 
768  if ( !( options & IgnoreScrollbars ) )
769  {
770  if ( hint.height() > rect.height() )
771  {
772  // The legend will need additional
773  // space for the vertical scrollbar.
774 
776  }
777  }
778  }
779  else
780  {
781  dim = qMin( hint.height(), int( rect.height() * d_data->legendRatio ) );
782  dim = qMax( dim, d_data->layoutData.legend.vScrollExtent );
783  }
784 
785  QRectF legendRect = rect;
786  switch ( d_data->legendPos )
787  {
788  case QwtPlot::LeftLegend:
789  legendRect.setWidth( dim );
790  break;
792  legendRect.setX( rect.right() - dim );
793  legendRect.setWidth( dim );
794  break;
795  case QwtPlot::TopLegend:
796  legendRect.setHeight( dim );
797  break;
799  legendRect.setY( rect.bottom() - dim );
800  legendRect.setHeight( dim );
801  break;
802  }
803 
804  return legendRect;
805 }
806 
816  const QRectF &legendRect ) const
817 {
818  QRectF alignedRect = legendRect;
819 
822  {
823  if ( d_data->layoutData.legend.hint.width() < canvasRect.width() )
824  {
825  alignedRect.setX( canvasRect.x() );
826  alignedRect.setWidth( canvasRect.width() );
827  }
828  }
829  else
830  {
831  if ( d_data->layoutData.legend.hint.height() < canvasRect.height() )
832  {
833  alignedRect.setY( canvasRect.y() );
834  alignedRect.setHeight( canvasRect.height() );
835  }
836  }
837 
838  return alignedRect;
839 }
840 
854  int &dimTitle, int &dimFooter, int dimAxis[QwtPlot::axisCnt] ) const
855 {
856  dimTitle = dimFooter = 0;
857  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
858  dimAxis[axis] = 0;
859 
860  int backboneOffset[QwtPlot::axisCnt];
861  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
862  {
863  backboneOffset[axis] = 0;
864  if ( !( options & IgnoreFrames ) )
865  backboneOffset[axis] += d_data->layoutData.canvas.contentsMargins[ axis ];
866 
867  if ( !d_data->alignCanvasToScales[axis] )
868  backboneOffset[axis] += d_data->canvasMargin[axis];
869  }
870 
871  bool done = false;
872  while ( !done )
873  {
874  done = true;
875 
876  // the size for the 4 axis depend on each other. Expanding
877  // the height of a horizontal axis will shrink the height
878  // for the vertical axis, shrinking the height of a vertical
879  // axis will result in a line break what will expand the
880  // width and results in shrinking the width of a horizontal
881  // axis what might result in a line break of a horizontal
882  // axis ... . So we loop as long until no size changes.
883 
884  if ( !( ( options & IgnoreTitle ) ||
886  {
887  double w = rect.width();
888 
891  {
892  // center to the canvas
893  w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
894  }
895 
897  if ( !( options & IgnoreFrames ) )
898  d += 2 * d_data->layoutData.title.frameWidth;
899 
900  if ( d > dimTitle )
901  {
902  dimTitle = d;
903  done = false;
904  }
905  }
906 
907  if ( !( ( options & IgnoreFooter ) ||
909  {
910  double w = rect.width();
911 
914  {
915  // center to the canvas
916  w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
917  }
918 
920  if ( !( options & IgnoreFrames ) )
922 
923  if ( d > dimFooter )
924  {
925  dimFooter = d;
926  done = false;
927  }
928  }
929 
930  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
931  {
932  const struct LayoutData::t_scaleData &scaleData =
933  d_data->layoutData.scale[axis];
934 
935  if ( scaleData.isEnabled )
936  {
937  double length;
938  if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
939  {
940  length = rect.width() - dimAxis[QwtPlot::yLeft]
941  - dimAxis[QwtPlot::yRight];
942  length -= scaleData.start + scaleData.end;
943 
944  if ( dimAxis[QwtPlot::yRight] > 0 )
945  length -= 1;
946 
947  length += qMin( dimAxis[QwtPlot::yLeft],
948  scaleData.start - backboneOffset[QwtPlot::yLeft] );
949  length += qMin( dimAxis[QwtPlot::yRight],
950  scaleData.end - backboneOffset[QwtPlot::yRight] );
951  }
952  else // QwtPlot::yLeft, QwtPlot::yRight
953  {
954  length = rect.height() - dimAxis[QwtPlot::xTop]
955  - dimAxis[QwtPlot::xBottom];
956  length -= scaleData.start + scaleData.end;
957  length -= 1;
958 
959  if ( dimAxis[QwtPlot::xBottom] <= 0 )
960  length -= 1;
961  if ( dimAxis[QwtPlot::xTop] <= 0 )
962  length -= 1;
963 
964  if ( dimAxis[QwtPlot::xBottom] > 0 )
965  {
966  length += qMin(
968  double( scaleData.start - backboneOffset[QwtPlot::xBottom] ) );
969  }
970  if ( dimAxis[QwtPlot::xTop] > 0 )
971  {
972  length += qMin(
974  double( scaleData.end - backboneOffset[QwtPlot::xTop] ) );
975  }
976 
977  if ( dimTitle > 0 )
978  length -= dimTitle + d_data->spacing;
979  }
980 
981  int d = scaleData.dimWithoutTitle;
982  if ( !scaleData.scaleWidget->title().isEmpty() )
983  {
984  d += scaleData.scaleWidget->titleHeightForWidth( qwtFloor( length ) );
985  }
986 
987 
988  if ( d > dimAxis[axis] )
989  {
990  dimAxis[axis] = d;
991  done = false;
992  }
993  }
994  }
995  }
996 }
997 
1010  QRectF &canvasRect, QRectF scaleRect[QwtPlot::axisCnt] ) const
1011 {
1012  int backboneOffset[QwtPlot::axisCnt];
1013  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
1014  {
1015  backboneOffset[axis] = 0;
1016 
1017  if ( !d_data->alignCanvasToScales[axis] )
1018  {
1019  backboneOffset[axis] += d_data->canvasMargin[axis];
1020  }
1021 
1022  if ( !( options & IgnoreFrames ) )
1023  {
1024  backboneOffset[axis] +=
1026  }
1027  }
1028 
1029  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
1030  {
1031  if ( !scaleRect[axis].isValid() )
1032  continue;
1033 
1034  const int startDist = d_data->layoutData.scale[axis].start;
1035  const int endDist = d_data->layoutData.scale[axis].end;
1036 
1037  QRectF &axisRect = scaleRect[axis];
1038 
1039  if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
1040  {
1041  const QRectF &leftScaleRect = scaleRect[QwtPlot::yLeft];
1042  const int leftOffset =
1043  backboneOffset[QwtPlot::yLeft] - startDist;
1044 
1045  if ( leftScaleRect.isValid() )
1046  {
1047  const double dx = leftOffset + leftScaleRect.width();
1048  if ( d_data->alignCanvasToScales[QwtPlot::yLeft] && dx < 0.0 )
1049  {
1050  /*
1051  The axis needs more space than the width
1052  of the left scale.
1053  */
1054  const double cLeft = canvasRect.left(); // qreal -> double
1055  canvasRect.setLeft( qwtMaxF( cLeft, axisRect.left() - dx ) );
1056  }
1057  else
1058  {
1059  const double minLeft = leftScaleRect.left();
1060  const double left = axisRect.left() + leftOffset;
1061  axisRect.setLeft( qwtMaxF( left, minLeft ) );
1062  }
1063  }
1064  else
1065  {
1066  if ( d_data->alignCanvasToScales[QwtPlot::yLeft] && leftOffset < 0 )
1067  {
1068  canvasRect.setLeft( qwtMaxF( canvasRect.left(),
1069  axisRect.left() - leftOffset ) );
1070  }
1071  else
1072  {
1073  if ( leftOffset > 0 )
1074  axisRect.setLeft( axisRect.left() + leftOffset );
1075  }
1076  }
1077 
1078  const QRectF &rightScaleRect = scaleRect[QwtPlot::yRight];
1079  const int rightOffset =
1080  backboneOffset[QwtPlot::yRight] - endDist + 1;
1081 
1082  if ( rightScaleRect.isValid() )
1083  {
1084  const double dx = rightOffset + rightScaleRect.width();
1085  if ( d_data->alignCanvasToScales[QwtPlot::yRight] && dx < 0 )
1086  {
1087  /*
1088  The axis needs more space than the width
1089  of the right scale.
1090  */
1091  const double cRight = canvasRect.right(); // qreal -> double
1092  canvasRect.setRight( qwtMinF( cRight, axisRect.right() + dx ) );
1093  }
1094 
1095  const double maxRight = rightScaleRect.right();
1096  const double right = axisRect.right() - rightOffset;
1097  axisRect.setRight( qwtMinF( right, maxRight ) );
1098  }
1099  else
1100  {
1101  if ( d_data->alignCanvasToScales[QwtPlot::yRight] && rightOffset < 0 )
1102  {
1103  canvasRect.setRight( qwtMinF( canvasRect.right(),
1104  axisRect.right() + rightOffset ) );
1105  }
1106  else
1107  {
1108  if ( rightOffset > 0 )
1109  axisRect.setRight( axisRect.right() - rightOffset );
1110  }
1111  }
1112  }
1113  else // QwtPlot::yLeft, QwtPlot::yRight
1114  {
1115  const QRectF &bottomScaleRect = scaleRect[QwtPlot::xBottom];
1116  const int bottomOffset =
1117  backboneOffset[QwtPlot::xBottom] - endDist + 1;
1118 
1119  if ( bottomScaleRect.isValid() )
1120  {
1121  const double dy = bottomOffset + bottomScaleRect.height();
1122  if ( d_data->alignCanvasToScales[QwtPlot::xBottom] && dy < 0 )
1123  {
1124  /*
1125  The axis needs more space than the height
1126  of the bottom scale.
1127  */
1128  const double cBottom = canvasRect.bottom(); // qreal -> double
1129  canvasRect.setBottom( qwtMinF( cBottom, axisRect.bottom() + dy ) );
1130  }
1131  else
1132  {
1133  const double maxBottom = bottomScaleRect.top() +
1135  const double bottom = axisRect.bottom() - bottomOffset;
1136  axisRect.setBottom( qwtMinF( bottom, maxBottom ) );
1137  }
1138  }
1139  else
1140  {
1141  if ( d_data->alignCanvasToScales[QwtPlot::xBottom] && bottomOffset < 0 )
1142  {
1143  canvasRect.setBottom( qwtMinF( canvasRect.bottom(),
1144  axisRect.bottom() + bottomOffset ) );
1145  }
1146  else
1147  {
1148  if ( bottomOffset > 0 )
1149  axisRect.setBottom( axisRect.bottom() - bottomOffset );
1150  }
1151  }
1152 
1153  const QRectF &topScaleRect = scaleRect[QwtPlot::xTop];
1154  const int topOffset = backboneOffset[QwtPlot::xTop] - startDist;
1155 
1156  if ( topScaleRect.isValid() )
1157  {
1158  const double dy = topOffset + topScaleRect.height();
1159  if ( d_data->alignCanvasToScales[QwtPlot::xTop] && dy < 0 )
1160  {
1161  /*
1162  The axis needs more space than the height
1163  of the top scale.
1164  */
1165  const double cTop = canvasRect.top(); // qreal -> double
1166  canvasRect.setTop( qwtMaxF( cTop, axisRect.top() - dy ) );
1167  }
1168  else
1169  {
1170  const double minTop = topScaleRect.bottom() -
1172  const double top = axisRect.top() + topOffset;
1173  axisRect.setTop( qwtMaxF( top, minTop ) );
1174  }
1175  }
1176  else
1177  {
1178  if ( d_data->alignCanvasToScales[QwtPlot::xTop] && topOffset < 0 )
1179  {
1180  canvasRect.setTop( qwtMaxF( canvasRect.top(),
1181  axisRect.top() - topOffset ) );
1182  }
1183  else
1184  {
1185  if ( topOffset > 0 )
1186  axisRect.setTop( axisRect.top() + topOffset );
1187  }
1188  }
1189  }
1190  }
1191 
1192  /*
1193  The canvas has been aligned to the scale with largest
1194  border distances. Now we have to realign the other scale.
1195  */
1196 
1197 
1198  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
1199  {
1200  QRectF &sRect = scaleRect[axis];
1201 
1202  if ( !sRect.isValid() )
1203  continue;
1204 
1205  if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop )
1206  {
1208  {
1209  double y = canvasRect.left() - d_data->layoutData.scale[axis].start;
1210  if ( !( options & IgnoreFrames ) )
1212 
1213  sRect.setLeft( y );
1214  }
1216  {
1217  double y = canvasRect.right() - 1 + d_data->layoutData.scale[axis].end;
1218  if ( !( options & IgnoreFrames ) )
1220 
1221  sRect.setRight( y );
1222  }
1223 
1224  if ( d_data->alignCanvasToScales[ axis ] )
1225  {
1226  if ( axis == QwtPlot::xTop )
1227  sRect.setBottom( canvasRect.top() );
1228  else
1229  sRect.setTop( canvasRect.bottom() );
1230  }
1231  }
1232  else
1233  {
1235  {
1236  double x = canvasRect.top() - d_data->layoutData.scale[axis].start;
1237  if ( !( options & IgnoreFrames ) )
1239 
1240  sRect.setTop( x );
1241  }
1243  {
1244  double x = canvasRect.bottom() - 1 + d_data->layoutData.scale[axis].end;
1245  if ( !( options & IgnoreFrames ) )
1247 
1248  sRect.setBottom( x );
1249  }
1250 
1251  if ( d_data->alignCanvasToScales[ axis ] )
1252  {
1253  if ( axis == QwtPlot::yLeft )
1254  sRect.setRight( canvasRect.left() );
1255  else
1256  sRect.setLeft( canvasRect.right() );
1257  }
1258  }
1259  }
1260 }
1261 
1273  const QRectF &plotRect, Options options )
1274 {
1275  invalidate();
1276 
1277  QRectF rect( plotRect ); // undistributed rest of the plot rect
1278 
1279  // We extract all layout relevant parameters from the widgets,
1280  // and save them to d_data->layoutData.
1281 
1282  d_data->layoutData.init( plot, rect );
1283 
1284  if ( !( options & IgnoreLegend )
1285  && plot->legend() && !plot->legend()->isEmpty() )
1286  {
1287  d_data->legendRect = layoutLegend( options, rect );
1288 
1289  // subtract d_data->legendRect from rect
1290 
1291  const QRegion region( rect.toRect() );
1292  rect = region.subtracted( d_data->legendRect.toRect() ).boundingRect();
1293 
1294  switch ( d_data->legendPos )
1295  {
1296  case QwtPlot::LeftLegend:
1297  {
1298  rect.setLeft( rect.left() + d_data->spacing );
1299  break;
1300  }
1301  case QwtPlot::RightLegend:
1302  {
1303  rect.setRight( rect.right() - d_data->spacing );
1304  break;
1305  }
1306  case QwtPlot::TopLegend:
1307  {
1308  rect.setTop( rect.top() + d_data->spacing );
1309  break;
1310  }
1311  case QwtPlot::BottomLegend:
1312  {
1313  rect.setBottom( rect.bottom() - d_data->spacing );
1314  break;
1315  }
1316  }
1317  }
1318 
1319  /*
1320  +---+-----------+---+
1321  | Title |
1322  +---+-----------+---+
1323  | | Axis | |
1324  +---+-----------+---+
1325  | A | | A |
1326  | x | Canvas | x |
1327  | i | | i |
1328  | s | | s |
1329  +---+-----------+---+
1330  | | Axis | |
1331  +---+-----------+---+
1332  | Footer |
1333  +---+-----------+---+
1334  */
1335 
1336  // title, footer and axes include text labels. The height of each
1337  // label depends on its line breaks, that depend on the width
1338  // for the label. A line break in a horizontal text will reduce
1339  // the available width for vertical texts and vice versa.
1340  // expandLineBreaks finds the height/width for title, footer and axes
1341  // including all line breaks.
1342 
1343  int dimTitle, dimFooter, dimAxes[QwtPlot::axisCnt];
1344  expandLineBreaks( options, rect, dimTitle, dimFooter, dimAxes );
1345 
1346  if ( dimTitle > 0 )
1347  {
1348  d_data->titleRect.setRect(
1349  rect.left(), rect.top(), rect.width(), dimTitle );
1350 
1351  rect.setTop( d_data->titleRect.bottom() + d_data->spacing );
1352 
1355  {
1356  // if only one of the y axes is missing we align
1357  // the title centered to the canvas
1358 
1359  d_data->titleRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] );
1360  d_data->titleRect.setWidth( rect.width()
1361  - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] );
1362  }
1363  }
1364 
1365  if ( dimFooter > 0 )
1366  {
1367  d_data->footerRect.setRect(
1368  rect.left(), rect.bottom() - dimFooter, rect.width(), dimFooter );
1369 
1370  rect.setBottom( d_data->footerRect.top() - d_data->spacing );
1371 
1374  {
1375  // if only one of the y axes is missing we align
1376  // the footer centered to the canvas
1377 
1378  d_data->footerRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] );
1379  d_data->footerRect.setWidth( rect.width()
1380  - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] );
1381  }
1382  }
1383 
1384  d_data->canvasRect.setRect(
1385  rect.x() + dimAxes[QwtPlot::yLeft],
1386  rect.y() + dimAxes[QwtPlot::xTop],
1387  rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
1388  rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop] );
1389 
1390  for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
1391  {
1392  // set the rects for the axes
1393 
1394  if ( dimAxes[axis] )
1395  {
1396  int dim = dimAxes[axis];
1397  QRectF &scaleRect = d_data->scaleRect[axis];
1398 
1399  scaleRect = d_data->canvasRect;
1400  switch ( axis )
1401  {
1402  case QwtPlot::yLeft:
1403  {
1404  scaleRect.setX( d_data->canvasRect.left() - dim );
1405  scaleRect.setWidth( dim );
1406  break;
1407  }
1408  case QwtPlot::yRight:
1409  {
1410  scaleRect.setX( d_data->canvasRect.right() );
1411  scaleRect.setWidth( dim );
1412  break;
1413  }
1414  case QwtPlot::xBottom:
1415  {
1416  scaleRect.setY( d_data->canvasRect.bottom() );
1417  scaleRect.setHeight( dim );
1418  break;
1419  }
1420  case QwtPlot::xTop:
1421  {
1422  scaleRect.setY( d_data->canvasRect.top() - dim );
1423  scaleRect.setHeight( dim );
1424  break;
1425  }
1426  }
1427  scaleRect = scaleRect.normalized();
1428  }
1429  }
1430 
1431  // +---+-----------+---+
1432  // | <- Axis -> |
1433  // +-^-+-----------+-^-+
1434  // | | | | | |
1435  // | | | |
1436  // | A | | A |
1437  // | x | Canvas | x |
1438  // | i | | i |
1439  // | s | | s |
1440  // | | | |
1441  // | | | | | |
1442  // +-V-+-----------+-V-+
1443  // | <- Axis -> |
1444  // +---+-----------+---+
1445 
1446  // The ticks of the axes - not the labels above - should
1447  // be aligned to the canvas. So we try to use the empty
1448  // corners to extend the axes, so that the label texts
1449  // left/right of the min/max ticks are moved into them.
1450 
1451  alignScales( options, d_data->canvasRect, d_data->scaleRect );
1452 
1453  if ( !d_data->legendRect.isEmpty() )
1454  {
1455  // We prefer to align the legend to the canvas - not to
1456  // the complete plot - if possible.
1457 
1459  }
1460 }
QwtPlotLayout::LayoutData layoutData
QwtPlotLayout()
Constructor.
int canvasMargin(int axisId) const
virtual ~QwtPlotLayout()
Destructor.
LegendPosition
Definition: qwt_plot.h:117
X axis above the canvas.
Definition: qwt_plot.h:106
void setFont(const QFont &)
Definition: qwt_text.cpp:306
QRectF scaleRect[QwtPlot::axisCnt]
virtual void activate(const QwtPlot *, const QRectF &plotRect, Options options=Options())
Recalculate the geometry of all components.
lu_byte right
Definition: lparser.c:1229
void setLegendRect(const QRectF &)
Set the geometry for the legend.
A Widget which displays a QwtText.
QRectF legendRect() const
QwtTextLabel * titleLabel()
Definition: qwt_plot.cpp:354
double legendRatio() const
Number of axes.
Definition: qwt_plot.h:109
MQTTClient d
Definition: test10.c:1656
QRectF layoutLegend(Options options, const QRectF &) const
void setCanvasRect(const QRectF &)
Set the geometry for the canvas.
QWT_CONSTEXPR float qwtMaxF(float a, float b)
Definition: qwt_math.h:123
int margin() const
QRectF alignLegend(const QRectF &canvasRect, const QRectF &legendRect) const
lu_byte left
Definition: lparser.c:1228
struct QwtPlotLayout::LayoutData::t_legendData legend
QRectF footerRect() const
QwtPlot::LegendPosition legendPosition() const
Y axis right of the canvas.
Definition: qwt_plot.h:100
int titleHeightForWidth(int width) const
Find the height of the title for a given width.
const QwtText & text() const
Return the text.
void setCanvasMargin(int margin, int axis=-1)
virtual int heightForWidth(int) const QWT_OVERRIDE
QwtTextLabel * footerLabel()
Definition: qwt_plot.cpp:398
virtual QSize minimumSizeHint(const QwtPlot *) const
bool axisEnabled(int axisId) const
bool alignCanvasToScales[QwtPlot::axisCnt]
A 2-D plotting widget.
Definition: qwt_plot.h:75
const QwtScaleDraw * scaleDraw() const
QWT_CONSTEXPR float qwtMinF(float a, float b)
Definition: qwt_math.h:99
struct QwtPlotLayout::LayoutData::t_scaleData scale[QwtPlot::axisCnt]
Y axis left of the canvas.
Definition: qwt_plot.h:97
int qwtFloor(qreal value)
Definition: qwt_math.h:271
virtual QSize minimumSizeHint() const QWT_OVERRIDE
const QwtScaleWidget * axisWidget(int axisId) const
void expandLineBreaks(Options options, const QRectF &rect, int &dimTitle, int &dimFooter, int dimAxes[QwtPlot::axisCnt]) const
QwtAbstractLegend * legend()
Definition: qwt_plot.cpp:442
bool testPaintAttribute(PaintAttribute) const
Definition: qwt_text.cpp:459
double heightForWidth(double width) const
Definition: qwt_text.cpp:499
The legend will be below the footer.
Definition: qwt_plot.h:126
QRectF titleRect() const
void setAlignCanvasToScale(int axisId, bool)
virtual bool isEmpty() const =0
int startBorderDist() const
QRectF scaleRect(int axis) const
int spacing() const
A Widget which contains a scale.
void setLegendPosition(QwtPlot::LegendPosition pos, double ratio)
Specify the position of the legend.
void setScaleRect(int axis, const QRectF &)
Set the geometry for an axis.
bool isEmpty() const
Definition: qwt_text.cpp:716
struct QwtPlotLayout::LayoutData::t_footerData footer
A class representing a text.
Definition: qwt_text.h:51
void setAlignCanvasToScales(bool)
Set the align-canvas-to-axis-scales flag for all axes.
virtual void invalidate()
int dimForLength(int length, const QFont &scaleFont) const
Find the minimum dimension for a given length. dim is the height, length the width seen in direction ...
The legend will be right from the QwtPlot::yRight axis.
Definition: qwt_plot.h:123
The legend will be left from the QwtPlot::yLeft axis.
Definition: qwt_plot.h:120
QRectF canvasRect() const
void setTitleRect(const QRectF &)
Set the geometry for the title.
unsigned int canvasMargin[QwtPlot::axisCnt]
void setFooterRect(const QRectF &)
Set the geometry for the footer.
int endBorderDist() const
int top(lua_State *L)
Definition: sol.hpp:10543
struct QwtPlotLayout::LayoutData::t_titleData title
void setSpacing(int)
Abstract base class for legend widgets.
QWidget * canvas()
Definition: qwt_plot.cpp:460
bool alignCanvasToScale(int axisId) const
void setLegendRatio(double ratio)
QwtPlot::LegendPosition legendPos
void init(const QwtPlot *, const QRectF &rect)
void getBorderDistHint(int &start, int &end) const
Calculate a hint for the border distances.
bool hasComponent(ScaleComponent) const
PrivateData * d_data
The legend will be above the title.
Definition: qwt_plot.h:129
The text has an individual font.
Definition: qwt_text.h:117
void alignScales(Options options, QRectF &canvasRect, QRectF scaleRect[QwtPlot::axisCnt]) const
QwtText title() const
virtual int scrollExtent(Qt::Orientation) const
int qwtCeil(qreal value)
Definition: qwt_math.h:262
struct QwtPlotLayout::LayoutData::t_canvasData canvas
X axis below the canvas.
Definition: qwt_plot.h:103
struct Options options


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:48:10