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 }

Generated on Sun Nov 21 11:12:43 2004 for Qwt User's Guide by doxygen 1.3.5