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

Generated on Wed Aug 31 23:02:29 2005 for Qwt User's Guide by  doxygen 1.4.1