Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

# qwt_plot_layout.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 // vim: expandtab
    00011
    00012 #include <qlabel.h>
    00013 #include "qwt_rect.h"
    00014 #include "qwt_text.h"
    00015 #include "qwt_plot_canvas.h"
    00016 #include "qwt_scale.h"
    00017 #include "qwt_legend.h"
    00018 #include "qwt_plot_layout.h"
    00019
    00020 class QwtPlotLayoutData
    00021 {
    00022     friend class QwtPlotLayout;
    00023
    00024 protected:
    00025     QwtPlotLayoutData();
    00026     ~QwtPlotLayoutData();
    00027
    00028     void init(const QwtPlot *, const QRect &rect);
    00029
    00030     struct t_legendData
    00031     {
    00032         int frameWidth;
    00033         int vScrollBarWidth;
    00034         int hScrollBarHeight;
    00035         QSize hint;
    00036     } legend;
    00037
    00038     struct t_titleData
    00039     {
    00040         const QwtText *text;
    00041         int frameWidth;
    00042     } title;
    00043
    00044     struct t_scaleData
    00045     {
    00046         bool isEnabled;
    00047         const QwtScale *scale;
    00048         QFont scaleFont;
    00049         int start;
    00050         int end;
    00051         int baseLineOffset;
    00052         int tickOffset;
    00053         int dimWithoutTitle;
    00054     } scale[QwtPlot::axisCnt];
    00055
    00056     struct t_canvasData
    00057     {
    00058         int frameWidth;
    00059     } canvas;
    00060 };
    00061
    00066 QwtPlotLayout::QwtPlotLayout():
    00067     d_margin(0),
    00068     d_spacing(5),
    00069     d_alignCanvasToScales(FALSE)
    00070 {
    00071     setLegendPosition(QwtPlot::Bottom);
    00072     setCanvasMargin(4);
    00073     d_layoutData = new QwtPlotLayoutData;
    00074
    00075     invalidate();
    00076 }
    00077
    00079 QwtPlotLayout::~QwtPlotLayout()
    00080 {
    00081     delete d_layoutData;
    00082 }
    00083
    00093 void QwtPlotLayout::setMargin(int margin)
    00094 {
    00095     if ( margin < 0 )
    00096         margin = 0;
    00097     d_margin = margin;
    00098 }
    00099
    00106 int QwtPlotLayout::margin() const
    00107 {
    00108     return d_margin;
    00109 }
    00110
    00124 void QwtPlotLayout::setCanvasMargin(int margin, int axis)
    00125 {
    00126     if ( margin < -1 )
    00127         margin = -1;
    00128
    00129     if ( axis == -1 )
    00130     {
    00131         for (axis = 0; axis < QwtPlot::axisCnt; axis++)
    00132             d_canvasMargin[axis] = margin;
    00133     }
    00134     else if ( axis >= 0 || axis < QwtPlot::axisCnt )
    00135         d_canvasMargin[axis] = margin;
    00136 }
    00137
    00143 int QwtPlotLayout::canvasMargin(int axis) const
    00144 {
    00145     if ( axis < 0 || axis >= QwtPlot::axisCnt )
    00146         return 0;
    00147
    00148     return d_canvasMargin[axis];
    00149 }
    00150
    00151
    00165 void QwtPlotLayout::setAlignCanvasToScales(bool alignCanvasToScales)
    00166 {
    00167     d_alignCanvasToScales = alignCanvasToScales;
    00168 }
    00169
    00180 bool QwtPlotLayout::alignCanvasToScales() const
    00181 {
    00182     return d_alignCanvasToScales;
    00183 }
    00184
    00193 void QwtPlotLayout::setSpacing(int spacing)
    00194 {
    00195     d_spacing = QMAX(0, spacing);
    00196 }
    00197
    00202 int QwtPlotLayout::spacing() const
    00203 {
    00204     return d_spacing;
    00205 }
    00206
    00221 void QwtPlotLayout::setLegendPosition(QwtPlot::Position pos, double ratio)
    00222 {
    00223     if ( ratio > 1.0 )
    00224         ratio = 1.0;
    00225
    00226     switch(pos)
    00227     {
    00228         case QwtPlot::Top:
    00229         case QwtPlot::Bottom:
    00230             if ( ratio <= 0.0 )
    00231                 ratio = 0.33;
    00232             d_legendRatio = ratio;
    00233             d_legendPos = pos;
    00234             break;
    00235         case QwtPlot::Left:
    00236         case QwtPlot::Right:
    00237             if ( ratio <= 0.0 )
    00238                 ratio = 0.5;
    00239             d_legendRatio = ratio;
    00240             d_legendPos = pos;
    00241             break;
    00242         default:
    00243             break;
    00244     }
    00245 }
    00246
    00255 void QwtPlotLayout::setLegendPosition(QwtPlot::Position pos)
    00256 {
    00257     setLegendPosition(pos, 0.0);
    00258 }
    00259
    00266 QwtPlot::Position QwtPlotLayout::legendPosition() const
    00267 {
    00268     return d_legendPos;
    00269 }
    00270
    00271 #ifndef QWT_NO_COMPAT
    00272
    00288 void QwtPlotLayout::setLegendPos(int pos, double ratio)
    00289 {
    00290     setLegendPosition(QwtPlot::Position(pos), ratio);
    00291 }
    00292
    00300 int QwtPlotLayout::legendPos() const
    00301 {
    00302     return d_legendPos;
    00303 }
    00304
    00305 #endif // !QWT_NO_COMPAT
    00306
    00318 void QwtPlotLayout::setLegendRatio(double ratio)
    00319 {
    00320     setLegendPosition(legendPosition(), ratio);
    00321 }
    00322
    00328 double QwtPlotLayout::legendRatio() const
    00329 {
    00330     return d_legendRatio;
    00331 }
    00332
    00338 const QRect &QwtPlotLayout::titleRect() const
    00339 {
    00340     return d_titleRect;
    00341 }
    00342
    00348 const QRect &QwtPlotLayout::legendRect() const
    00349 {
    00350     return d_legendRect;
    00351 }
    00352
    00359 const QRect &QwtPlotLayout::scaleRect(int axis) const
    00360 {
    00361     if ( axis < 0 || axis >= QwtPlot::axisCnt )
    00362     {
    00363         static QRect dummyRect;
    00364         return dummyRect;
    00365     }
    00366     return d_scaleRect[axis];
    00367 }
    00368
    00374 const QRect &QwtPlotLayout::canvasRect() const
    00375 {
    00376     return d_canvasRect;
    00377 }
    00378
    00383 void QwtPlotLayout::invalidate()
    00384 {
    00385     d_titleRect = d_legendRect = d_canvasRect = QRect();
    00386     for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
    00387         d_scaleRect[axis] = QRect();
    00388 }
    00389
    00395 QSize QwtPlotLayout::minimumSizeHint(const QwtPlot *plot) const
    00396 {
    00397     class ScaleData
    00398     {
    00399     public:
    00400         ScaleData()
    00401         {
    00402             w = h = minLeft = minRight = tickOffset = 0;
    00403         }
    00404
    00405         int w;
    00406         int h;
    00407         int minLeft;
    00408         int minRight;
    00409         int tickOffset;
    00410     } scaleData[QwtPlot::axisCnt];
    00411
    00412     int canvasBorder[QwtPlot::axisCnt];
    00413
    00414     int axis;
    00415     for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
    00416     {
    00417         const QwtScale *scl = plot->axis(axis);
    00418         if ( scl )
    00419         {
    00420             ScaleData &sd = scaleData[axis];
    00421
    00422             const QSize hint = scl->minimumSizeHint();
    00423             sd.w = hint.width();
    00424             sd.h = hint.height();
    00425             scl->minBorderDist(sd.minLeft, sd.minRight);
    00426             sd.tickOffset = scl->baseLineDist() +
    00427                 scl->scaleDraw()->majTickLength();
    00428         }
    00429
    00430         canvasBorder[axis] = plot->canvas()->frameWidth() +
    00431             d_canvasMargin[axis] + 1;
    00432
    00433     }
    00434
    00435
    00436     for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
    00437     {
    00438         ScaleData &sd = scaleData[axis];
    00439         if ( sd.w && (axis == QwtPlot::xBottom || axis == QwtPlot::xTop) )
    00440         {
    00441             if ( (sd.minLeft > canvasBorder[QwtPlot::yLeft])
    00442                 && scaleData[QwtPlot::yLeft].w )
    00443             {
    00444                 int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft];
    00445                 if ( shiftLeft > scaleData[QwtPlot::yLeft].w )
    00446                     shiftLeft = scaleData[QwtPlot::yLeft].w;
    00447
    00448                 sd.w -= shiftLeft;
    00449             }
    00450             if ( (sd.minRight > canvasBorder[QwtPlot::yRight])
    00451                 && scaleData[QwtPlot::yRight].w )
    00452             {
    00453                 int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight];
    00454                 if ( shiftRight > scaleData[QwtPlot::yRight].w )
    00455                     shiftRight = scaleData[QwtPlot::yRight].w;
    00456
    00457                 sd.w -= shiftRight;
    00458             }
    00459         }
    00460
    00461         if ( sd.h && (axis == QwtPlot::yLeft || axis == QwtPlot::yRight) )
    00462         {
    00463             if ( (sd.minLeft > canvasBorder[QwtPlot::xBottom]) &&
    00464                 scaleData[QwtPlot::xBottom].h )
    00465             {
    00466                 int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom];
    00467                 if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset )
    00468                     shiftBottom = scaleData[QwtPlot::xBottom].tickOffset;
    00469
    00470                 sd.h -= shiftBottom;
    00471             }
    00472             if ( (sd.minLeft > canvasBorder[QwtPlot::xTop]) &&
    00473                 scaleData[QwtPlot::xTop].h )
    00474             {
    00475                 int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop];
    00476                 if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset )
    00477                     shiftTop = scaleData[QwtPlot::xTop].tickOffset;
    00478
    00479                 sd.h -= shiftTop;
    00480             }
    00481         }
    00482     }
    00483
    00484     const QwtPlotCanvas *canvas = plot->canvas();
    00485
    00486     int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w
    00487         + QMAX(scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w)
    00488         + 2 * (canvas->frameWidth() + 1);
    00489     int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h
    00490         + QMAX(scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h)
    00491         + 2 * (canvas->frameWidth() + 1);
    00492
    00493     const QLabel *title = plot->titleLabel();
    00494     if (title && !title->text().isEmpty())
    00495     {
    00496         // If only QwtPlot::yLeft or QwtPlot::yRight is showing,
    00497         // we center on the plot canvas.
    00498         const bool centerOnCanvas = plot->axis(QwtPlot::yLeft) == 0
    00499             || plot->axis(QwtPlot::yRight) == 0;
    00500
    00501         int titleW = w;
    00502         if ( centerOnCanvas )
    00503         {
    00504             titleW -= scaleData[QwtPlot::yLeft].w
    00505                 + scaleData[QwtPlot::yRight].w;
    00506         }
    00507
    00508         int titleH = title->heightForWidth(titleW);
    00509         if ( titleH > titleW ) // Compensate for a long title
    00510         {
    00511             w = titleW = titleH;
    00512             if ( centerOnCanvas )
    00513             {
    00514                 w += scaleData[QwtPlot::yLeft].w
    00515                     + scaleData[QwtPlot::yRight].w;
    00516             }
    00517
    00518             titleH = title->heightForWidth(titleW);
    00519         }
    00520         h += titleH + d_spacing;
    00521     }
    00522
    00523     // Compute the legend contribution
    00524
    00525     const QwtLegend *legend = plot->legend();
    00526     if ( legend && !legend->isEmpty() )
    00527     {
    00528         if ( d_legendPos == QwtPlot::Left || d_legendPos == QwtPlot::Right )
    00529         {
    00530             int legendW = legend->sizeHint().width();
    00531             int legendH = legend->heightForWidth(legendW);
    00532
    00533             if ( legend->frameWidth() > 0 )
    00534                 w += d_spacing;
    00535
    00536             if ( legendH > h )
    00537                 legendW += legend->verticalScrollBar()->sizeHint().height();
    00538
    00539             if ( d_legendRatio < 1.0 )
    00540                 legendW = QMIN(legendW, int(w / (1.0 - d_legendRatio)));
    00541
    00542             w += legendW;
    00543         }
    00544         else // QwtPlot::Top, QwtPlot::Bottom
    00545         {
    00546             int legendW = QMIN(legend->sizeHint().width(), w);
    00547             int legendH = legend->heightForWidth(legendW);
    00548
    00549             if ( legend->frameWidth() > 0 )
    00550                 h += d_spacing;
    00551
    00552             if ( d_legendRatio < 1.0 )
    00553                 legendH = QMIN(legendH, int(h / (1.0 - d_legendRatio)));
    00554
    00555             h += legendH;
    00556         }
    00557     }
    00558
    00559     w += 2 * d_margin;
    00560     h += 2 * d_margin;
    00561
    00562     return QSize( w, h );
    00563 }
    00564
    00572 QRect QwtPlotLayout::layoutLegend(int options,
    00573     const QRect &rect) const
    00574 {
    00575     const QSize hint(d_layoutData->legend.hint);
    00576
    00577     int dim;
    00578     if ( d_legendPos == QwtPlot::Left || d_legendPos == QwtPlot::Right )
    00579     {
    00580         // We don't allow vertical legends to take more than
    00581         // half of the available space.
    00582
    00583         dim = QMIN(hint.width(), int(rect.width() * d_legendRatio));
    00584
    00585         if ( !(options & IgnoreScrollbars) )
    00586         {
    00587             if ( hint.height() > rect.height() )
    00588             {
    00589                 // The legend will need additional
    00590                 // space for the vertical scrollbar.
    00591
    00592                 dim += d_layoutData->legend.vScrollBarWidth;
    00593             }
    00594         }
    00595     }
    00596     else
    00597     {
    00598         dim = QMIN(hint.height(), int(rect.height() * d_legendRatio));
    00599         dim = QMAX(dim, d_layoutData->legend.hScrollBarHeight);
    00600     }
    00601
    00602     QRect legendRect = rect;
    00603     switch(d_legendPos)
    00604     {
    00605         case QwtPlot::Left:
    00606             legendRect.setWidth(dim);
    00607             break;
    00608         case QwtPlot::Right:
    00609             legendRect.setX(rect.right() - dim + 1);
    00610             legendRect.setWidth(dim);
    00611             break;
    00612         case QwtPlot::Top:
    00613             legendRect.setHeight(dim);
    00614             break;
    00615         case QwtPlot::Bottom:
    00616             legendRect.setY(rect.bottom() - dim + 1);
    00617             legendRect.setHeight(dim);
    00618             break;
    00619     }
    00620
    00621     return legendRect;
    00622 }
    00623
    00630 QRect QwtPlotLayout::alignLegend(const QRect &canvasRect,
    00631     const QRect &legendRect) const
    00632 {
    00633     QRect alignedRect = legendRect;
    00634
    00635     if ( d_legendPos == QwtPlot::Bottom || d_legendPos == QwtPlot::Top )
    00636     {
    00637         if ( d_layoutData->legend.hint.width() < canvasRect.width() )
    00638         {
    00639             alignedRect.setX(canvasRect.x());
    00640             alignedRect.setWidth(canvasRect.width());
    00641         }
    00642     }
    00643     else
    00644     {
    00645         if ( d_layoutData->legend.hint.height() < canvasRect.height() )
    00646         {
    00647             alignedRect.setY(canvasRect.y());
    00648             alignedRect.setHeight(canvasRect.height());
    00649         }
    00650     }
    00651
    00652     return alignedRect;
    00653 }
    00654
    00664 void QwtPlotLayout::expandLineBreaks(int options, const QRect &rect,
    00665     int &dimTitle, int dimAxis[QwtPlot::axisCnt]) const
    00666 {
    00667     dimTitle = 0;
    00668     for ( int i = 0; i < QwtPlot::axisCnt; i++ )
    00669         dimAxis[i] = 0;
    00670
    00671     bool done = FALSE;
    00672     while (!done)
    00673     {
    00674         done = TRUE;
    00675
    00676         // the size for the 4 axis depend on each other. Expanding
    00677         // the height of a horizontal axis will shrink the height
    00678         // for the vertical axis, shrinking the height of a vertical
    00679         // axis will result in a line break what will expand the
    00680         // width and results in shrinking the width of a horizontal
    00681         // axis what might result in a line break of a horizontal
    00682         // axis ... . So we loop as long until no size changes.
    00683
    00684         if ( d_layoutData->title.text)
    00685         {
    00686             int w = rect.width();
    00687
    00688             if ( d_layoutData->scale[QwtPlot::yLeft].isEnabled
    00689                 != d_layoutData->scale[QwtPlot::yRight].isEnabled )
    00690             {
    00691                 // center to the canvas
    00692                 w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
    00693             }
    00694
    00695             int d = d_layoutData->title.text->heightForWidth(w);
    00696             if ( !(options & IgnoreFrames) )
    00697                 d += 2 * d_layoutData->title.frameWidth;
    00698
    00699             if ( d > dimTitle )
    00700             {
    00701                 dimTitle = d;
    00702                 done = FALSE;
    00703             }
    00704         }
    00705
    00706         for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
    00707         {
    00708             int backboneOffset = d_canvasMargin[axis];
    00709             if ( !(options & IgnoreFrames) )
    00710                 backboneOffset += d_layoutData->canvas.frameWidth;
    00711
    00712             const struct QwtPlotLayoutData::t_scaleData &scaleData =
    00713                 d_layoutData->scale[axis];
    00714
    00715             if (scaleData.isEnabled)
    00716             {
    00717                 int length;
    00718                 if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
    00719                 {
    00720                     length = rect.width() - dimAxis[QwtPlot::yLeft]
    00721                         - dimAxis[QwtPlot::yRight];
    00722                     length += QMIN(dimAxis[QwtPlot::yLeft],
    00723                         scaleData.start - backboneOffset);
    00724                     length += QMIN(dimAxis[QwtPlot::yRight],
    00725                         scaleData.end - backboneOffset);
    00726                 }
    00727                 else // QwtPlot::yLeft, QwtPlot::yRight
    00728                 {
    00729                     length = rect.height() - dimAxis[QwtPlot::xTop]
    00730                         - dimAxis[QwtPlot::xBottom];
    00731
    00732                     if ( dimAxis[QwtPlot::xBottom] > 0 )
    00733                     {
    00734                         length += QMIN(
    00735                             d_layoutData->scale[QwtPlot::xBottom].tickOffset,
    00736                             scaleData.start - backboneOffset);
    00737                     }
    00738                     if ( dimAxis[QwtPlot::xTop] > 0 )
    00739                     {
    00740                         length += QMIN(
    00741                             d_layoutData->scale[QwtPlot::xTop].tickOffset,
    00742                             scaleData.end - backboneOffset);
    00743                     }
    00744
    00745                     if ( dimTitle > 0 )
    00746                         length -= dimTitle + d_spacing;
    00747                 }
    00748
    00749                 int d = scaleData.dimWithoutTitle;
    00750                 if ( !scaleData.scale->title().isEmpty() )
    00751                 {
    00752                     d += scaleData.scale->titleHeightForWidth(length);
    00753                 }
    00754
    00755                 if ( options & AlignScales )
    00756                     d -= scaleData.baseLineOffset;
    00757
    00758                 if ( d > dimAxis[axis] )
    00759                 {
    00760                     dimAxis[axis] = d;
    00761                     done = FALSE;
    00762                 }
    00763             }
    00764         }
    00765     }
    00766 }
    00767
    00773 void QwtPlotLayout::alignScales(int options,
    00774     QRect &canvasRect, QRect scaleRect[QwtPlot::axisCnt]) const
    00775 {
    00776     int axis;
    00777
    00778     int backboneOffset[QwtPlot::axisCnt];
    00779     for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
    00780     {
    00781         backboneOffset[axis] = 0;
    00782         if ( !d_alignCanvasToScales )
    00783             backboneOffset[axis] += d_canvasMargin[axis];
    00784         if ( !(options & IgnoreFrames) )
    00785             backboneOffset[axis] += d_layoutData->canvas.frameWidth;
    00786     }
    00787
    00788     for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
    00789     {
    00790         if ( !scaleRect[axis].isValid() )
    00791             continue;
    00792
    00793         const int startDist = d_layoutData->scale[axis].start;
    00794         const int endDist = d_layoutData->scale[axis].end;
    00795
    00796         QRect &axisRect = scaleRect[axis];
    00797
    00798         if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
    00799         {
    00800             const int leftOffset = backboneOffset[QwtPlot::yLeft] - startDist;
    00801
    00802             if ( scaleRect[QwtPlot::yLeft].isValid() )
    00803             {
    00804                 int minLeft = scaleRect[QwtPlot::yLeft].left();
    00805                 int left = axisRect.left() + leftOffset;
    00806                 axisRect.setLeft(QMAX(left, minLeft));
    00807             }
    00808             else
    00809             {
    00810                 if ( d_alignCanvasToScales )
    00811                 {
    00812                     canvasRect.setLeft(QMAX(canvasRect.left(),
    00813                         axisRect.left() - leftOffset));
    00814                 }
    00815                 else
    00816                 {
    00817                     if ( leftOffset > 0 )
    00818                         axisRect.setLeft(axisRect.left() + leftOffset);
    00819                 }
    00820             }
    00821
    00822             const int rightOffset = backboneOffset[QwtPlot::yRight] - endDist;
    00823
    00824             if ( scaleRect[QwtPlot::yRight].isValid() )
    00825             {
    00826                 int maxRight = scaleRect[QwtPlot::yRight].right();
    00827                 int right = axisRect.right() - rightOffset;
    00828                 axisRect.setRight(QMIN(right, maxRight));
    00829             }
    00830             else
    00831             {
    00832                 if ( d_alignCanvasToScales )
    00833                 {
    00834                     canvasRect.setRight( QMIN(canvasRect.right(),
    00835                         axisRect.right() + rightOffset) );
    00836                 }
    00837                 else
    00838                 {
    00839                     if ( rightOffset > 0 )
    00840                         axisRect.setRight(axisRect.right() - rightOffset);
    00841                 }
    00842             }
    00843         }
    00844         else // QwtPlot::yLeft, QwtPlot::yRight
    00845         {
    00846             const int bottomOffset =
    00847                 backboneOffset[QwtPlot::xBottom] - startDist;
    00848
    00849             if ( scaleRect[QwtPlot::xBottom].isValid() )
    00850             {
    00851                 int maxBottom = scaleRect[QwtPlot::xBottom].top() +
    00852                     d_layoutData->scale[QwtPlot::xBottom].tickOffset;
    00853
    00854                 int bottom = axisRect.bottom() - bottomOffset;
    00855                 axisRect.setBottom(QMIN(bottom, maxBottom));
    00856             }
    00857             else
    00858             {
    00859                 if ( d_alignCanvasToScales )
    00860                 {
    00861                     canvasRect.setBottom(QMIN(canvasRect.bottom(),
    00862                         axisRect.bottom() + bottomOffset));
    00863                 }
    00864                 else
    00865                 {
    00866                     if ( bottomOffset > 0 )
    00867                         axisRect.setBottom(axisRect.bottom() - bottomOffset);
    00868                 }
    00869             }
    00870
    00871             const int topOffset = backboneOffset[QwtPlot::xTop] - endDist;
    00872
    00873             if ( scaleRect[QwtPlot::xTop].isValid() )
    00874             {
    00875                 int minTop = scaleRect[QwtPlot::xTop].bottom() -
    00876                     d_layoutData->scale[QwtPlot::xTop].tickOffset;
    00877
    00878                 int top = axisRect.top() + topOffset;
    00879                 axisRect.setTop(QMAX(top, minTop));
    00880             }
    00881             else
    00882             {
    00883                 if ( d_alignCanvasToScales )
    00884                 {
    00885                     canvasRect.setTop(QMAX(canvasRect.top(),
    00886                         axisRect.top() + - topOffset));
    00887                 }
    00888                 else
    00889                 {
    00890                     if ( topOffset > 0 )
    00891                         axisRect.setTop(axisRect.top() + topOffset);
    00892                 }
    00893             }
    00894         }
    00895     }
    00896 }
    00897
    00910 void QwtPlotLayout::activate(const QwtPlot *plot,
    00911     const QRect &plotRect, int options)
    00912 {
    00913     invalidate();
    00914
    00915     QRect rect(plotRect);  // undistributed rest of the plot rect
    00916
    00917     if ( !(options & IgnoreMargin) )
    00918     {
    00919         // subtract the margin
    00920
    00921         rect.setRect(
    00922             rect.x() + d_margin,
    00923             rect.y() + d_margin,
    00924             rect.width() - 2 * d_margin,
    00925             rect.height() - 2 * d_margin
    00926         );
    00927     }
    00928
    00929     // We extract all layout relevant data from the widgets,
    00930     // filter them through pfilter and save them to d_layoutData.
    00931
    00932     d_layoutData->init(plot, rect);
    00933
    00934     if (!(options & IgnoreLegend)
    00935         && plot->legend() && !plot->legend()->isEmpty() )
    00936     {
    00937         d_legendRect = layoutLegend(options, rect);
    00938
    00939         // subtract d_legendRect from rect
    00940
    00941         const QRegion region(rect);
    00942         rect = region.subtract(d_legendRect).boundingRect();
    00943
    00944         if ( d_layoutData->legend.frameWidth &&
    00945             !(options & IgnoreFrames ) )
    00946         {
    00947             // In case of a frame we have to insert a spacing.
    00948             // Otherwise the leading of the font separates
    00949             // legend and scale/canvas
    00950
    00951             switch(d_legendPos)
    00952             {
    00953                 case QwtPlot::Left:
    00954                     rect.setLeft(rect.left() + d_spacing);
    00955                     break;
    00956                 case QwtPlot::Right:
    00957                     rect.setRight(rect.right() - d_spacing);
    00958                     break;
    00959                 case QwtPlot::Top:
    00960                     rect.setTop(rect.top() + d_spacing);
    00961                     break;
    00962                 case QwtPlot::Bottom:
    00963                     rect.setBottom(rect.bottom() - d_spacing);
    00964                     break;
    00965             }
    00966         }
    00967     }
    00968
    00969     /*
    00970      +---+-----------+---+
    00971      |       Title       |
    00972      +---+-----------+---+
    00973      |   |   Axis    |   |
    00974      +---+-----------+---+
    00975      | A |           | A |
    00976      | x |  Canvas   | x |
    00977      | i |           | i |
    00978      | s |           | s |
    00979      +---+-----------+---+
    00980      |   |   Axis    |   |
    00981      +---+-----------+---+
    00982     */
    00983
    00984
    00985     // axes and title include text labels. The height of each
    00986     // label depends on its line breaks, that depend on the width
    00987     // for the label. A line break in a horizontal text will reduce
    00988     // the available width for vertical texts and vice versa.
    00989     // expandLineBreaks finds the height/width for title and axes
    00990     // including all line breaks.
    00991
    00992     int dimTitle, dimAxes[QwtPlot::axisCnt];
    00993     expandLineBreaks(options, rect, dimTitle, dimAxes);
    00994
    00995     if (dimTitle > 0 )
    00996     {
    00997         d_titleRect = QRect(rect.x(), rect.y(),
    00998             rect.width(), dimTitle);
    00999
    01000         if ( d_layoutData->scale[QwtPlot::yLeft].isEnabled !=
    01001             d_layoutData->scale[QwtPlot::yRight].isEnabled )
    01002         {
    01003             // if only one of the y axes is missing we align
    01004             // the title centered to the canvas
    01005
    01006             d_titleRect.setX(rect.x() + dimAxes[QwtPlot::yLeft]);
    01007             d_titleRect.setWidth(rect.width()
    01008                 - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight]);
    01009         }
    01010
    01011         // subtract title
    01012         rect.setTop(rect.top() + dimTitle + d_spacing);
    01013     }
    01014
    01015     d_canvasRect.setRect(
    01016         rect.x() + dimAxes[QwtPlot::yLeft],
    01017         rect.y() + dimAxes[QwtPlot::xTop],
    01018         rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
    01019         rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop]);
    01020
    01021     for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
    01022     {
    01023         // set the rects for the axes
    01024
    01025         if ( dimAxes[axis] )
    01026         {
    01027             int dim = dimAxes[axis];
    01028             QRect &scaleRect = d_scaleRect[axis];
    01029
    01030             scaleRect = d_canvasRect;
    01031             switch(axis)
    01032             {
    01033                 case QwtPlot::yLeft:
    01034                     scaleRect.setX(d_canvasRect.left() - dim);
    01035                     scaleRect.setWidth(dim);
    01036                     break;
    01037                 case QwtPlot::yRight:
    01038                     scaleRect.setX(d_canvasRect.right() + 1);
    01039                     scaleRect.setWidth(dim);
    01040                     break;
    01041                 case QwtPlot::xBottom:
    01042                     scaleRect.setY(d_canvasRect.bottom() + 1);
    01043                     scaleRect.setHeight(dim);
    01044                     break;
    01045                 case QwtPlot::xTop:
    01046                     scaleRect.setY(d_canvasRect.top() - dim);
    01047                     scaleRect.setHeight(dim);
    01048                     break;
    01049             }
    01050             scaleRect = scaleRect.normalize();
    01051         }
    01052     }
    01053
    01054     // +---+-----------+---+
    01055     // |  <-   Axis   ->   |
    01056     // +-^-+-----------+-^-+
    01057     // | | |           | | |
    01058     // |   |           |   |
    01059     // | A |           | A |
    01060     // | x |  Canvas   | x |
    01061     // | i |           | i |
    01062     // | s |           | s |
    01063     // |   |           |   |
    01064     // | | |           | | |
    01065     // +-V-+-----------+-V-+
    01066     // |   <-  Axis   ->   |
    01067     // +---+-----------+---+
    01068
    01069     // The ticks of the axes - not the labels above - should
    01070     // be aligned to the canvas. So we try to use the empty
    01071     // corners to extend the axes, so that the label texts
    01072     // left/right of the min/max ticks are moved into them.
    01073
    01074     alignScales(options, d_canvasRect, d_scaleRect);
    01075
    01076     if (!d_legendRect.isEmpty() )
    01077     {
    01078         // We prefer to align the legend to the canvas - not to
    01079         // the complete plot - if possible.
    01080
    01081         d_legendRect = alignLegend(d_canvasRect, d_legendRect);
    01082     }
    01083 }
    01084
    01085 QwtPlotLayoutData::QwtPlotLayoutData()
    01086 {
    01087     title.text = NULL;
    01088 }
    01089
    01090 QwtPlotLayoutData::~QwtPlotLayoutData()
    01091 {
    01092     delete title.text;
    01093 }
    01094
    01095 /*
    01096   Extract all layout relevant data from the plot components
    01097 */
    01098
    01099 void QwtPlotLayoutData::init(const QwtPlot *plot, const QRect &rect)
    01100 {
    01101     // legend
    01102
    01103     legend.frameWidth = plot->legend()->frameWidth();
    01104     legend.vScrollBarWidth =
    01105         plot->legend()->verticalScrollBar()->sizeHint().width();
    01106     legend.hScrollBarHeight =
    01107         plot->legend()->horizontalScrollBar()->sizeHint().height();
    01108
    01109     const QSize hint = plot->legend()->sizeHint();
    01110
    01111     int w = QMIN(hint.width(), rect.width());
    01112     int h = plot->legend()->heightForWidth(w);
    01113     if ( h == 0 )
    01114         h = hint.height();
    01115
    01116     if ( h > rect.height() )
    01117         w += legend.vScrollBarWidth;
    01118
    01119     legend.hint = QSize(w, h);
    01120
    01121     // title
    01122
    01123     title.frameWidth = 0;
    01124     delete title.text;
    01125     title.text = NULL;
    01126
    01127     if (plot->titleLabel() && !plot->titleLabel()->text().isEmpty())
    01128     {
    01129         const QLabel *label = plot->titleLabel();
    01130         title.text = QwtText::makeText(label->text(), label->textFormat(),
    01131             label->alignment(), label->font());
    01132         title.frameWidth = plot->titleLabel()->frameWidth();
    01133     }
    01134
    01135     // scales
    01136
    01137     for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
    01138     {
    01139         const QwtScale *sd = plot->axis(axis);
    01140         if ( sd )
    01141         {
    01142             scale[axis].isEnabled = TRUE;
    01143
    01144             scale[axis].scale = sd;
    01145
    01146             scale[axis].scaleFont = sd->font();
    01147
    01148             scale[axis].start = sd->startBorderDist();
    01149             scale[axis].end = sd->endBorderDist();
    01150
    01151             scale[axis].baseLineOffset = sd->baseLineDist();
    01152             scale[axis].tickOffset = sd->baseLineDist() +
    01153                 (int)sd->scaleDraw()->majTickLength();
    01154
    01155             scale[axis].dimWithoutTitle = sd->dimForLength(
    01156                 QCOORD_MAX, scale[axis].scaleFont);
    01157
    01158             if ( !sd->title().isEmpty() )
    01159             {
    01160                 scale[axis].dimWithoutTitle -=
    01161                     sd->titleHeightForWidth(QCOORD_MAX);
    01162             }
    01163         }
    01164         else
    01165         {
    01166             scale[axis].isEnabled = FALSE;
    01167             scale[axis].start = 0;
    01168             scale[axis].end = 0;
    01169             scale[axis].baseLineOffset = 0;
    01170             scale[axis].tickOffset = 0;
    01171             scale[axis].dimWithoutTitle = 0;
    01172         }
    01173     }
    01174
    01175     // canvas
    01176
    01177     canvas.frameWidth = plot->canvas()->frameWidth();
    01178 }