qwt_plot_layout.cpp

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

Generated on Mon Feb 26 21:22:37 2007 for Qwt User's Guide by  doxygen 1.4.6