00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_plot_layout.h"
00011 #include "qwt_text.h"
00012 #include "qwt_text_label.h"
00013 #include "qwt_scale_widget.h"
00014 #include "qwt_abstract_legend.h"
00015 #include <qscrollbar.h>
00016 #include <qmath.h>
00017
00018 class QwtPlotLayout::LayoutData
00019 {
00020 public:
00021 void init( const QwtPlot *, const QRectF &rect );
00022
00023 struct t_legendData
00024 {
00025 int frameWidth;
00026 int hScrollExtent;
00027 int vScrollExtent;
00028 QSize hint;
00029 } legend;
00030
00031 struct t_titleData
00032 {
00033 QwtText text;
00034 int frameWidth;
00035 } title;
00036
00037 struct t_footerData
00038 {
00039 QwtText text;
00040 int frameWidth;
00041 } footer;
00042
00043 struct t_scaleData
00044 {
00045 bool isEnabled;
00046 const QwtScaleWidget *scaleWidget;
00047 QFont scaleFont;
00048 int start;
00049 int end;
00050 int baseLineOffset;
00051 double tickOffset;
00052 int dimWithoutTitle;
00053 } scale[QwtPlot::axisCnt];
00054
00055 struct t_canvasData
00056 {
00057 int contentsMargins[ QwtPlot::axisCnt ];
00058
00059 } canvas;
00060 };
00061
00062
00063
00064
00065 void QwtPlotLayout::LayoutData::init( const QwtPlot *plot, const QRectF &rect )
00066 {
00067
00068
00069 if ( plot->legend() )
00070 {
00071 legend.frameWidth = plot->legend()->frameWidth();
00072 legend.hScrollExtent =
00073 plot->legend()->scrollExtent( Qt::Horizontal );
00074 legend.vScrollExtent =
00075 plot->legend()->scrollExtent( Qt::Vertical );
00076
00077 const QSize hint = plot->legend()->sizeHint();
00078
00079 const int w = qMin( hint.width(), qFloor( rect.width() ) );
00080
00081 int h = plot->legend()->heightForWidth( w );
00082 if ( h <= 0 )
00083 h = hint.height();
00084
00085 legend.hint = QSize( w, h );
00086 }
00087
00088
00089
00090 title.frameWidth = 0;
00091 title.text = QwtText();
00092
00093 if ( plot->titleLabel() )
00094 {
00095 const QwtTextLabel *label = plot->titleLabel();
00096 title.text = label->text();
00097 if ( !( title.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) )
00098 title.text.setFont( label->font() );
00099
00100 title.frameWidth = plot->titleLabel()->frameWidth();
00101 }
00102
00103
00104
00105 footer.frameWidth = 0;
00106 footer.text = QwtText();
00107
00108 if ( plot->footerLabel() )
00109 {
00110 const QwtTextLabel *label = plot->footerLabel();
00111 footer.text = label->text();
00112 if ( !( footer.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) )
00113 footer.text.setFont( label->font() );
00114
00115 footer.frameWidth = plot->footerLabel()->frameWidth();
00116 }
00117
00118
00119
00120 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00121 {
00122 if ( plot->axisEnabled( axis ) )
00123 {
00124 const QwtScaleWidget *scaleWidget = plot->axisWidget( axis );
00125
00126 scale[axis].isEnabled = true;
00127
00128 scale[axis].scaleWidget = scaleWidget;
00129
00130 scale[axis].scaleFont = scaleWidget->font();
00131
00132 scale[axis].start = scaleWidget->startBorderDist();
00133 scale[axis].end = scaleWidget->endBorderDist();
00134
00135 scale[axis].baseLineOffset = scaleWidget->margin();
00136 scale[axis].tickOffset = scaleWidget->margin();
00137 if ( scaleWidget->scaleDraw()->hasComponent(
00138 QwtAbstractScaleDraw::Ticks ) )
00139 {
00140 scale[axis].tickOffset +=
00141 scaleWidget->scaleDraw()->maxTickLength();
00142 }
00143
00144 scale[axis].dimWithoutTitle = scaleWidget->dimForLength(
00145 QWIDGETSIZE_MAX, scale[axis].scaleFont );
00146
00147 if ( !scaleWidget->title().isEmpty() )
00148 {
00149 scale[axis].dimWithoutTitle -=
00150 scaleWidget->titleHeightForWidth( QWIDGETSIZE_MAX );
00151 }
00152 }
00153 else
00154 {
00155 scale[axis].isEnabled = false;
00156 scale[axis].start = 0;
00157 scale[axis].end = 0;
00158 scale[axis].baseLineOffset = 0;
00159 scale[axis].tickOffset = 0.0;
00160 scale[axis].dimWithoutTitle = 0;
00161 }
00162 }
00163
00164
00165
00166 plot->canvas()->getContentsMargins(
00167 &canvas.contentsMargins[ QwtPlot::yLeft ],
00168 &canvas.contentsMargins[ QwtPlot::xTop ],
00169 &canvas.contentsMargins[ QwtPlot::yRight ],
00170 &canvas.contentsMargins[ QwtPlot::xBottom ] );
00171 }
00172
00173 class QwtPlotLayout::PrivateData
00174 {
00175 public:
00176 PrivateData():
00177 spacing( 5 )
00178 {
00179 }
00180
00181 QRectF titleRect;
00182 QRectF footerRect;
00183 QRectF legendRect;
00184 QRectF scaleRect[QwtPlot::axisCnt];
00185 QRectF canvasRect;
00186
00187 QwtPlotLayout::LayoutData layoutData;
00188
00189 QwtPlot::LegendPosition legendPos;
00190 double legendRatio;
00191 unsigned int spacing;
00192 unsigned int canvasMargin[QwtPlot::axisCnt];
00193 bool alignCanvasToScales[QwtPlot::axisCnt];
00194 };
00195
00200 QwtPlotLayout::QwtPlotLayout()
00201 {
00202 d_data = new PrivateData;
00203
00204 setLegendPosition( QwtPlot::BottomLegend );
00205 setCanvasMargin( 4 );
00206 setAlignCanvasToScales( false );
00207
00208 invalidate();
00209 }
00210
00212 QwtPlotLayout::~QwtPlotLayout()
00213 {
00214 delete d_data;
00215 }
00216
00230 void QwtPlotLayout::setCanvasMargin( int margin, int axis )
00231 {
00232 if ( margin < -1 )
00233 margin = -1;
00234
00235 if ( axis == -1 )
00236 {
00237 for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
00238 d_data->canvasMargin[axis] = margin;
00239 }
00240 else if ( axis >= 0 && axis < QwtPlot::axisCnt )
00241 d_data->canvasMargin[axis] = margin;
00242 }
00243
00249 int QwtPlotLayout::canvasMargin( int axisId ) const
00250 {
00251 if ( axisId < 0 || axisId >= QwtPlot::axisCnt )
00252 return 0;
00253
00254 return d_data->canvasMargin[axisId];
00255 }
00256
00263 void QwtPlotLayout::setAlignCanvasToScales( bool on )
00264 {
00265 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00266 d_data->alignCanvasToScales[axis] = on;
00267 }
00268
00286 void QwtPlotLayout::setAlignCanvasToScale( int axisId, bool on )
00287 {
00288 if ( axisId >= 0 && axisId < QwtPlot::axisCnt )
00289 d_data->alignCanvasToScales[axisId] = on;
00290 }
00291
00301 bool QwtPlotLayout::alignCanvasToScale( int axisId ) const
00302 {
00303 if ( axisId < 0 || axisId >= QwtPlot::axisCnt )
00304 return false;
00305
00306 return d_data->alignCanvasToScales[ axisId ];
00307 }
00308
00316 void QwtPlotLayout::setSpacing( int spacing )
00317 {
00318 d_data->spacing = qMax( 0, spacing );
00319 }
00320
00325 int QwtPlotLayout::spacing() const
00326 {
00327 return d_data->spacing;
00328 }
00329
00343 void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos, double ratio )
00344 {
00345 if ( ratio > 1.0 )
00346 ratio = 1.0;
00347
00348 switch ( pos )
00349 {
00350 case QwtPlot::TopLegend:
00351 case QwtPlot::BottomLegend:
00352 if ( ratio <= 0.0 )
00353 ratio = 0.33;
00354 d_data->legendRatio = ratio;
00355 d_data->legendPos = pos;
00356 break;
00357 case QwtPlot::LeftLegend:
00358 case QwtPlot::RightLegend:
00359 if ( ratio <= 0.0 )
00360 ratio = 0.5;
00361 d_data->legendRatio = ratio;
00362 d_data->legendPos = pos;
00363 break;
00364 default:
00365 break;
00366 }
00367 }
00368
00377 void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos )
00378 {
00379 setLegendPosition( pos, 0.0 );
00380 }
00381
00387 QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const
00388 {
00389 return d_data->legendPos;
00390 }
00391
00401 void QwtPlotLayout::setLegendRatio( double ratio )
00402 {
00403 setLegendPosition( legendPosition(), ratio );
00404 }
00405
00410 double QwtPlotLayout::legendRatio() const
00411 {
00412 return d_data->legendRatio;
00413 }
00414
00423 void QwtPlotLayout::setTitleRect( const QRectF &rect )
00424 {
00425 d_data->titleRect = rect;
00426 }
00427
00432 QRectF QwtPlotLayout::titleRect() const
00433 {
00434 return d_data->titleRect;
00435 }
00436
00445 void QwtPlotLayout::setFooterRect( const QRectF &rect )
00446 {
00447 d_data->footerRect = rect;
00448 }
00449
00454 QRectF QwtPlotLayout::footerRect() const
00455 {
00456 return d_data->footerRect;
00457 }
00458
00469 void QwtPlotLayout::setLegendRect( const QRectF &rect )
00470 {
00471 d_data->legendRect = rect;
00472 }
00473
00478 QRectF QwtPlotLayout::legendRect() const
00479 {
00480 return d_data->legendRect;
00481 }
00482
00494 void QwtPlotLayout::setScaleRect( int axis, const QRectF &rect )
00495 {
00496 if ( axis >= 0 && axis < QwtPlot::axisCnt )
00497 d_data->scaleRect[axis] = rect;
00498 }
00499
00505 QRectF QwtPlotLayout::scaleRect( int axis ) const
00506 {
00507 if ( axis < 0 || axis >= QwtPlot::axisCnt )
00508 {
00509 static QRectF dummyRect;
00510 return dummyRect;
00511 }
00512 return d_data->scaleRect[axis];
00513 }
00514
00523 void QwtPlotLayout::setCanvasRect( const QRectF &rect )
00524 {
00525 d_data->canvasRect = rect;
00526 }
00527
00532 QRectF QwtPlotLayout::canvasRect() const
00533 {
00534 return d_data->canvasRect;
00535 }
00536
00541 void QwtPlotLayout::invalidate()
00542 {
00543 d_data->titleRect = d_data->footerRect
00544 = d_data->legendRect = d_data->canvasRect = QRect();
00545
00546 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00547 d_data->scaleRect[axis] = QRect();
00548 }
00549
00557 QSize QwtPlotLayout::minimumSizeHint( const QwtPlot *plot ) const
00558 {
00559 class ScaleData
00560 {
00561 public:
00562 ScaleData()
00563 {
00564 w = h = minLeft = minRight = tickOffset = 0;
00565 }
00566
00567 int w;
00568 int h;
00569 int minLeft;
00570 int minRight;
00571 int tickOffset;
00572 } scaleData[QwtPlot::axisCnt];
00573
00574 int canvasBorder[QwtPlot::axisCnt];
00575
00576 int fw;
00577 plot->canvas()->getContentsMargins( &fw, NULL, NULL, NULL );
00578
00579 int axis;
00580 for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
00581 {
00582 if ( plot->axisEnabled( axis ) )
00583 {
00584 const QwtScaleWidget *scl = plot->axisWidget( axis );
00585 ScaleData &sd = scaleData[axis];
00586
00587 const QSize hint = scl->minimumSizeHint();
00588 sd.w = hint.width();
00589 sd.h = hint.height();
00590 scl->getBorderDistHint( sd.minLeft, sd.minRight );
00591 sd.tickOffset = scl->margin();
00592 if ( scl->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) )
00593 sd.tickOffset += qCeil( scl->scaleDraw()->maxTickLength() );
00594 }
00595
00596 canvasBorder[axis] = fw + d_data->canvasMargin[axis] + 1;
00597 }
00598
00599
00600 for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
00601 {
00602 ScaleData &sd = scaleData[axis];
00603 if ( sd.w && ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) )
00604 {
00605 if ( ( sd.minLeft > canvasBorder[QwtPlot::yLeft] )
00606 && scaleData[QwtPlot::yLeft].w )
00607 {
00608 int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft];
00609 if ( shiftLeft > scaleData[QwtPlot::yLeft].w )
00610 shiftLeft = scaleData[QwtPlot::yLeft].w;
00611
00612 sd.w -= shiftLeft;
00613 }
00614 if ( ( sd.minRight > canvasBorder[QwtPlot::yRight] )
00615 && scaleData[QwtPlot::yRight].w )
00616 {
00617 int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight];
00618 if ( shiftRight > scaleData[QwtPlot::yRight].w )
00619 shiftRight = scaleData[QwtPlot::yRight].w;
00620
00621 sd.w -= shiftRight;
00622 }
00623 }
00624
00625 if ( sd.h && ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) )
00626 {
00627 if ( ( sd.minLeft > canvasBorder[QwtPlot::xBottom] ) &&
00628 scaleData[QwtPlot::xBottom].h )
00629 {
00630 int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom];
00631 if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset )
00632 shiftBottom = scaleData[QwtPlot::xBottom].tickOffset;
00633
00634 sd.h -= shiftBottom;
00635 }
00636 if ( ( sd.minLeft > canvasBorder[QwtPlot::xTop] ) &&
00637 scaleData[QwtPlot::xTop].h )
00638 {
00639 int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop];
00640 if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset )
00641 shiftTop = scaleData[QwtPlot::xTop].tickOffset;
00642
00643 sd.h -= shiftTop;
00644 }
00645 }
00646 }
00647
00648 const QWidget *canvas = plot->canvas();
00649
00650 int left, top, right, bottom;
00651 canvas->getContentsMargins( &left, &top, &right, &bottom );
00652
00653 const QSize minCanvasSize = canvas->minimumSize();
00654
00655 int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w;
00656 int cw = qMax( scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w )
00657 + left + 1 + right + 1;
00658 w += qMax( cw, minCanvasSize.width() );
00659
00660 int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h;
00661 int ch = qMax( scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h )
00662 + top + 1 + bottom + 1;
00663 h += qMax( ch, minCanvasSize.height() );
00664
00665 const QwtTextLabel *labels[2];
00666 labels[0] = plot->titleLabel();
00667 labels[1] = plot->footerLabel();
00668
00669 for ( int i = 0; i < 2; i++ )
00670 {
00671 const QwtTextLabel *label = labels[i];
00672 if ( label && !label->text().isEmpty() )
00673 {
00674
00675
00676 const bool centerOnCanvas = !( plot->axisEnabled( QwtPlot::yLeft )
00677 && plot->axisEnabled( QwtPlot::yRight ) );
00678
00679 int labelW = w;
00680 if ( centerOnCanvas )
00681 {
00682 labelW -= scaleData[QwtPlot::yLeft].w
00683 + scaleData[QwtPlot::yRight].w;
00684 }
00685
00686 int labelH = label->heightForWidth( labelW );
00687 if ( labelH > labelW )
00688 {
00689 w = labelW = labelH;
00690 if ( centerOnCanvas )
00691 {
00692 w += scaleData[QwtPlot::yLeft].w
00693 + scaleData[QwtPlot::yRight].w;
00694 }
00695
00696 labelH = label->heightForWidth( labelW );
00697 }
00698 h += labelH + d_data->spacing;
00699 }
00700 }
00701
00702
00703
00704 const QwtAbstractLegend *legend = plot->legend();
00705 if ( legend && !legend->isEmpty() )
00706 {
00707 if ( d_data->legendPos == QwtPlot::LeftLegend
00708 || d_data->legendPos == QwtPlot::RightLegend )
00709 {
00710 int legendW = legend->sizeHint().width();
00711 int legendH = legend->heightForWidth( legendW );
00712
00713 if ( legend->frameWidth() > 0 )
00714 w += d_data->spacing;
00715
00716 if ( legendH > h )
00717 legendW += legend->scrollExtent( Qt::Horizontal );
00718
00719 if ( d_data->legendRatio < 1.0 )
00720 legendW = qMin( legendW, int( w / ( 1.0 - d_data->legendRatio ) ) );
00721
00722 w += legendW + d_data->spacing;
00723 }
00724 else
00725 {
00726 int legendW = qMin( legend->sizeHint().width(), w );
00727 int legendH = legend->heightForWidth( legendW );
00728
00729 if ( legend->frameWidth() > 0 )
00730 h += d_data->spacing;
00731
00732 if ( d_data->legendRatio < 1.0 )
00733 legendH = qMin( legendH, int( h / ( 1.0 - d_data->legendRatio ) ) );
00734
00735 h += legendH + d_data->spacing;
00736 }
00737 }
00738
00739 return QSize( w, h );
00740 }
00741
00752 QRectF QwtPlotLayout::layoutLegend( Options options,
00753 const QRectF &rect ) const
00754 {
00755 const QSize hint( d_data->layoutData.legend.hint );
00756
00757 int dim;
00758 if ( d_data->legendPos == QwtPlot::LeftLegend
00759 || d_data->legendPos == QwtPlot::RightLegend )
00760 {
00761
00762
00763
00764 dim = qMin( hint.width(), int( rect.width() * d_data->legendRatio ) );
00765
00766 if ( !( options & IgnoreScrollbars ) )
00767 {
00768 if ( hint.height() > rect.height() )
00769 {
00770
00771
00772
00773 dim += d_data->layoutData.legend.hScrollExtent;
00774 }
00775 }
00776 }
00777 else
00778 {
00779 dim = qMin( hint.height(), int( rect.height() * d_data->legendRatio ) );
00780 dim = qMax( dim, d_data->layoutData.legend.vScrollExtent );
00781 }
00782
00783 QRectF legendRect = rect;
00784 switch ( d_data->legendPos )
00785 {
00786 case QwtPlot::LeftLegend:
00787 legendRect.setWidth( dim );
00788 break;
00789 case QwtPlot::RightLegend:
00790 legendRect.setX( rect.right() - dim );
00791 legendRect.setWidth( dim );
00792 break;
00793 case QwtPlot::TopLegend:
00794 legendRect.setHeight( dim );
00795 break;
00796 case QwtPlot::BottomLegend:
00797 legendRect.setY( rect.bottom() - dim );
00798 legendRect.setHeight( dim );
00799 break;
00800 }
00801
00802 return legendRect;
00803 }
00804
00813 QRectF QwtPlotLayout::alignLegend( const QRectF &canvasRect,
00814 const QRectF &legendRect ) const
00815 {
00816 QRectF alignedRect = legendRect;
00817
00818 if ( d_data->legendPos == QwtPlot::BottomLegend
00819 || d_data->legendPos == QwtPlot::TopLegend )
00820 {
00821 if ( d_data->layoutData.legend.hint.width() < canvasRect.width() )
00822 {
00823 alignedRect.setX( canvasRect.x() );
00824 alignedRect.setWidth( canvasRect.width() );
00825 }
00826 }
00827 else
00828 {
00829 if ( d_data->layoutData.legend.hint.height() < canvasRect.height() )
00830 {
00831 alignedRect.setY( canvasRect.y() );
00832 alignedRect.setHeight( canvasRect.height() );
00833 }
00834 }
00835
00836 return alignedRect;
00837 }
00838
00851 void QwtPlotLayout::expandLineBreaks( Options options, const QRectF &rect,
00852 int &dimTitle, int &dimFooter, int dimAxis[QwtPlot::axisCnt] ) const
00853 {
00854 dimTitle = dimFooter = 0;
00855 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00856 dimAxis[axis] = 0;
00857
00858 int backboneOffset[QwtPlot::axisCnt];
00859 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00860 {
00861 backboneOffset[axis] = 0;
00862 if ( !( options & IgnoreFrames ) )
00863 backboneOffset[axis] += d_data->layoutData.canvas.contentsMargins[ axis ];
00864
00865 if ( !d_data->alignCanvasToScales[axis] )
00866 backboneOffset[axis] += d_data->canvasMargin[axis];
00867 }
00868
00869 bool done = false;
00870 while ( !done )
00871 {
00872 done = true;
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882 if ( !( ( options & IgnoreTitle ) ||
00883 d_data->layoutData.title.text.isEmpty() ) )
00884 {
00885 double w = rect.width();
00886
00887 if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled
00888 != d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
00889 {
00890
00891 w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
00892 }
00893
00894 int d = qCeil( d_data->layoutData.title.text.heightForWidth( w ) );
00895 if ( !( options & IgnoreFrames ) )
00896 d += 2 * d_data->layoutData.title.frameWidth;
00897
00898 if ( d > dimTitle )
00899 {
00900 dimTitle = d;
00901 done = false;
00902 }
00903 }
00904
00905 if ( !( ( options & IgnoreFooter ) ||
00906 d_data->layoutData.footer.text.isEmpty() ) )
00907 {
00908 double w = rect.width();
00909
00910 if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled
00911 != d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
00912 {
00913
00914 w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
00915 }
00916
00917 int d = qCeil( d_data->layoutData.footer.text.heightForWidth( w ) );
00918 if ( !( options & IgnoreFrames ) )
00919 d += 2 * d_data->layoutData.footer.frameWidth;
00920
00921 if ( d > dimFooter )
00922 {
00923 dimFooter = d;
00924 done = false;
00925 }
00926 }
00927
00928 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00929 {
00930 const struct LayoutData::t_scaleData &scaleData =
00931 d_data->layoutData.scale[axis];
00932
00933 if ( scaleData.isEnabled )
00934 {
00935 double length;
00936 if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
00937 {
00938 length = rect.width() - dimAxis[QwtPlot::yLeft]
00939 - dimAxis[QwtPlot::yRight];
00940 length -= scaleData.start + scaleData.end;
00941
00942 if ( dimAxis[QwtPlot::yRight] > 0 )
00943 length -= 1;
00944
00945 length += qMin( dimAxis[QwtPlot::yLeft],
00946 scaleData.start - backboneOffset[QwtPlot::yLeft] );
00947 length += qMin( dimAxis[QwtPlot::yRight],
00948 scaleData.end - backboneOffset[QwtPlot::yRight] );
00949 }
00950 else
00951 {
00952 length = rect.height() - dimAxis[QwtPlot::xTop]
00953 - dimAxis[QwtPlot::xBottom];
00954 length -= scaleData.start + scaleData.end;
00955 length -= 1;
00956
00957 if ( dimAxis[QwtPlot::xBottom] <= 0 )
00958 length -= 1;
00959 if ( dimAxis[QwtPlot::xTop] <= 0 )
00960 length -= 1;
00961
00962 if ( dimAxis[QwtPlot::xBottom] > 0 )
00963 {
00964 length += qMin(
00965 d_data->layoutData.scale[QwtPlot::xBottom].tickOffset,
00966 double( scaleData.start - backboneOffset[QwtPlot::xBottom] ) );
00967 }
00968 if ( dimAxis[QwtPlot::xTop] > 0 )
00969 {
00970 length += qMin(
00971 d_data->layoutData.scale[QwtPlot::xTop].tickOffset,
00972 double( scaleData.end - backboneOffset[QwtPlot::xTop] ) );
00973 }
00974
00975 if ( dimTitle > 0 )
00976 length -= dimTitle + d_data->spacing;
00977 }
00978
00979 int d = scaleData.dimWithoutTitle;
00980 if ( !scaleData.scaleWidget->title().isEmpty() )
00981 {
00982 d += scaleData.scaleWidget->titleHeightForWidth( qFloor( length ) );
00983 }
00984
00985
00986 if ( d > dimAxis[axis] )
00987 {
00988 dimAxis[axis] = d;
00989 done = false;
00990 }
00991 }
00992 }
00993 }
00994 }
00995
01007 void QwtPlotLayout::alignScales( Options options,
01008 QRectF &canvasRect, QRectF scaleRect[QwtPlot::axisCnt] ) const
01009 {
01010 int backboneOffset[QwtPlot::axisCnt];
01011 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
01012 {
01013 backboneOffset[axis] = 0;
01014
01015 if ( !d_data->alignCanvasToScales[axis] )
01016 {
01017 backboneOffset[axis] += d_data->canvasMargin[axis];
01018 }
01019
01020 if ( !( options & IgnoreFrames ) )
01021 {
01022 backboneOffset[axis] +=
01023 d_data->layoutData.canvas.contentsMargins[axis];
01024 }
01025 }
01026
01027 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
01028 {
01029 if ( !scaleRect[axis].isValid() )
01030 continue;
01031
01032 const int startDist = d_data->layoutData.scale[axis].start;
01033 const int endDist = d_data->layoutData.scale[axis].end;
01034
01035 QRectF &axisRect = scaleRect[axis];
01036
01037 if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
01038 {
01039 const QRectF &leftScaleRect = scaleRect[QwtPlot::yLeft];
01040 const int leftOffset =
01041 backboneOffset[QwtPlot::yLeft] - startDist;
01042
01043 if ( leftScaleRect.isValid() )
01044 {
01045 const double dx = leftOffset + leftScaleRect.width();
01046 if ( d_data->alignCanvasToScales[QwtPlot::yLeft] && dx < 0.0 )
01047 {
01048
01049
01050
01051
01052 const double cLeft = canvasRect.left();
01053 canvasRect.setLeft( qMax( cLeft, axisRect.left() - dx ) );
01054 }
01055 else
01056 {
01057 const double minLeft = leftScaleRect.left();
01058 const double left = axisRect.left() + leftOffset;
01059 axisRect.setLeft( qMax( left, minLeft ) );
01060 }
01061 }
01062 else
01063 {
01064 if ( d_data->alignCanvasToScales[QwtPlot::yLeft] && leftOffset < 0 )
01065 {
01066 canvasRect.setLeft( qMax( canvasRect.left(),
01067 axisRect.left() - leftOffset ) );
01068 }
01069 else
01070 {
01071 if ( leftOffset > 0 )
01072 axisRect.setLeft( axisRect.left() + leftOffset );
01073 }
01074 }
01075
01076 const QRectF &rightScaleRect = scaleRect[QwtPlot::yRight];
01077 const int rightOffset =
01078 backboneOffset[QwtPlot::yRight] - endDist + 1;
01079
01080 if ( rightScaleRect.isValid() )
01081 {
01082 const double dx = rightOffset + rightScaleRect.width();
01083 if ( d_data->alignCanvasToScales[QwtPlot::yRight] && dx < 0 )
01084 {
01085
01086
01087
01088
01089 const double cRight = canvasRect.right();
01090 canvasRect.setRight( qMin( cRight, axisRect.right() + dx ) );
01091 }
01092
01093 const double maxRight = rightScaleRect.right();
01094 const double right = axisRect.right() - rightOffset;
01095 axisRect.setRight( qMin( right, maxRight ) );
01096 }
01097 else
01098 {
01099 if ( d_data->alignCanvasToScales[QwtPlot::yRight] && rightOffset < 0 )
01100 {
01101 canvasRect.setRight( qMin( canvasRect.right(),
01102 axisRect.right() + rightOffset ) );
01103 }
01104 else
01105 {
01106 if ( rightOffset > 0 )
01107 axisRect.setRight( axisRect.right() - rightOffset );
01108 }
01109 }
01110 }
01111 else
01112 {
01113 const QRectF &bottomScaleRect = scaleRect[QwtPlot::xBottom];
01114 const int bottomOffset =
01115 backboneOffset[QwtPlot::xBottom] - endDist + 1;
01116
01117 if ( bottomScaleRect.isValid() )
01118 {
01119 const double dy = bottomOffset + bottomScaleRect.height();
01120 if ( d_data->alignCanvasToScales[QwtPlot::xBottom] && dy < 0 )
01121 {
01122
01123
01124
01125
01126 const double cBottom = canvasRect.bottom();
01127 canvasRect.setBottom( qMin( cBottom, axisRect.bottom() + dy ) );
01128 }
01129 else
01130 {
01131 const double maxBottom = bottomScaleRect.top() +
01132 d_data->layoutData.scale[QwtPlot::xBottom].tickOffset;
01133 const double bottom = axisRect.bottom() - bottomOffset;
01134 axisRect.setBottom( qMin( bottom, maxBottom ) );
01135 }
01136 }
01137 else
01138 {
01139 if ( d_data->alignCanvasToScales[QwtPlot::xBottom] && bottomOffset < 0 )
01140 {
01141 canvasRect.setBottom( qMin( canvasRect.bottom(),
01142 axisRect.bottom() + bottomOffset ) );
01143 }
01144 else
01145 {
01146 if ( bottomOffset > 0 )
01147 axisRect.setBottom( axisRect.bottom() - bottomOffset );
01148 }
01149 }
01150
01151 const QRectF &topScaleRect = scaleRect[QwtPlot::xTop];
01152 const int topOffset = backboneOffset[QwtPlot::xTop] - startDist;
01153
01154 if ( topScaleRect.isValid() )
01155 {
01156 const double dy = topOffset + topScaleRect.height();
01157 if ( d_data->alignCanvasToScales[QwtPlot::xTop] && dy < 0 )
01158 {
01159
01160
01161
01162
01163 const double cTop = canvasRect.top();
01164 canvasRect.setTop( qMax( cTop, axisRect.top() - dy ) );
01165 }
01166 else
01167 {
01168 const double minTop = topScaleRect.bottom() -
01169 d_data->layoutData.scale[QwtPlot::xTop].tickOffset;
01170 const double top = axisRect.top() + topOffset;
01171 axisRect.setTop( qMax( top, minTop ) );
01172 }
01173 }
01174 else
01175 {
01176 if ( d_data->alignCanvasToScales[QwtPlot::xTop] && topOffset < 0 )
01177 {
01178 canvasRect.setTop( qMax( canvasRect.top(),
01179 axisRect.top() - topOffset ) );
01180 }
01181 else
01182 {
01183 if ( topOffset > 0 )
01184 axisRect.setTop( axisRect.top() + topOffset );
01185 }
01186 }
01187 }
01188 }
01189
01190
01191
01192
01193
01194
01195
01196 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
01197 {
01198 QRectF &sRect = scaleRect[axis];
01199
01200 if ( !sRect.isValid() )
01201 continue;
01202
01203 if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop )
01204 {
01205 if ( d_data->alignCanvasToScales[QwtPlot::yLeft] )
01206 {
01207 double y = canvasRect.left() - d_data->layoutData.scale[axis].start;
01208 if ( !( options & IgnoreFrames ) )
01209 y += d_data->layoutData.canvas.contentsMargins[ QwtPlot::yLeft ];
01210
01211 sRect.setLeft( y );
01212 }
01213 if ( d_data->alignCanvasToScales[QwtPlot::yRight] )
01214 {
01215 double y = canvasRect.right() - 1 + d_data->layoutData.scale[axis].end;
01216 if ( !( options & IgnoreFrames ) )
01217 y -= d_data->layoutData.canvas.contentsMargins[ QwtPlot::yRight ];
01218
01219 sRect.setRight( y );
01220 }
01221
01222 if ( d_data->alignCanvasToScales[ axis ] )
01223 {
01224 if ( axis == QwtPlot::xTop )
01225 sRect.setBottom( canvasRect.top() );
01226 else
01227 sRect.setTop( canvasRect.bottom() );
01228 }
01229 }
01230 else
01231 {
01232 if ( d_data->alignCanvasToScales[QwtPlot::xTop] )
01233 {
01234 double x = canvasRect.top() - d_data->layoutData.scale[axis].start;
01235 if ( !( options & IgnoreFrames ) )
01236 x += d_data->layoutData.canvas.contentsMargins[ QwtPlot::xTop ];
01237
01238 sRect.setTop( x );
01239 }
01240 if ( d_data->alignCanvasToScales[QwtPlot::xBottom] )
01241 {
01242 double x = canvasRect.bottom() - 1 + d_data->layoutData.scale[axis].end;
01243 if ( !( options & IgnoreFrames ) )
01244 x -= d_data->layoutData.canvas.contentsMargins[ QwtPlot::xBottom ];
01245
01246 sRect.setBottom( x );
01247 }
01248
01249 if ( d_data->alignCanvasToScales[ axis ] )
01250 {
01251 if ( axis == QwtPlot::yLeft )
01252 sRect.setRight( canvasRect.left() );
01253 else
01254 sRect.setLeft( canvasRect.right() );
01255 }
01256 }
01257 }
01258 }
01259
01270 void QwtPlotLayout::activate( const QwtPlot *plot,
01271 const QRectF &plotRect, Options options )
01272 {
01273 invalidate();
01274
01275 QRectF rect( plotRect );
01276
01277
01278
01279
01280 d_data->layoutData.init( plot, rect );
01281
01282 if ( !( options & IgnoreLegend )
01283 && plot->legend() && !plot->legend()->isEmpty() )
01284 {
01285 d_data->legendRect = layoutLegend( options, rect );
01286
01287
01288
01289 const QRegion region( rect.toRect() );
01290 rect = region.subtracted( d_data->legendRect.toRect() ).boundingRect();
01291
01292 switch ( d_data->legendPos )
01293 {
01294 case QwtPlot::LeftLegend:
01295 rect.setLeft( rect.left() + d_data->spacing );
01296 break;
01297 case QwtPlot::RightLegend:
01298 rect.setRight( rect.right() - d_data->spacing );
01299 break;
01300 case QwtPlot::TopLegend:
01301 rect.setTop( rect.top() + d_data->spacing );
01302 break;
01303 case QwtPlot::BottomLegend:
01304 rect.setBottom( rect.bottom() - d_data->spacing );
01305 break;
01306 }
01307 }
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333 int dimTitle, dimFooter, dimAxes[QwtPlot::axisCnt];
01334 expandLineBreaks( options, rect, dimTitle, dimFooter, dimAxes );
01335
01336 if ( dimTitle > 0 )
01337 {
01338 d_data->titleRect.setRect(
01339 rect.left(), rect.top(), rect.width(), dimTitle );
01340
01341 rect.setTop( d_data->titleRect.bottom() + d_data->spacing );
01342
01343 if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled !=
01344 d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
01345 {
01346
01347
01348
01349 d_data->titleRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] );
01350 d_data->titleRect.setWidth( rect.width()
01351 - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] );
01352 }
01353 }
01354
01355 if ( dimFooter > 0 )
01356 {
01357 d_data->footerRect.setRect(
01358 rect.left(), rect.bottom() - dimFooter, rect.width(), dimFooter );
01359
01360 rect.setBottom( d_data->footerRect.top() - d_data->spacing );
01361
01362 if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled !=
01363 d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
01364 {
01365
01366
01367
01368 d_data->footerRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] );
01369 d_data->footerRect.setWidth( rect.width()
01370 - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] );
01371 }
01372 }
01373
01374 d_data->canvasRect.setRect(
01375 rect.x() + dimAxes[QwtPlot::yLeft],
01376 rect.y() + dimAxes[QwtPlot::xTop],
01377 rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
01378 rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop] );
01379
01380 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
01381 {
01382
01383
01384 if ( dimAxes[axis] )
01385 {
01386 int dim = dimAxes[axis];
01387 QRectF &scaleRect = d_data->scaleRect[axis];
01388
01389 scaleRect = d_data->canvasRect;
01390 switch ( axis )
01391 {
01392 case QwtPlot::yLeft:
01393 scaleRect.setX( d_data->canvasRect.left() - dim );
01394 scaleRect.setWidth( dim );
01395 break;
01396 case QwtPlot::yRight:
01397 scaleRect.setX( d_data->canvasRect.right() );
01398 scaleRect.setWidth( dim );
01399 break;
01400 case QwtPlot::xBottom:
01401 scaleRect.setY( d_data->canvasRect.bottom() );
01402 scaleRect.setHeight( dim );
01403 break;
01404 case QwtPlot::xTop:
01405 scaleRect.setY( d_data->canvasRect.top() - dim );
01406 scaleRect.setHeight( dim );
01407 break;
01408 }
01409 scaleRect = scaleRect.normalized();
01410 }
01411 }
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 alignScales( options, d_data->canvasRect, d_data->scaleRect );
01434
01435 if ( !d_data->legendRect.isEmpty() )
01436 {
01437
01438
01439
01440 d_data->legendRect = alignLegend( d_data->canvasRect, d_data->legendRect );
01441 }
01442 }