30 frameWidth = legend->frameWidth();
34 hint = legend->sizeHint();
40 const int w = qMin( hint.width(),
qwtFloor( rect.width() ) );
42 int h = legend->heightForWidth( w );
66 text.setFont( label->font() );
68 frameWidth = label->frameWidth();
82 scaleWidget = axisWidget;
83 scaleFont = axisWidget->font();
88 baseLineOffset = axisWidget->
margin();
90 tickOffset = axisWidget->
margin();
94 dimWithoutTitle = axisWidget->
dimForLength( QWIDGETSIZE_MAX, scaleFont );
121 void init(
const QWidget* canvas )
123 const QMargins m = canvas->contentsMargins();
144 bool hasSymmetricYAxes()
const;
146 inline ScaleData& axisData(
QwtAxisId axisId )
148 return m_scaleData[ axisId ];
151 inline const ScaleData& axisData(
QwtAxisId axisId )
const
153 return m_scaleData[ axisId ];
156 inline double tickOffset(
int axisPos )
const
158 return axisData( axisPos ).tickOffset;
161 LegendData legendData;
162 LabelData labelData[ NumLabels ];
163 CanvasData canvasData;
172 LayoutData::LayoutData(
const QwtPlot* plot )
174 legendData.init( plot->
legend() );
175 labelData[ Title ].init( plot->
titleLabel() );
183 ScaleData& scaleData = axisData( axisId );
188 scaleData.init( scaleWidget );
197 canvasData.init( plot->
canvas() );
200 bool LayoutData::hasSymmetricYAxes()
const
203 return m_scaleData[
YLeft ].isVisible == m_scaleData[
YRight ].isVisible;
212 LayoutHintData(
const QwtPlot* plot );
214 int alignedSize(
const QwtAxisId )
const;
216 inline int yAxesWidth()
const
222 inline int yAxesHeight()
const
225 return qMax( axesHeight(
YLeft ), axesHeight(
YRight ) );
228 inline int xAxesHeight()
const
234 inline int xAxesWidth()
const
237 return qMax( axesWidth(
XTop ), axesWidth(
XBottom ) );
246 w = h = minLeft = minRight = tickOffset = 0;
257 const ScaleData& axisData(
QwtAxisId axisId )
const
259 return m_scaleData[ axisId ];
264 return m_scaleData[ axisId ];
267 inline int axesWidth(
int axisPos )
const
269 return m_scaleData[axisPos].w;
272 inline int axesHeight(
int axisPos )
const
274 return m_scaleData[axisPos].h;
281 LayoutHintData::LayoutHintData(
const QwtPlot* plot )
285 const QMargins m = plot->
canvas()->contentsMargins();
287 int contentsMargins[ 4 ];
288 contentsMargins[
YLeft ] = m.left();
289 contentsMargins[
XTop ] = m.top();
290 contentsMargins[
YRight ] = m.right();
291 contentsMargins[
XBottom ] = m.bottom();
295 m_canvasBorder[axisPos] = contentsMargins[axisPos] +
306 ScaleData& sd = axisData( axisId );
308 sd.h = hint.height();
312 sd.tickOffset = scl->
margin();
322 const int sz = alignedSize( axis );
324 ScaleData& sd = axisData( axis );
332 int LayoutHintData::alignedSize(
const QwtAxisId axisId )
const
336 const ScaleData& sd = axisData( axisId );
338 if ( sd.w &&
isXAxis( axisId ) )
342 if (
const int leftW = axesWidth(
YLeft ) )
344 const int shiftLeft = sd.minLeft - m_canvasBorder[
YLeft];
346 w -= qMin( shiftLeft, leftW );
349 if (
const int rightW = axesWidth(
YRight ) )
351 const int shiftRight = sd.minRight - m_canvasBorder[
YRight];
352 if ( shiftRight > 0 )
353 w -= qMin( shiftRight, rightW );
359 if ( sd.h &&
isYAxis( axisId ) )
365 const int shiftBottom = sd.minLeft - m_canvasBorder[
XBottom];
366 if ( shiftBottom > 0 )
367 h -= qMin( shiftBottom, axisData(
XBottom ).tickOffset );
370 if ( axesHeight(
XTop ) )
372 const int shiftTop = sd.minRight - m_canvasBorder[
XTop];
374 h -= qMin( shiftTop, axisData(
XTop ).tickOffset );
393 dimTitle = dimFooter = 0;
395 m_dimAxes[axisPos] = 0;
398 inline int dimAxis(
QwtAxisId axisId )
const
400 return m_dimAxes[ axisId ];
403 void setDimAxis(
QwtAxisId axisId,
int dim )
405 m_dimAxes[ axisId ] = dim;
408 inline int dimAxes(
int axisPos )
const
410 return m_dimAxes[ axisPos ];
413 inline int dimYAxes()
const
418 inline int dimXAxes()
const
423 inline QRectF centered(
const QRectF& rect,
const QRectF& labelRect )
const
425 QRectF r = labelRect;
427 r.setWidth( rect.width() - dimYAxes() );
432 inline QRectF innerRect(
const QRectF& rect )
const
437 rect.width() - dimYAxes(),
438 rect.height() - dimXAxes() );
442 r.setX( rect.center().x() );
445 if ( r.height() < 0 )
447 r.setY( rect.center().y() );
462 : m_legendPos(
QwtPlot::BottomLegend )
463 , m_legendRatio( 1.0 )
468 QRectF layoutLegend( QwtPlotLayout::Options,
469 const LayoutData::LegendData&,
const QRectF&,
const QSize& )
const;
471 QRectF alignLegend(
const QSize& legendHint,
472 const QRectF& canvasRect,
const QRectF& legendRect )
const;
474 void alignScales( QwtPlotLayout::Options,
475 const LayoutData&, QRectF& canvasRect,
478 Dimensions layoutDimensions( QwtPlotLayout::Options,
479 const LayoutData&,
const QRectF& )
const;
481 inline void setSpacing(
unsigned int spacing ) { m_spacing = spacing; }
482 inline unsigned int spacing()
const {
return m_spacing; }
484 inline void setAlignCanvas(
int axisPos,
bool on ) { m_alignCanvas[ axisPos ] = on; }
485 inline bool alignCanvas(
int axisPos )
const {
return m_alignCanvas[ axisPos ]; }
487 inline void setCanvasMargin(
int axisPos,
int margin ) { m_canvasMargin[ axisPos ] = margin; }
488 inline int canvasMargin(
int axisPos )
const {
return m_canvasMargin[ axisPos ]; }
493 inline void setLegendRatio(
double ratio ) { m_legendRatio = ratio; }
494 inline double legendRatio()
const {
return m_legendRatio; }
497 int heightForWidth( LayoutData::Label,
const LayoutData&,
498 QwtPlotLayout::Options,
double width,
int axesWidth )
const;
501 double m_legendRatio;
506 unsigned int m_spacing;
510 QRectF LayoutEngine::layoutLegend( QwtPlotLayout::Options options,
511 const LayoutData::LegendData& legendData,
512 const QRectF& rect,
const QSize& legendHint )
const
521 dim = qMin( legendHint.width(),
int( rect.width() * m_legendRatio ) );
525 if ( legendHint.height() > rect.height() )
530 dim += legendData.hScrollExtent;
536 dim = qMin( legendHint.height(),
int( rect.height() * m_legendRatio ) );
537 dim = qMax( dim, legendData.vScrollExtent );
540 QRectF legendRect = rect;
541 switch ( m_legendPos )
545 legendRect.setWidth( dim );
550 legendRect.setX( rect.right() - dim );
551 legendRect.setWidth( dim );
556 legendRect.setHeight( dim );
561 legendRect.setY( rect.bottom() - dim );
562 legendRect.setHeight( dim );
570 QRectF LayoutEngine::alignLegend(
const QSize& legendHint,
571 const QRectF& canvasRect,
const QRectF& legendRect )
const
573 QRectF alignedRect = legendRect;
578 if ( legendHint.width() < canvasRect.width() )
580 alignedRect.setX( canvasRect.x() );
581 alignedRect.setWidth( canvasRect.width() );
586 if ( legendHint.height() < canvasRect.height() )
588 alignedRect.setY( canvasRect.y() );
589 alignedRect.setHeight( canvasRect.height() );
596 int LayoutEngine::heightForWidth(
597 LayoutData::Label labelType,
const LayoutData& layoutData,
598 QwtPlotLayout::Options options,
599 double width,
int axesWidth )
const
601 const LayoutData::LabelData& labelData = layoutData.labelData[ labelType ];
603 if ( labelData.text.isEmpty() )
608 if ( !layoutData.hasSymmetricYAxes() )
614 int d =
qwtCeil( labelData.text.heightForWidth( w ) );
616 d += 2 * labelData.frameWidth;
621 LayoutEngine::Dimensions LayoutEngine::layoutDimensions( QwtPlotLayout::Options options,
622 const LayoutData& layoutData,
const QRectF& rect )
const
626 Dimensions dimensions;
631 backboneOffset[axisPos] = 0;
633 backboneOffset[axisPos] += layoutData.canvasData.contentsMargins[axisPos];
635 if ( !m_alignCanvas[axisPos] )
636 backboneOffset[axisPos] += m_canvasMargin[axisPos];
654 const int d = heightForWidth(
655 LayoutData::Title, layoutData, options,
656 rect.width(), dimensions.dimYAxes() );
658 if ( d > dimensions.dimTitle )
660 dimensions.dimTitle =
d;
667 const int d = heightForWidth(
668 LayoutData::Footer, layoutData, options,
669 rect.width(), dimensions.dimYAxes() );
671 if ( d > dimensions.dimFooter )
673 dimensions.dimFooter =
d;
683 const LayoutData::ScaleData& scaleData = layoutData.axisData( axisId );
685 if ( scaleData.isVisible )
690 length = rect.width() - dimensions.dimYAxes();
691 length -= scaleData.start + scaleData.end;
693 if ( dimensions.dimAxes(
YRight ) > 0 )
697 scaleData.start - backboneOffset[
YLeft] );
700 scaleData.end - backboneOffset[
YRight] );
704 length = rect.height() - dimensions.dimXAxes();
705 length -= scaleData.start + scaleData.end;
708 if ( dimensions.dimAxes(
XBottom ) <= 0 )
711 if ( dimensions.dimAxes(
XTop ) <= 0 )
719 if ( dimensions.dimAxes(
XBottom ) > 0 )
722 layoutData.tickOffset(
XBottom ),
723 double( scaleData.start - backboneOffset[
XBottom] ) );
726 if ( dimensions.dimAxes(
XTop ) > 0 )
729 layoutData.tickOffset(
XTop ),
730 double( scaleData.end - backboneOffset[
XTop] ) );
733 if ( dimensions.dimTitle > 0 )
734 length -= dimensions.dimTitle + m_spacing;
737 int d = scaleData.dimWithoutTitle;
738 if ( !scaleData.scaleWidget->title().isEmpty() )
740 d += scaleData.scaleWidget->titleHeightForWidth(
qwtFloor( length ) );
744 if ( d > dimensions.dimAxis( axisId ) )
746 dimensions.setDimAxis( axisId, d );
757 void LayoutEngine::alignScales( QwtPlotLayout::Options options,
758 const LayoutData& layoutData, QRectF& canvasRect,
766 backboneOffset[axisPos] = 0;
768 if ( !m_alignCanvas[axisPos] )
770 backboneOffset[axisPos] += m_canvasMargin[axisPos];
775 backboneOffset[axisPos] +=
776 layoutData.canvasData.contentsMargins[axisPos];
783 QRectF& axisRect = scaleRect[axisPos];
784 if ( !axisRect.isValid() )
789 const int startDist = layoutData.axisData( axisId ).start;
790 const int endDist = layoutData.axisData( axisId ).end;
794 const QRectF& leftScaleRect = scaleRect[
YLeft];
795 const int leftOffset = backboneOffset[
YLeft] - startDist;
797 if ( leftScaleRect.isValid() )
799 const double dx = leftOffset + leftScaleRect.width();
800 if ( m_alignCanvas[
YLeft] && dx < 0.0 )
806 const double cLeft = canvasRect.left();
807 canvasRect.setLeft(
qwtMaxF( cLeft, axisRect.left() - dx ) );
811 const double minLeft = leftScaleRect.left();
812 const double left = axisRect.left() + leftOffset;
818 if ( m_alignCanvas[
YLeft] && leftOffset < 0 )
820 canvasRect.setLeft(
qwtMaxF( canvasRect.left(),
821 axisRect.left() - leftOffset ) );
825 if ( leftOffset > 0 )
826 axisRect.setLeft( axisRect.left() + leftOffset );
830 const QRectF& rightScaleRect = scaleRect[
YRight];
831 const int rightOffset = backboneOffset[
YRight] - endDist + 1;
833 if ( rightScaleRect.isValid() )
835 const double dx = rightOffset + rightScaleRect.width();
836 if ( m_alignCanvas[
YRight] && dx < 0 )
842 const double cRight = canvasRect.right();
843 canvasRect.setRight(
qwtMinF( cRight, axisRect.right() + dx ) );
846 const double maxRight = rightScaleRect.right();
847 const double right = axisRect.right() - rightOffset;
852 if ( m_alignCanvas[
YRight] && rightOffset < 0 )
854 canvasRect.setRight(
qwtMinF( canvasRect.right(),
855 axisRect.right() + rightOffset ) );
859 if ( rightOffset > 0 )
860 axisRect.setRight( axisRect.right() - rightOffset );
866 const QRectF& bottomScaleRect = scaleRect[
XBottom];
867 const int bottomOffset = backboneOffset[
XBottom] - endDist + 1;
869 if ( bottomScaleRect.isValid() )
871 const double dy = bottomOffset + bottomScaleRect.height();
872 if ( m_alignCanvas[
XBottom] && dy < 0 )
878 const double cBottom = canvasRect.bottom();
879 canvasRect.setBottom(
qwtMinF( cBottom, axisRect.bottom() + dy ) );
883 const double maxBottom = bottomScaleRect.top() +
884 layoutData.tickOffset(
XBottom );
885 const double bottom = axisRect.bottom() - bottomOffset;
886 axisRect.setBottom(
qwtMinF( bottom, maxBottom ) );
891 if ( m_alignCanvas[
XBottom] && bottomOffset < 0 )
893 canvasRect.setBottom(
qwtMinF( canvasRect.bottom(),
894 axisRect.bottom() + bottomOffset ) );
898 if ( bottomOffset > 0 )
899 axisRect.setBottom( axisRect.bottom() - bottomOffset );
903 const QRectF& topScaleRect = scaleRect[
XTop];
904 const int topOffset = backboneOffset[
XTop] - startDist;
906 if ( topScaleRect.isValid() )
908 const double dy = topOffset + topScaleRect.height();
909 if ( m_alignCanvas[
XTop] && dy < 0 )
915 const double cTop = canvasRect.top();
916 canvasRect.setTop(
qwtMaxF( cTop, axisRect.top() - dy ) );
920 const double minTop = topScaleRect.bottom() -
921 layoutData.tickOffset(
XTop );
923 const double top = axisRect.top() + topOffset;
929 if ( m_alignCanvas[
XTop] && topOffset < 0 )
931 canvasRect.setTop(
qwtMaxF( canvasRect.top(),
932 axisRect.top() - topOffset ) );
937 axisRect.setTop( axisRect.top() + topOffset );
954 QRectF& sRect = scaleRect[axisPos];
955 const LayoutData::ScaleData& axisData = layoutData.axisData( axisId );
957 if ( !sRect.isValid() )
962 if ( m_alignCanvas[
YLeft] )
964 double y = canvasRect.left() - axisData.start;
966 y += layoutData.canvasData.contentsMargins[
YLeft];
971 if ( m_alignCanvas[
YRight] )
973 double y = canvasRect.right() - 1 + axisData.end;
975 y -= layoutData.canvasData.contentsMargins[
YRight];
980 if ( m_alignCanvas[axisPos] )
982 if ( axisPos ==
XTop )
983 sRect.setBottom( canvasRect.top() );
985 sRect.setTop( canvasRect.bottom() );
990 if ( m_alignCanvas[
XTop] )
992 double x = canvasRect.top() - axisData.start;
994 x += layoutData.canvasData.contentsMargins[
XTop];
1001 double x = canvasRect.bottom() - 1 + axisData.end;
1003 x -= layoutData.canvasData.contentsMargins[
XBottom];
1005 sRect.setBottom(
x );
1008 if ( m_alignCanvas[axisPos] )
1010 if ( axisPos ==
YLeft )
1011 sRect.setRight( canvasRect.left() );
1013 sRect.setLeft( canvasRect.right() );
1041 setCanvasMargin( 4 );
1042 setAlignCanvasToScales(
false );
1071 LayoutEngine& engine = m_data->engine;
1073 if ( axisPos == -1 )
1076 engine.setCanvasMargin( axisPos, margin );
1080 engine.setCanvasMargin( axisPos, margin );
1094 return m_data->engine.canvasMargin( axisPos );
1106 m_data->engine.setAlignCanvas( axisPos, on );
1129 m_data->engine.setAlignCanvas( axisPos, on );
1146 return m_data->engine.alignCanvas( axisPos );
1158 m_data->engine.setSpacing( qMax( 0, spacing ) );
1167 return m_data->engine.spacing();
1188 LayoutEngine& engine = m_data->engine;
1198 engine.setLegendRatio( ratio );
1199 engine.setLegendPos( pos );
1209 engine.setLegendRatio( ratio );
1210 engine.setLegendPos( pos );
1229 setLegendPosition( pos, 0.0 );
1239 return m_data->engine.legendPos();
1253 setLegendPosition( legendPosition(), ratio );
1262 return m_data->engine.legendRatio();
1275 m_data->titleRect = rect;
1284 return m_data->titleRect;
1297 m_data->footerRect = rect;
1306 return m_data->footerRect;
1321 m_data->legendRect = rect;
1330 return m_data->legendRect;
1347 m_data->scaleRects[axisId] = rect;
1358 return m_data->scaleRects[axisId];
1373 m_data->canvasRect = rect;
1382 return m_data->canvasRect;
1391 m_data->titleRect = m_data->footerRect =
1392 m_data->legendRect = m_data->canvasRect = QRectF();
1395 m_data->scaleRects[axisPos] = QRect();
1406 LayoutHintData hintData( plot );
1408 const int xAxesWidth = hintData.xAxesWidth();
1409 const int yAxesHeight = hintData.yAxesHeight();
1411 const QWidget* canvas = plot->
canvas();
1413 const QMargins m = canvas->contentsMargins();
1414 const QSize minCanvasSize = canvas->minimumSize();
1416 int w = hintData.yAxesWidth();
1417 int cw = xAxesWidth + m.left() + 1 + m.right() + 1;
1418 w += qMax( cw, minCanvasSize.width() );
1420 int h = hintData.xAxesHeight();
1421 int ch = yAxesHeight + m.top() + 1 + m.bottom() + 1;
1422 h += qMax( ch, minCanvasSize.height() );
1428 for (
int i = 0; i < 2; i++ )
1438 if ( centerOnCanvas )
1440 labelW -= hintData.yAxesWidth();
1444 if ( labelH > labelW )
1446 w = labelW = labelH;
1447 if ( centerOnCanvas )
1448 w += hintData.yAxesWidth();
1452 h += labelH + spacing();
1459 if ( legend && !legend->
isEmpty() )
1461 const LayoutEngine& engine = m_data->engine;
1466 int legendW = legend->sizeHint().width();
1467 int legendH = legend->heightForWidth( legendW );
1469 if ( legend->frameWidth() > 0 )
1475 if ( engine.legendRatio() < 1.0 )
1476 legendW = qMin( legendW,
int( w / ( 1.0 - engine.legendRatio() ) ) );
1478 w += legendW + spacing();
1482 int legendW = qMin( legend->sizeHint().width(), w );
1483 int legendH = legend->heightForWidth( legendW );
1485 if ( legend->frameWidth() > 0 )
1488 if ( engine.legendRatio() < 1.0 )
1489 legendH = qMin( legendH,
int( h / ( 1.0 - engine.legendRatio() ) ) );
1491 h += legendH + spacing();
1495 return QSize( w, h );
1509 const QRectF& plotRect, Options options )
1513 QRectF rect( plotRect );
1518 LayoutData layoutData( plot );
1522 if ( !( options & IgnoreLegend )
1525 legendHint = layoutData.legendData.legendHint( plot->
legend(), rect );
1527 m_data->legendRect = m_data->engine.layoutLegend(
1528 options, layoutData.legendData, rect, legendHint );
1532 const QRegion region( rect.toRect() );
1533 rect = region.subtracted( m_data->legendRect.toRect() ).boundingRect();
1535 switch ( m_data->engine.legendPos() )
1539 rect.setLeft( rect.left() + spacing() );
1544 rect.setRight( rect.right() - spacing() );
1549 rect.setTop( rect.top() + spacing() );
1554 rect.setBottom( rect.bottom() - spacing() );
1586 const LayoutEngine::Dimensions dimensions =
1587 m_data->engine.layoutDimensions( options, layoutData, rect );
1589 if ( dimensions.dimTitle > 0 )
1591 QRectF& labelRect = m_data->titleRect;
1593 labelRect.setRect( rect.left(), rect.top(), rect.width(), dimensions.dimTitle );
1595 rect.setTop( labelRect.bottom() + spacing() );
1597 if ( !layoutData.hasSymmetricYAxes() )
1602 labelRect = dimensions.centered( rect, labelRect );
1606 if ( dimensions.dimFooter > 0 )
1608 QRectF& labelRect = m_data->footerRect;
1610 labelRect.setRect( rect.left(), rect.bottom() - dimensions.dimFooter,
1611 rect.width(), dimensions.dimFooter );
1613 rect.setBottom( labelRect.top() - spacing() );
1615 if ( !layoutData.hasSymmetricYAxes() )
1620 labelRect = dimensions.centered( rect, labelRect );
1624 m_data->canvasRect = dimensions.innerRect( rect );
1634 if ( dimensions.dimAxis( axisId ) )
1636 const int dim = dimensions.dimAxis( axisId );
1638 const QRectF& canvasRect = m_data->canvasRect;
1640 QRectF& scaleRect = m_data->scaleRects[axisId];
1641 scaleRect = canvasRect;
1647 scaleRect.setX( canvasRect.left() - pos - dim );
1648 scaleRect.setWidth( dim );
1653 scaleRect.setX( canvasRect.right() + pos );
1654 scaleRect.setWidth( dim );
1659 scaleRect.setY( canvasRect.bottom() + pos );
1660 scaleRect.setHeight( dim );
1665 scaleRect.setY( canvasRect.top() - pos - dim );
1666 scaleRect.setHeight( dim );
1670 scaleRect = scaleRect.normalized();
1695 m_data->engine.alignScales( options, layoutData,
1696 m_data->canvasRect, m_data->scaleRects );
1698 if ( !m_data->legendRect.isEmpty() )
1703 m_data->legendRect = m_data->engine.alignLegend(
1704 legendHint, m_data->canvasRect, m_data->legendRect );