Qwt User's Guide: qwt_plot_layout.cpp Source File

- Main Page
- Classes
- Files
- Related Pages

- File List
- File Members

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