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 }

Generated on Sun Mar 22 16:54:07 2009 for Qwt User's Guide by  doxygen 1.5.0