Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | 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 <qscrollbar.h>
00013 #include "qwt_rect.h"
00014 #include "qwt_text.h"
00015 #include "qwt_text_label.h"
00016 #include "qwt_plot_canvas.h"
00017 #include "qwt_scale_widget.h"
00018 #include "qwt_legend.h"
00019 #include "qwt_plot_layout.h"
00020 
00021 class QwtPlotLayout::LayoutData
00022 {
00023 public:
00024     void init(const QwtPlot *, const QRect &rect);
00025 
00026     struct t_legendData
00027     {
00028         int frameWidth;
00029         int vScrollBarWidth;
00030         int hScrollBarHeight;
00031         QSize hint;
00032     } legend;
00033     
00034     struct t_titleData
00035     {
00036         QwtText text;
00037         int frameWidth;
00038     } title;
00039 
00040     struct t_scaleData
00041     {
00042         bool isEnabled;
00043         const QwtScaleWidget *scaleWidget;
00044         QFont scaleFont;
00045         int start;
00046         int end;
00047         int baseLineOffset;
00048         int tickOffset; 
00049         int dimWithoutTitle;
00050     } scale[QwtPlot::axisCnt];
00051 
00052     struct t_canvasData
00053     {
00054         int frameWidth;
00055     } canvas;
00056 };
00057 
00058 /*
00059   Extract all layout relevant data from the plot components
00060 */
00061 
00062 void QwtPlotLayout::LayoutData::init(const QwtPlot *plot, const QRect &rect)
00063 {
00064     // legend
00065 
00066     if ( plot->legend() )
00067     {
00068         legend.frameWidth = plot->legend()->frameWidth();
00069         legend.vScrollBarWidth = 
00070             plot->legend()->verticalScrollBar()->sizeHint().width();
00071         legend.hScrollBarHeight = 
00072             plot->legend()->horizontalScrollBar()->sizeHint().height();
00073 
00074         const QSize hint = plot->legend()->sizeHint();
00075 
00076         int w = qwtMin(hint.width(), rect.width());
00077         int h = plot->legend()->heightForWidth(w);
00078         if ( h == 0 )
00079             h = hint.height();
00080 
00081         if ( h > rect.height() )
00082             w += legend.vScrollBarWidth;
00083 
00084         legend.hint = QSize(w, h);
00085     }
00086 
00087     // title 
00088 
00089     title.frameWidth = 0;
00090 
00091     if (plot->titleLabel() && !plot->titleLabel()->text().isEmpty())
00092     {
00093         const QwtTextLabel *label = plot->titleLabel();
00094         title.text = label->text(); 
00095         if ( !(title.text.paintAttributes() & QwtText::PaintUsingTextFont))
00096             title.text.setFont(label->font());
00097         
00098         title.frameWidth = plot->titleLabel()->frameWidth();
00099     }
00100 
00101     // scales 
00102 
00103     for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00104     {
00105         if ( plot->axisEnabled(axis) )
00106         {
00107             const QwtScaleWidget *scaleWidget = plot->axisWidget(axis);
00108 
00109             scale[axis].isEnabled = true;
00110 
00111             scale[axis].scaleWidget = scaleWidget;
00112 
00113             scale[axis].scaleFont = scaleWidget->font();
00114 
00115             scale[axis].start = scaleWidget->startBorderDist();
00116             scale[axis].end = scaleWidget->endBorderDist();
00117 
00118             scale[axis].baseLineOffset = scaleWidget->baseLineDist();
00119             scale[axis].tickOffset = scaleWidget->baseLineDist();
00120             if ( scaleWidget->scaleDraw()->hasComponent(
00121                 QwtAbstractScaleDraw::Ticks) )
00122             {
00123                 scale[axis].tickOffset += 
00124                     (int)scaleWidget->scaleDraw()->majTickLength();
00125             }
00126 
00127             scale[axis].dimWithoutTitle = scaleWidget->dimForLength(
00128                 QWIDGETSIZE_MAX, scale[axis].scaleFont);
00129 
00130             if ( !scaleWidget->title().isEmpty() )
00131             {
00132                 scale[axis].dimWithoutTitle -= 
00133                     scaleWidget->titleHeightForWidth(QWIDGETSIZE_MAX);
00134             }
00135         }
00136         else
00137         {
00138             scale[axis].isEnabled = false;
00139             scale[axis].start = 0;
00140             scale[axis].end = 0;
00141             scale[axis].baseLineOffset = 0;
00142             scale[axis].tickOffset = 0;
00143             scale[axis].dimWithoutTitle = 0;
00144         }
00145     }
00146 
00147     // canvas 
00148 
00149     canvas.frameWidth = plot->canvas()->frameWidth();
00150 }
00151 
00152 class QwtPlotLayout::PrivateData
00153 {
00154 public:
00155     PrivateData():
00156         margin(0),
00157         spacing(5),
00158         alignCanvasToScales(false)
00159     {
00160     }
00161 
00162     QRect titleRect;
00163     QRect legendRect;
00164     QRect scaleRect[QwtPlot::axisCnt];
00165     QRect canvasRect;
00166 
00167     QwtPlotLayout::LayoutData layoutData;
00168 
00169     QwtPlot::LegendPosition legendPos;
00170     double legendRatio;
00171     unsigned int margin;
00172     unsigned int spacing;
00173     unsigned int canvasMargin[QwtPlot::axisCnt];
00174     bool alignCanvasToScales;
00175 };
00176 
00181 QwtPlotLayout::QwtPlotLayout()
00182 {
00183     d_data = new PrivateData;
00184 
00185     setLegendPosition(QwtPlot::BottomLegend);
00186     setCanvasMargin(4);
00187 
00188     invalidate();
00189 }
00190 
00192 QwtPlotLayout::~QwtPlotLayout()
00193 {
00194     delete d_data;
00195 }
00196 
00206 void QwtPlotLayout::setMargin(int margin)
00207 {
00208     if ( margin < 0 )
00209         margin = 0;
00210     d_data->margin = margin;
00211 }
00212 
00219 int QwtPlotLayout::margin() const
00220 {
00221     return d_data->margin;
00222 }
00223 
00237 void QwtPlotLayout::setCanvasMargin(int margin, int axis)
00238 {
00239     if ( margin < -1 )
00240         margin = -1;
00241 
00242     if ( axis == -1 )
00243     {
00244         for (axis = 0; axis < QwtPlot::axisCnt; axis++)
00245             d_data->canvasMargin[axis] = margin;
00246     }
00247     else if ( axis >= 0 || axis < QwtPlot::axisCnt )
00248         d_data->canvasMargin[axis] = margin;
00249 }
00250 
00256 int QwtPlotLayout::canvasMargin(int axis) const
00257 {
00258     if ( axis < 0 || axis >= QwtPlot::axisCnt )
00259         return 0;
00260 
00261     return d_data->canvasMargin[axis];
00262 }
00263 
00264 
00278 void QwtPlotLayout::setAlignCanvasToScales(bool alignCanvasToScales)
00279 {
00280     d_data->alignCanvasToScales = alignCanvasToScales;
00281 }
00282 
00293 bool QwtPlotLayout::alignCanvasToScales() const
00294 {
00295     return d_data->alignCanvasToScales;
00296 }
00297 
00306 void QwtPlotLayout::setSpacing(int spacing)
00307 {
00308     d_data->spacing = qwtMax(0, spacing);
00309 }
00310 
00315 int QwtPlotLayout::spacing() const
00316 {
00317     return d_data->spacing;
00318 }
00319 
00334 void QwtPlotLayout::setLegendPosition(QwtPlot::LegendPosition pos, double ratio)
00335 {
00336     if ( ratio > 1.0 )
00337         ratio = 1.0;
00338 
00339     switch(pos)
00340     {
00341         case QwtPlot::TopLegend:
00342         case QwtPlot::BottomLegend:
00343             if ( ratio <= 0.0 )
00344                 ratio = 0.33;
00345             d_data->legendRatio = ratio;
00346             d_data->legendPos = pos;
00347             break;
00348         case QwtPlot::LeftLegend:
00349         case QwtPlot::RightLegend:
00350             if ( ratio <= 0.0 )
00351                 ratio = 0.5;
00352             d_data->legendRatio = ratio;
00353             d_data->legendPos = pos;
00354             break;
00355         default:
00356             break;
00357     }
00358 }
00359 
00368 void QwtPlotLayout::setLegendPosition(QwtPlot::LegendPosition pos)
00369 {
00370     setLegendPosition(pos, 0.0);
00371 }
00372 
00379 QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const
00380 {
00381     return d_data->legendPos;
00382 }
00383 
00395 void QwtPlotLayout::setLegendRatio(double ratio)
00396 {
00397     setLegendPosition(legendPosition(), ratio);
00398 }
00399 
00405 double QwtPlotLayout::legendRatio() const
00406 {
00407     return d_data->legendRatio;
00408 }
00409 
00415 const QRect &QwtPlotLayout::titleRect() const
00416 {
00417     return d_data->titleRect;
00418 }
00419 
00425 const QRect &QwtPlotLayout::legendRect() const
00426 {
00427     return d_data->legendRect;
00428 }
00429 
00436 const QRect &QwtPlotLayout::scaleRect(int axis) const
00437 {
00438     if ( axis < 0 || axis >= QwtPlot::axisCnt )
00439     {
00440         static QRect dummyRect;
00441         return dummyRect;
00442     }
00443     return d_data->scaleRect[axis];
00444 }
00445 
00451 const QRect &QwtPlotLayout::canvasRect() const
00452 {
00453     return d_data->canvasRect;
00454 }
00455 
00460 void QwtPlotLayout::invalidate()
00461 {
00462     d_data->titleRect = d_data->legendRect = d_data->canvasRect = QRect();
00463     for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00464         d_data->scaleRect[axis] = QRect();
00465 }
00466 
00472 QSize QwtPlotLayout::minimumSizeHint(const QwtPlot *plot) const
00473 {
00474     class ScaleData
00475     {
00476     public:
00477         ScaleData()
00478         {
00479             w = h = minLeft = minRight = tickOffset = 0;
00480         }
00481 
00482         int w;
00483         int h;
00484         int minLeft;
00485         int minRight;
00486         int tickOffset;
00487     } scaleData[QwtPlot::axisCnt];
00488 
00489     int canvasBorder[QwtPlot::axisCnt];
00490 
00491     int axis;
00492     for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
00493     {
00494         if ( plot->axisEnabled(axis) )
00495         {
00496             const QwtScaleWidget *scl = plot->axisWidget(axis);
00497             ScaleData &sd = scaleData[axis];
00498 
00499             const QSize hint = scl->minimumSizeHint();
00500             sd.w = hint.width(); 
00501             sd.h = hint.height(); 
00502             scl->getBorderDistHint(sd.minLeft, sd.minRight);
00503             sd.tickOffset = scl->baseLineDist();
00504             if ( scl->scaleDraw()->hasComponent(QwtAbstractScaleDraw::Ticks) )
00505                 sd.tickOffset += scl->scaleDraw()->majTickLength();
00506         }
00507 
00508         canvasBorder[axis] = plot->canvas()->frameWidth() +
00509             d_data->canvasMargin[axis] + 1;
00510             
00511     }
00512 
00513 
00514     for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
00515     {
00516         ScaleData &sd = scaleData[axis];
00517         if ( sd.w && (axis == QwtPlot::xBottom || axis == QwtPlot::xTop) )
00518         {
00519             if ( (sd.minLeft > canvasBorder[QwtPlot::yLeft]) 
00520                 && scaleData[QwtPlot::yLeft].w )
00521             {
00522                 int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft];
00523                 if ( shiftLeft > scaleData[QwtPlot::yLeft].w )
00524                     shiftLeft = scaleData[QwtPlot::yLeft].w;
00525 
00526                 sd.w -= shiftLeft;
00527             }
00528             if ( (sd.minRight > canvasBorder[QwtPlot::yRight]) 
00529                 && scaleData[QwtPlot::yRight].w )
00530             {
00531                 int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight];
00532                 if ( shiftRight > scaleData[QwtPlot::yRight].w )
00533                     shiftRight = scaleData[QwtPlot::yRight].w;
00534 
00535                 sd.w -= shiftRight;
00536             }
00537         }
00538 
00539         if ( sd.h && (axis == QwtPlot::yLeft || axis == QwtPlot::yRight) )
00540         {
00541             if ( (sd.minLeft > canvasBorder[QwtPlot::xBottom]) &&
00542                 scaleData[QwtPlot::xBottom].h )
00543             {
00544                 int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom];
00545                 if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset )
00546                     shiftBottom = scaleData[QwtPlot::xBottom].tickOffset;
00547 
00548                 sd.h -= shiftBottom;
00549             }
00550             if ( (sd.minLeft > canvasBorder[QwtPlot::xTop]) &&
00551                 scaleData[QwtPlot::xTop].h )
00552             {
00553                 int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop];
00554                 if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset )
00555                     shiftTop = scaleData[QwtPlot::xTop].tickOffset;
00556 
00557                 sd.h -= shiftTop;
00558             }
00559         }
00560     }
00561 
00562     const QwtPlotCanvas *canvas = plot->canvas();
00563 
00564     int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w
00565         + qwtMax(scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w)
00566         + 2 * (canvas->frameWidth() + 1);
00567     int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h 
00568         + qwtMax(scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h)
00569         + 2 * (canvas->frameWidth() + 1);
00570 
00571     const QwtTextLabel *title = plot->titleLabel();
00572     if (title && !title->text().isEmpty())
00573     {
00574         // If only QwtPlot::yLeft or QwtPlot::yRight is showing, 
00575         // we center on the plot canvas.
00576         const bool centerOnCanvas = !(plot->axisEnabled(QwtPlot::yLeft) 
00577             && plot->axisEnabled(QwtPlot::yRight));
00578 
00579         int titleW = w;
00580         if ( centerOnCanvas )
00581         {
00582             titleW -= scaleData[QwtPlot::yLeft].w 
00583                 + scaleData[QwtPlot::yRight].w;
00584         }
00585 
00586         int titleH = title->heightForWidth(titleW);
00587         if ( titleH > titleW ) // Compensate for a long title
00588         {
00589             w = titleW = titleH;
00590             if ( centerOnCanvas )
00591             {
00592                 w += scaleData[QwtPlot::yLeft].w
00593                     + scaleData[QwtPlot::yRight].w;
00594             }
00595 
00596             titleH = title->heightForWidth(titleW);
00597         }
00598         h += titleH + d_data->spacing;
00599     }
00600 
00601     // Compute the legend contribution
00602 
00603     const QwtLegend *legend = plot->legend();
00604     if ( legend && !legend->isEmpty() )
00605     {
00606         if ( d_data->legendPos == QwtPlot::LeftLegend 
00607             || d_data->legendPos == QwtPlot::RightLegend )
00608         {
00609             int legendW = legend->sizeHint().width();
00610             int legendH = legend->heightForWidth(legendW); 
00611 
00612             if ( legend->frameWidth() > 0 )
00613                 w += d_data->spacing;
00614 
00615             if ( legendH > h )
00616                 legendW += legend->verticalScrollBar()->sizeHint().height();
00617 
00618             if ( d_data->legendRatio < 1.0 )
00619                 legendW = qwtMin(legendW, int(w / (1.0 - d_data->legendRatio)));
00620 
00621             w += legendW;
00622         }
00623         else // QwtPlot::Top, QwtPlot::Bottom
00624         {
00625             int legendW = qwtMin(legend->sizeHint().width(), w);
00626             int legendH = legend->heightForWidth(legendW); 
00627 
00628             if ( legend->frameWidth() > 0 )
00629                 h += d_data->spacing;
00630 
00631             if ( d_data->legendRatio < 1.0 )
00632                 legendH = qwtMin(legendH, int(h / (1.0 - d_data->legendRatio)));
00633             
00634             h += legendH;
00635         }
00636     }
00637 
00638     w += 2 * d_data->margin;
00639     h += 2 * d_data->margin;
00640 
00641     return QSize( w, h );
00642 }
00643 
00651 QRect QwtPlotLayout::layoutLegend(int options, 
00652     const QRect &rect) const
00653 {
00654     const QSize hint(d_data->layoutData.legend.hint);
00655 
00656     int dim;
00657     if ( d_data->legendPos == QwtPlot::LeftLegend 
00658         || d_data->legendPos == QwtPlot::RightLegend )
00659     {
00660         // We don't allow vertical legends to take more than
00661         // half of the available space.
00662 
00663         dim = qwtMin(hint.width(), int(rect.width() * d_data->legendRatio));
00664 
00665         if ( !(options & IgnoreScrollbars) )
00666         {
00667             if ( hint.height() > rect.height() )
00668             {
00669                 // The legend will need additional
00670                 // space for the vertical scrollbar. 
00671 
00672                 dim += d_data->layoutData.legend.vScrollBarWidth;
00673             }
00674         }
00675     }
00676     else
00677     {
00678         dim = qwtMin(hint.height(), int(rect.height() * d_data->legendRatio));
00679         dim = qwtMax(dim, d_data->layoutData.legend.hScrollBarHeight);
00680     }
00681 
00682     QRect legendRect = rect;
00683     switch(d_data->legendPos)
00684     {
00685         case QwtPlot::LeftLegend:
00686             legendRect.setWidth(dim);
00687             break;
00688         case QwtPlot::RightLegend:
00689             legendRect.setX(rect.right() - dim + 1);
00690             legendRect.setWidth(dim);
00691             break;
00692         case QwtPlot::TopLegend:
00693             legendRect.setHeight(dim);
00694             break;
00695         case QwtPlot::BottomLegend:
00696             legendRect.setY(rect.bottom() - dim + 1);
00697             legendRect.setHeight(dim);
00698             break;
00699     }
00700 
00701     return legendRect;
00702 }
00703 
00710 QRect QwtPlotLayout::alignLegend(const QRect &canvasRect, 
00711     const QRect &legendRect) const
00712 {
00713     QRect alignedRect = legendRect;
00714 
00715     if ( d_data->legendPos == QwtPlot::BottomLegend 
00716         || d_data->legendPos == QwtPlot::TopLegend )
00717     {
00718         if ( d_data->layoutData.legend.hint.width() < canvasRect.width() )
00719         {
00720             alignedRect.setX(canvasRect.x());
00721             alignedRect.setWidth(canvasRect.width());
00722         }
00723     }
00724     else
00725     {
00726         if ( d_data->layoutData.legend.hint.height() < canvasRect.height() )
00727         {
00728             alignedRect.setY(canvasRect.y());
00729             alignedRect.setHeight(canvasRect.height());
00730         }
00731     }
00732 
00733     return alignedRect;
00734 }
00735 
00745 void QwtPlotLayout::expandLineBreaks(int options, const QRect &rect, 
00746     int &dimTitle, int dimAxis[QwtPlot::axisCnt]) const
00747 {
00748     dimTitle = 0;
00749     for ( int i = 0; i < QwtPlot::axisCnt; i++ )
00750         dimAxis[i] = 0;
00751 
00752     bool done = false;
00753     while (!done)
00754     {
00755         done = true;
00756 
00757         // the size for the 4 axis depend on each other. Expanding
00758         // the height of a horizontal axis will shrink the height
00759         // for the vertical axis, shrinking the height of a vertical
00760         // axis will result in a line break what will expand the
00761         // width and results in shrinking the width of a horizontal
00762         // axis what might result in a line break of a horizontal
00763         // axis ... . So we loop as long until no size changes.
00764 
00765         if ( !d_data->layoutData.title.text.isEmpty() )
00766         {
00767             int w = rect.width();
00768 
00769             if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled
00770                 != d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
00771             {
00772                 // center to the canvas
00773                 w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight]; 
00774             }
00775 
00776             int d = d_data->layoutData.title.text.heightForWidth(w);
00777             if ( !(options & IgnoreFrames) )
00778                 d += 2 * d_data->layoutData.title.frameWidth;
00779 
00780             if ( d > dimTitle )
00781             {
00782                 dimTitle = d;
00783                 done = false;
00784             }
00785         }
00786 
00787         for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
00788         {
00789             int backboneOffset = d_data->canvasMargin[axis];
00790             if ( !(options & IgnoreFrames) )
00791                 backboneOffset += d_data->layoutData.canvas.frameWidth;
00792 
00793             const struct LayoutData::t_scaleData &scaleData = 
00794                 d_data->layoutData.scale[axis];
00795 
00796             if (scaleData.isEnabled)
00797             {
00798                 int length;
00799                 if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
00800                 {
00801                     length = rect.width() - dimAxis[QwtPlot::yLeft] 
00802                         - dimAxis[QwtPlot::yRight];
00803                     length += qwtMin(dimAxis[QwtPlot::yLeft], 
00804                         scaleData.start - backboneOffset);
00805                     length += qwtMin(dimAxis[QwtPlot::yRight], 
00806                         scaleData.end - backboneOffset);
00807                 }
00808                 else // QwtPlot::yLeft, QwtPlot::yRight
00809                 {
00810                     length = rect.height() - dimAxis[QwtPlot::xTop] 
00811                         - dimAxis[QwtPlot::xBottom];
00812 
00813                     if ( dimAxis[QwtPlot::xBottom] > 0 )
00814                     {
00815                         length += qwtMin(
00816                             d_data->layoutData.scale[QwtPlot::xBottom].tickOffset, 
00817                             scaleData.start - backboneOffset);
00818                     }
00819                     if ( dimAxis[QwtPlot::xTop] > 0 )
00820                     {
00821                         length += qwtMin(
00822                             d_data->layoutData.scale[QwtPlot::xTop].tickOffset, 
00823                             scaleData.end - backboneOffset);
00824                     }
00825 
00826                     if ( dimTitle > 0 )
00827                         length -= dimTitle + d_data->spacing;
00828                 }
00829 
00830                 int d = scaleData.dimWithoutTitle;
00831                 if ( !scaleData.scaleWidget->title().isEmpty() )
00832                 {
00833                     d += scaleData.scaleWidget->titleHeightForWidth(length);
00834                 }
00835 
00836                 if ( d > dimAxis[axis] )
00837                 {
00838                     dimAxis[axis] = d;
00839                     done = false;
00840                 }
00841             }
00842         }
00843     }
00844 }
00845 
00851 void QwtPlotLayout::alignScales(int options,
00852     QRect &canvasRect, QRect scaleRect[QwtPlot::axisCnt]) const
00853 {
00854     int axis;
00855 
00856     int backboneOffset[QwtPlot::axisCnt];
00857     for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
00858     {
00859         backboneOffset[axis] = 0;
00860         if ( !d_data->alignCanvasToScales )
00861             backboneOffset[axis] += d_data->canvasMargin[axis];
00862         if ( !(options & IgnoreFrames) )
00863             backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
00864     }
00865 
00866     for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
00867     {
00868         if ( !scaleRect[axis].isValid() )
00869             continue;
00870 
00871         const int startDist = d_data->layoutData.scale[axis].start;
00872         const int endDist = d_data->layoutData.scale[axis].end;
00873 
00874         QRect &axisRect = scaleRect[axis];
00875 
00876         if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
00877         {
00878             const int leftOffset = backboneOffset[QwtPlot::yLeft] - startDist;
00879 
00880             if ( scaleRect[QwtPlot::yLeft].isValid() )
00881             {
00882                 int minLeft = scaleRect[QwtPlot::yLeft].left();
00883                 int left = axisRect.left() + leftOffset;
00884                 axisRect.setLeft(qwtMax(left, minLeft));
00885             }
00886             else
00887             {
00888                 if ( d_data->alignCanvasToScales )
00889                 {
00890                     canvasRect.setLeft(qwtMax(canvasRect.left(), 
00891                         axisRect.left() - leftOffset));
00892                 }
00893                 else
00894                 {
00895                     if ( leftOffset > 0 )
00896                         axisRect.setLeft(axisRect.left() + leftOffset);
00897                 }
00898             }
00899 
00900             const int rightOffset = backboneOffset[QwtPlot::yRight] - endDist;
00901 
00902             if ( scaleRect[QwtPlot::yRight].isValid() )
00903             {
00904                 int maxRight = scaleRect[QwtPlot::yRight].right();
00905                 int right = axisRect.right() - rightOffset;
00906                 axisRect.setRight(qwtMin(right, maxRight));
00907             }
00908             else
00909             {
00910                 if ( d_data->alignCanvasToScales )
00911                 {
00912                     canvasRect.setRight( qwtMin(canvasRect.right(), 
00913                         axisRect.right() + rightOffset) );
00914                 }
00915                 else
00916                 {
00917                     if ( rightOffset > 0 )
00918                         axisRect.setRight(axisRect.right() - rightOffset);
00919                 }
00920             }
00921         }
00922         else // QwtPlot::yLeft, QwtPlot::yRight
00923         {
00924             const int bottomOffset = 
00925                 backboneOffset[QwtPlot::xBottom] - startDist;
00926 
00927             if ( scaleRect[QwtPlot::xBottom].isValid() )
00928             {
00929                 int maxBottom = scaleRect[QwtPlot::xBottom].top() + 
00930                     d_data->layoutData.scale[QwtPlot::xBottom].tickOffset;
00931 
00932                 int bottom = axisRect.bottom() - bottomOffset;
00933                 axisRect.setBottom(qwtMin(bottom, maxBottom));
00934             }
00935             else
00936             {
00937                 if ( d_data->alignCanvasToScales )
00938                 {
00939                     canvasRect.setBottom(qwtMin(canvasRect.bottom(), 
00940                         axisRect.bottom() + bottomOffset));
00941                 }
00942                 else
00943                 {
00944                     if ( bottomOffset > 0 )
00945                         axisRect.setBottom(axisRect.bottom() - bottomOffset);
00946                 }
00947             }
00948         
00949             const int topOffset = backboneOffset[QwtPlot::xTop] - endDist;
00950 
00951             if ( scaleRect[QwtPlot::xTop].isValid() )
00952             {
00953                 int minTop = scaleRect[QwtPlot::xTop].bottom() -
00954                     d_data->layoutData.scale[QwtPlot::xTop].tickOffset;
00955 
00956                 int top = axisRect.top() + topOffset;
00957                 axisRect.setTop(qwtMax(top, minTop));
00958             }
00959             else
00960             {
00961                 if ( d_data->alignCanvasToScales )
00962                 {
00963                     canvasRect.setTop(qwtMax(canvasRect.top(), 
00964                         axisRect.top() + - topOffset));
00965                 }
00966                 else
00967                 {
00968                     if ( topOffset > 0 )
00969                         axisRect.setTop(axisRect.top() + topOffset);
00970                 }
00971             }
00972         }
00973     }
00974 }
00975 
00988 void QwtPlotLayout::activate(const QwtPlot *plot,
00989     const QRect &plotRect, int options) 
00990 {
00991     invalidate();
00992 
00993     QRect rect(plotRect);  // undistributed rest of the plot rect
00994 
00995     if ( !(options & IgnoreMargin) )
00996     {
00997         // subtract the margin
00998 
00999         rect.setRect(
01000             rect.x() + d_data->margin, 
01001             rect.y() + d_data->margin,
01002             rect.width() - 2 * d_data->margin, 
01003             rect.height() - 2 * d_data->margin
01004         );
01005     }
01006 
01007     // We extract all layout relevant data from the widgets,
01008     // filter them through pfilter and save them to d_data->layoutData.
01009 
01010     d_data->layoutData.init(plot, rect);
01011 
01012     if (!(options & IgnoreLegend)
01013         && plot->legend() && !plot->legend()->isEmpty() )
01014     {
01015         d_data->legendRect = layoutLegend(options, rect);
01016 
01017         // subtract d_data->legendRect from rect
01018 
01019         const QRegion region(rect);
01020         rect = region.subtract(d_data->legendRect).boundingRect(); 
01021 
01022         if ( d_data->layoutData.legend.frameWidth && 
01023             !(options & IgnoreFrames ) )
01024         {
01025             // In case of a frame we have to insert a spacing.
01026             // Otherwise the leading of the font separates
01027             // legend and scale/canvas
01028 
01029             switch(d_data->legendPos)
01030             {
01031                 case QwtPlot::LeftLegend:
01032                     rect.setLeft(rect.left() + d_data->spacing);
01033                     break;
01034                 case QwtPlot::RightLegend:
01035                     rect.setRight(rect.right() - d_data->spacing);
01036                     break;
01037                 case QwtPlot::TopLegend:
01038                     rect.setTop(rect.top() + d_data->spacing);
01039                     break;
01040                 case QwtPlot::BottomLegend:
01041                     rect.setBottom(rect.bottom() - d_data->spacing);
01042                     break;
01043             }
01044         }
01045     }
01046 
01047     /*
01048      +---+-----------+---+
01049      |       Title       |
01050      +---+-----------+---+
01051      |   |   Axis    |   |
01052      +---+-----------+---+
01053      | A |           | A |
01054      | x |  Canvas   | x |
01055      | i |           | i |
01056      | s |           | s |
01057      +---+-----------+---+
01058      |   |   Axis    |   |
01059      +---+-----------+---+
01060     */
01061 
01062 
01063     // axes and title include text labels. The height of each
01064     // label depends on its line breaks, that depend on the width
01065     // for the label. A line break in a horizontal text will reduce
01066     // the available width for vertical texts and vice versa. 
01067     // expandLineBreaks finds the height/width for title and axes
01068     // including all line breaks.
01069 
01070     int dimTitle, dimAxes[QwtPlot::axisCnt];
01071     expandLineBreaks(options, rect, dimTitle, dimAxes);
01072 
01073     if (dimTitle > 0 )
01074     {
01075         d_data->titleRect = QRect(rect.x(), rect.y(),
01076             rect.width(), dimTitle);
01077 
01078         if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled !=
01079             d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
01080         {
01081             // if only one of the y axes is missing we align
01082             // the title centered to the canvas
01083 
01084             d_data->titleRect.setX(rect.x() + dimAxes[QwtPlot::yLeft]);
01085             d_data->titleRect.setWidth(rect.width() 
01086                 - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight]);
01087         }
01088 
01089         // subtract title 
01090         rect.setTop(rect.top() + dimTitle + d_data->spacing);
01091     }
01092 
01093     d_data->canvasRect.setRect(
01094         rect.x() + dimAxes[QwtPlot::yLeft],
01095         rect.y() + dimAxes[QwtPlot::xTop],
01096         rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
01097         rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop]);
01098 
01099     for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
01100     {
01101         // set the rects for the axes
01102 
01103         if ( dimAxes[axis] )
01104         {
01105             int dim = dimAxes[axis];
01106             QRect &scaleRect = d_data->scaleRect[axis];
01107 
01108             scaleRect = d_data->canvasRect;
01109             switch(axis)
01110             {
01111                 case QwtPlot::yLeft:
01112                     scaleRect.setX(d_data->canvasRect.left() - dim);
01113                     scaleRect.setWidth(dim);
01114                     break;
01115                 case QwtPlot::yRight:
01116                     scaleRect.setX(d_data->canvasRect.right() + 1);
01117                     scaleRect.setWidth(dim);
01118                     break;
01119                 case QwtPlot::xBottom:
01120                     scaleRect.setY(d_data->canvasRect.bottom() + 1);
01121                     scaleRect.setHeight(dim);
01122                     break;
01123                 case QwtPlot::xTop:
01124                     scaleRect.setY(d_data->canvasRect.top() - dim);
01125                     scaleRect.setHeight(dim);
01126                     break;
01127             }
01128 #if QT_VERSION < 0x040000
01129             scaleRect = scaleRect.normalize();
01130 #else
01131             scaleRect = scaleRect.normalized();
01132 #endif
01133         }
01134     }
01135 
01136     // +---+-----------+---+
01137     // |  <-   Axis   ->   |
01138     // +-^-+-----------+-^-+
01139     // | | |           | | |
01140     // |   |           |   |
01141     // | A |           | A |
01142     // | x |  Canvas   | x |
01143     // | i |           | i |
01144     // | s |           | s |
01145     // |   |           |   |
01146     // | | |           | | |
01147     // +-V-+-----------+-V-+
01148     // |   <-  Axis   ->   |
01149     // +---+-----------+---+
01150 
01151     // The ticks of the axes - not the labels above - should
01152     // be aligned to the canvas. So we try to use the empty
01153     // corners to extend the axes, so that the label texts
01154     // left/right of the min/max ticks are moved into them.
01155  
01156     alignScales(options, d_data->canvasRect, d_data->scaleRect);
01157 
01158     if (!d_data->legendRect.isEmpty() )
01159     {
01160         // We prefer to align the legend to the canvas - not to
01161         // the complete plot - if possible.
01162 
01163         d_data->legendRect = alignLegend(d_data->canvasRect, d_data->legendRect);
01164     }
01165 }

Generated on Mon Jan 30 22:16:25 2006 for Qwt User's Guide by  doxygen 1.4.4