Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

qwt_scale_draw.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 <stdio.h>
00013 #include <qpainter.h>
00014 #include <qpalette.h>
00015 #include <qwidget.h>
00016 #include "qwt_math.h"
00017 #include "qwt_painter.h"
00018 #include "qwt_layout_metrics.h"
00019 #include "qwt_scale_div.h"
00020 #include "qwt_scale_draw.h"
00021 #if QT_VERSION < 0x040000
00022 #include <qwmatrix.h>
00023 #define QwtMatrix QWMatrix
00024 #else
00025 #include <qmatrix.h>
00026 #define QwtMatrix QMatrix
00027 #endif
00028 
00029 class QwtScaleDraw::PrivateData
00030 {
00031 public:
00032     PrivateData():
00033         options(QwtScaleDraw::Backbone),
00034         hpad(4),
00035         vpad(4),
00036         medLen(6),
00037         majLen(8),
00038         minLen(4),
00039         minAngle(-135 * 16),
00040         maxAngle(135 * 16),
00041         fmt('g'),
00042         prec(4),
00043         fieldwidth(0),
00044         labelFlags(0),
00045         labelRotation(0.0)
00046     {
00047         // snprintf is C99 and therefore not portable :-(
00048         // fieldwidth and precision must be in the range 0, 1, .., 99.
00049         sprintf(formatBuffer, "%%%d.%d%c", fieldwidth, prec, fmt);
00050     }
00051 
00052     int options;
00053     
00054     QwtScaleMap map;
00055     QwtScaleDiv scldiv;
00056     QwtScaleDraw::Orientation orient;
00057         
00058     int xorg;
00059     int yorg;
00060     int len;
00061         
00062     unsigned int hpad;
00063     unsigned int vpad;
00064 
00065     unsigned int medLen;
00066     unsigned int majLen;
00067     unsigned int minLen;
00068 
00069     int minAngle;
00070     int maxAngle;
00071 
00072     double xCenter;
00073     double yCenter;
00074     double radius;
00075 
00076     char fmt;
00077     int prec;
00078     int fieldwidth;
00079 
00080     int labelFlags;
00081     double labelRotation;
00082 
00083     // formatBuffer must be able to hold:
00084     // - a percent sign a '%'
00085     // - a two digit positive fieldwidth
00086     // - a point
00087     // - a two digit positive precision
00088     // - a format character ('e', 'f', 'g', 'E', 'F, 'G')
00089     // - a terminating '/0' character
00090     char formatBuffer[8];
00091 };
00092 
00101 QwtScaleDraw::QwtScaleDraw()
00102 {
00103     d_data = new QwtScaleDraw::PrivateData;
00104     setGeometry(0,0,100,Bottom);
00105 }
00106 
00107 QwtScaleDraw::QwtScaleDraw(const QwtScaleDraw &other)
00108 {
00109     d_data = new QwtScaleDraw::PrivateData(*other.d_data);
00110 }
00111 
00112 
00114 QwtScaleDraw::~QwtScaleDraw()
00115 {
00116     delete d_data;
00117 }
00118 
00119 QwtScaleDraw &QwtScaleDraw::operator=(const QwtScaleDraw &other)
00120 {
00121     *d_data = *other.d_data;
00122     return *this;
00123 }
00124 
00126 void QwtScaleDraw::setOptions(int opt)
00127 {
00128     d_data->options = opt;
00129 }
00130 
00134 int QwtScaleDraw::options() const
00135 {
00136     return d_data->options;
00137 }
00138 
00143 void QwtScaleDraw::setScaleDiv(const QwtScaleDiv &sd)
00144 {
00145     d_data->scldiv = sd;
00146     d_data->map.setScaleInterval(sd.lBound(), sd.hBound());
00147 }
00148 
00149 void QwtScaleDraw::setTransformation(
00150     const QwtScaleTransformation &transformation)
00151 {
00152     d_data->map.setTransformation(transformation);
00153 }
00154 
00155 const QwtScaleMap &QwtScaleDraw::map() const
00156 {
00157     return d_data->map;
00158 }
00159 
00161 const QwtScaleDiv& QwtScaleDraw::scaleDiv() const 
00162 { 
00163     return d_data->scldiv; 
00164 }
00165 
00178 #if QT_VERSION < 0x040000
00179 void QwtScaleDraw::draw(QPainter *painter, const QColorGroup& colorGroup) const
00180 #else
00181 void QwtScaleDraw::draw(QPainter *painter, const QPalette& palette) const
00182 #endif
00183 {
00184     uint i;
00185 
00186     QPen pen = painter->pen();
00187 
00188 #if QT_VERSION < 0x040000
00189     painter->setPen(colorGroup.text()); // ignore pen style
00190 #else
00191     painter->setPen(palette.color(QPalette::Text)); // ignore pen style
00192 #endif
00193 
00194     const QwtTickList &majorTicks = 
00195         d_data->scldiv.ticks(QwtScaleDiv::MajorTick);
00196 
00197     for (i=0; i< (uint)majorTicks.count(); i++)
00198     {
00199         const double v = majorTicks[i];
00200         if ( d_data->scldiv.contains(v) )
00201             drawLabel(painter, majorTicks[i]);
00202     }
00203 
00204 #if QT_VERSION < 0x040000
00205     pen.setColor(colorGroup.foreground()); // respect pen style
00206 #else
00207     pen.setColor(palette.color(QPalette::Foreground)); // respect pen style
00208 #endif
00209 
00210     int tickLength[QwtScaleDiv::NTickTypes];
00211     tickLength[QwtScaleDiv::MinorTick] = d_data->minLen;
00212     tickLength[QwtScaleDiv::MediumTick] = d_data->medLen;
00213     tickLength[QwtScaleDiv::MajorTick] = d_data->majLen;
00214 
00215     for ( int tickType = QwtScaleDiv::MinorTick; 
00216         tickType < QwtScaleDiv::NTickTypes; tickType++ )
00217     {
00218         const QwtTickList &ticks = d_data->scldiv.ticks(tickType);
00219         for (i=0; i < (uint)ticks.count(); i++)
00220         {
00221             const double v = ticks[i];
00222             if ( d_data->scldiv.contains(v) )
00223                 drawTick(painter, ticks[i], tickLength[tickType]);
00224         }
00225     }
00226 
00227     if ( options() & Backbone )
00228         drawBackbone(painter);
00229 }
00230 
00231 
00233 void QwtScaleDraw::drawTick(QPainter *painter, double val, int len) const
00234 {
00235     if ( len <= 0 )
00236         return;
00237 
00238     const int tval = map().transform(val);
00239 
00240     switch(d_data->orient)
00241     {
00242         case Left:
00243             QwtPainter::drawLine(painter, d_data->xorg, tval, 
00244                 d_data->xorg - len, tval);
00245             break;
00246 
00247         case Right:
00248             QwtPainter::drawLine(painter, d_data->xorg, tval, 
00249                 d_data->xorg + len, tval);
00250             break;
00251 
00252         case Bottom: 
00253             QwtPainter::drawLine(painter, tval, d_data->yorg, 
00254                 tval, d_data->yorg + len);
00255             break;
00256 
00257         case Top:
00258             QwtPainter::drawLine(painter, tval, d_data->yorg, 
00259                 tval, d_data->yorg - len);
00260             break;
00261 
00262         case Round:
00263             if ((tval <= d_data->minAngle + 359 * 16) 
00264                 || (tval >= d_data->minAngle - 359 * 16))
00265             {
00266                 const double arc = double(tval) / 16.0 * M_PI / 180.0;
00267                 const int x1 = qRound( d_data->xCenter + sin(arc) 
00268                     * d_data->radius);
00269                 const int x2 = qRound(d_data->xCenter + sin(arc) 
00270                     * (d_data->radius + double(len)));
00271                 const int y1 = qRound(d_data->yCenter - cos(arc) 
00272                     * d_data->radius);
00273                 const int y2 = qRound(d_data->yCenter - cos(arc) 
00274                     * (d_data->radius + double(len)));
00275 
00276                 QwtPainter::drawLine(painter, x1, y1, x2, y2);
00277             }
00278             break;
00279     }
00280 }
00281 
00283 void QwtScaleDraw::drawLabel(QPainter *painter, double val) const
00284 {
00285     QPoint pos;
00286     int flags;
00287     double rotation;
00288     labelPlacement(QFontMetrics(painter->font()), val, pos, flags, rotation);
00289 
00290     if ( flags )
00291     {
00292         const QString txt = label(val);
00293         if ( !txt.isEmpty() )
00294         {
00295             QwtMatrix m = labelWorldMatrix(QFontMetrics(painter->font()),
00296                 pos, flags, rotation, txt);
00297 
00298             painter->save();
00299 #ifndef QT_NO_TRANSFORMATIONS
00300 #if QT_VERSION < 0x040000
00301             painter->setWorldMatrix(m, true);
00302 #else
00303             painter->setMatrix(m, true);
00304 #endif
00305 #else
00306             painter->translate(m.dx(), m.dy());
00307 #endif
00308             QwtPainter::drawText(painter, 0, 0, txt);
00309             painter->restore();
00310         }
00311     }
00312 }
00313 
00315 void QwtScaleDraw::labelPlacement( const QFontMetrics &fm, double val, 
00316     QPoint &pos, int &flags, double &rotation) const
00317 {
00318     const int tval = map().transform(val);
00319 
00320     int x = 0;
00321     int y = 0;
00322     int flgs = 0;
00323 
00324     switch(d_data->orient)
00325     {
00326         case Right:
00327         {
00328             x = d_data->xorg + d_data->majLen + d_data->hpad + 1;
00329             y = tval;
00330             flgs = d_data->labelFlags;
00331             if ( flgs == 0 )
00332                 flgs = Qt::AlignRight | Qt::AlignVCenter;
00333             break;
00334         }
00335         case Left:
00336         {
00337             x = d_data->xorg - d_data->majLen - d_data->hpad - 1;
00338             y = tval;
00339             flgs = d_data->labelFlags;
00340             if ( flgs == 0 )
00341                 flgs = Qt::AlignLeft | Qt::AlignVCenter;
00342             break;
00343         }
00344         case Bottom:
00345         {
00346             x = tval;
00347             y = d_data->yorg + d_data->majLen + d_data->vpad + 1;
00348             flgs = d_data->labelFlags;
00349             if ( flgs == 0 )
00350                 flgs = Qt::AlignHCenter | Qt::AlignBottom;
00351             break;
00352         }
00353         case Top:
00354         {
00355             x = tval;
00356             y = d_data->yorg - d_data->majLen - d_data->vpad - 1;
00357             flgs = d_data->labelFlags;
00358             if ( flgs == 0 )
00359                 flgs = Qt::AlignHCenter | Qt::AlignTop;
00360             break;
00361         }
00362         case Round:
00363         {
00364             if ((tval > d_data->minAngle + 359 * 16) 
00365                 || (tval < d_data->minAngle - 359 * 16))
00366             {
00367                break;
00368             }
00369             
00370             const int fmh = fm.ascent() - 2; 
00371             const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
00372             const double radius = d_data->radius + d_data->majLen + d_data->vpad;
00373 
00374             // First we find the point on a circle enlarged
00375             // by half of the font height.
00376 
00377             double xOffset = ( radius + fmh / 2 ) * sin(arc); 
00378             double yOffset = ( radius + fmh / 2 ) * cos(arc);
00379 
00380             if ( qRound(xOffset) != 0 ) 
00381             {
00382                 // The centered label might cut the circle 
00383                 // with distance: d_data->radius + d_data->majLen + d_data->vpad
00384                 // We align the label to the circle by moving
00385                 // the x-coordinate, because we have only
00386                 // horizontal labels here.
00387 
00388                 const int fmw = fm.width(label(val));
00389 
00390                 const double circleX = radius * sin(arc); 
00391                 if ( xOffset < 0 )
00392                     xOffset = circleX - fmw / 2; // left
00393                 else
00394                     xOffset = circleX + fmw / 2; // right
00395             }
00396             x = qRound(d_data->xCenter + xOffset);
00397             y = qRound(d_data->yCenter - yOffset);
00398             flgs = Qt::AlignHCenter | Qt::AlignVCenter;
00399 
00400             break;
00401         }
00402     }
00403 
00404     pos = QPoint(x, y);
00405     flags = flgs;
00406     rotation = d_data->labelRotation;
00407 }
00408 
00410 QwtMatrix QwtScaleDraw::labelWorldMatrix(const QFontMetrics &fm,
00411     const QPoint &pos, int flags, 
00412 #ifdef QT_NO_TRANSFORMATIONS
00413     double,
00414 #else
00415     double rotation, 
00416 #endif
00417     const QString &txt) const
00418 {
00419     const int w = fm.boundingRect(0, 0, 
00420         QWIDGETSIZE_MAX, QWIDGETSIZE_MAX, 0, txt).width() - 2;
00421     const int h = fm.ascent() - 2;
00422     
00423     int x, y;
00424     if ( flags & Qt::AlignLeft )
00425         x = -w;
00426     else if ( flags & Qt::AlignRight )
00427         x = 0 - w % 2;
00428     else // Qt::AlignHCenter
00429         x = -(w / 2);
00430         
00431     if ( flags & Qt::AlignTop )
00432         y = 0;
00433     else if ( flags & Qt::AlignBottom )
00434         y = h - 1;
00435     else // Qt::AlignVCenter
00436         y = h / 2;
00437     
00438     QwtMatrix m;
00439     m.translate(pos.x(), pos.y());
00440 #ifndef QT_NO_TRANSFORMATIONS
00441     m.rotate(rotation);
00442 #endif
00443     m.translate(x, y);
00444 
00445     return m;
00446 }
00447 
00449 void QwtScaleDraw::drawBackbone(QPainter *painter) const
00450 {
00451     const int bw2 = painter->pen().width() / 2;
00452     
00453     switch(d_data->orient)
00454     {
00455         case Left:
00456             QwtPainter::drawLine(painter, d_data->xorg - bw2, 
00457                 d_data->yorg, d_data->xorg - bw2, d_data->yorg + d_data->len - 1);
00458             break;
00459         case Right:
00460             QwtPainter::drawLine(painter, d_data->xorg + bw2, 
00461                 d_data->yorg, d_data->xorg + bw2, d_data->yorg + d_data->len - 1);
00462             break;
00463         case Top:
00464             QwtPainter::drawLine(painter, d_data->xorg, d_data->yorg - bw2, 
00465                 d_data->xorg + d_data->len - 1, d_data->yorg - bw2);
00466             break;
00467         case Bottom:
00468             QwtPainter::drawLine(painter, d_data->xorg, d_data->yorg + bw2, 
00469                 d_data->xorg + d_data->len - 1, d_data->yorg + bw2);
00470             break;
00471         case Round:
00472         {
00473             const int a1 = qRound(qwtMin(map().p1(), map().p2()) - 90 * 16); 
00474             const int a2 = qRound(qwtMax(map().p1(), map().p2()) - 90 * 16); 
00475             
00476             painter->drawArc(d_data->xorg, d_data->yorg, d_data->len, 
00477                 d_data->len, -a2, a2 - a1 + 1);           // counterclockwise
00478             break;
00479         }
00480     }
00481 }
00482 
00483 
00523 void QwtScaleDraw::setGeometry(int xorigin, int yorigin, 
00524     int length, Orientation o)
00525 {
00526     static int minLen = 10;
00527 
00528     d_data->xorg = xorigin;
00529     d_data->yorg = yorigin;
00530     d_data->radius = double(length) * 0.5;
00531     d_data->xCenter = double(xorigin) + double(length) * 0.5;
00532     d_data->yCenter = double(yorigin) + double(length) * 0.5;
00533     
00534     if (length > minLen)
00535        d_data->len = length;
00536     else
00537        d_data->len = minLen;
00538     
00539     d_data->orient = o;
00540     
00541     switch(d_data->orient)
00542     {
00543         case Left:
00544         case Right:
00545             d_data->map.setPaintInterval(d_data->yorg + d_data->len - 1, d_data->yorg);
00546             break;
00547         case Round:
00548             d_data->map.setPaintInterval(d_data->minAngle, d_data->maxAngle);
00549             break;
00550         case Top:
00551         case Bottom:
00552             d_data->map.setPaintInterval(d_data->xorg, d_data->xorg + d_data->len - 1);
00553             break;
00554     }
00555 }
00556 
00562 int QwtScaleDraw::maxWidth(const QPen &pen, const QFont &font) const
00563 {
00564     int w = 0;
00565 
00566     switch (d_data->orient)
00567     {
00568         case Left:
00569         case Right:
00570             w += pen.width() + d_data->majLen 
00571                     + d_data->hpad + maxLabelWidth(font);
00572             break;
00573         case Round:
00574             w += pen.width() + d_data->majLen 
00575                     + d_data->vpad + maxLabelWidth(font);
00576             break;
00577         case Top:
00578         case Bottom:
00579             w = d_data->len + maxLabelWidth(font);
00580             break;
00581     }
00582     return w;
00583 }
00584 
00590 int QwtScaleDraw::maxHeight(const QPen &pen, const QFont &font) const 
00591 {
00592     int h = 0;
00593     
00594     switch (d_data->orient)
00595     {
00596         case Top:
00597         case Bottom:
00598             h = pen.width() + d_data->vpad 
00599                     + d_data->majLen + maxLabelHeight(font);
00600             break;
00601         case Left:
00602         case Right:
00603             h = d_data->len + maxLabelHeight(font);
00604             break;
00605         case Round:
00606             h = d_data->vpad + d_data->majLen;
00607             if ( maxLabelHeight(font) > 0 )
00608             {
00609                 const QFontMetrics fm(font);
00610                 h += fm.ascent() - 2;
00611             }
00612             break;
00613     }
00614     
00615     return h;
00616 }
00617 
00627 void QwtScaleDraw::setLabelRotation(double rotation)
00628 {
00629     d_data->labelRotation = rotation;
00630 }
00631 
00636 double QwtScaleDraw::labelRotation() const
00637 {
00638     return d_data->labelRotation;
00639 }
00640 
00660 void QwtScaleDraw::setLabelFlags(int flags)
00661 {
00662     d_data->labelFlags = flags;
00663 }
00664 
00669 int QwtScaleDraw::labelFlags() const
00670 {
00671     return d_data->labelFlags;
00672 }
00673 
00692 void QwtScaleDraw::setAngleRange(double angle1, double angle2)
00693 {
00694     angle1 = qwtLim(angle1, -360.0, 360.0);
00695     angle2 = qwtLim(angle2, -360.0, 360.0);
00696 
00697     int amin = qRound(qwtMin(angle1, angle2) * 16.0);
00698     int amax = qRound(qwtMax(angle1, angle2) * 16.0);
00699     
00700     if (amin == amax)
00701     {
00702         amin -= 1;
00703         amax += 1;
00704     }
00705     
00706     d_data->minAngle = amin;
00707     d_data->maxAngle = amax;
00708     d_data->map.setPaintInterval(d_data->minAngle, d_data->maxAngle);
00709 }
00710 
00727 void QwtScaleDraw::setLabelFormat(char f, int prec, int fieldwidth)
00728 {
00729     switch(f)
00730     {
00731         case 'e':
00732         case 'f':
00733         case 'g':
00734             d_data->fmt = f;
00735             break;
00736         default:
00737             break;
00738     }
00739     if ((prec > -1) && (prec < 99))
00740         d_data->prec = prec;
00741     if ((fieldwidth > -1) && (fieldwidth < 99))
00742         d_data->fieldwidth = fieldwidth;
00743 
00744     sprintf(d_data->formatBuffer, "%%%d.%d%c", d_data->fieldwidth, d_data->prec, d_data->fmt);
00745 }
00746 
00760 void QwtScaleDraw::labelFormat(char &f, int &prec, int &fieldwidth) const
00761 {
00762     f = d_data->fmt;
00763     prec = d_data->prec;
00764     fieldwidth = d_data->fieldwidth;
00765 }
00766 
00773 void QwtScaleDraw::setMargin(uint hMargin, uint vMargin)
00774 {
00775     d_data->hpad = hMargin;
00776     d_data->vpad = vMargin;
00777 }
00778 
00782 void QwtScaleDraw::setTickLength(unsigned int minLen, 
00783     unsigned int medLen, unsigned int majLen)
00784 {
00785     const unsigned int maxTickLen = 1000;
00786 
00787     d_data->minLen = qwtMin(minLen, maxTickLen);
00788     d_data->medLen = qwtMin(medLen, maxTickLen);
00789     d_data->majLen = qwtMin(majLen, maxTickLen);
00790 }
00791 
00796 void QwtScaleDraw::tickLength(unsigned int &minLen,
00797         unsigned int &medLen, unsigned int &majLen) const
00798 {
00799     minLen = d_data->minLen;
00800     medLen = d_data->medLen;
00801     majLen = d_data->majLen;
00802 }
00803 
00808 unsigned int QwtScaleDraw::majTickLength() const
00809 {
00810     return d_data->majLen;
00811 }
00812 
00817 int QwtScaleDraw::maxLabelWidth(const QFont &font) const
00818 {
00819     int maxWidth = 0;
00820 
00821     const QwtTickList &ticks = d_data->scldiv.ticks(QwtScaleDiv::MajorTick);
00822     for (uint i = 0; i < (uint)ticks.count(); i++)
00823     {
00824         const double v = ticks[i];
00825         if ( d_data->scldiv.contains(v) )
00826         {
00827             const int w = labelBoundingRect(font, ticks[i]).width();
00828             if ( w > maxWidth )
00829                 maxWidth = w;
00830         }
00831     }
00832 
00833     return maxWidth;
00834 }
00835 
00840 int QwtScaleDraw::maxLabelHeight(const QFont &font) const
00841 {
00842     int maxHeight = 0;
00843 
00844     const QwtTickList &ticks = d_data->scldiv.ticks(QwtScaleDiv::MajorTick);
00845     for (uint i = 0; i < (uint)ticks.count(); i++)
00846     {
00847         const double v = ticks[i];
00848         if ( d_data->scldiv.contains(v) )
00849         {
00850             const int h = labelBoundingRect(font, ticks[i]).height();
00851             if ( h > maxHeight )
00852                 maxHeight = h;
00853         }
00854     }
00855 
00856     return maxHeight;
00857 }
00858 
00864 QRect QwtScaleDraw::labelBoundingRect(
00865     const QFont &font, double val) const
00866 {
00867     const QFontMetrics fm(font);
00868 
00869     QString zeroString;
00870     if ( d_data->fieldwidth > 0 )
00871         zeroString.fill('0', d_data->fieldwidth);
00872 
00873     const QString lbl = label(val);
00874 
00875     const QString &txt = fm.width(zeroString) > fm.width(lbl) 
00876         ? zeroString : lbl;
00877     if ( txt.isEmpty() )
00878         return QRect(0, 0, 0, 0);
00879 
00880     QRect br;
00881 
00882     QPoint pos;
00883     int flags;
00884     double rotation;
00885 
00886     labelPlacement(fm, val, pos, flags, rotation);
00887     if ( flags )
00888     {
00889         // Don't use fm.boundingRect(txt), it cuts off pixels.
00890         const int w = fm.boundingRect(0, 0, 
00891             QWIDGETSIZE_MAX, QWIDGETSIZE_MAX, 0, txt).width();
00892         const int h = -(fm.ascent() - 2);
00893 
00894         QwtMatrix m = labelWorldMatrix(fm, pos, flags, rotation, txt);
00895         br = QwtMetricsMap::translate(m, QRect(0, 0, w, h));
00896 #if QT_VERSION < 0x040000
00897         br.moveBy(-pos.x(), -pos.y());
00898 #else
00899         br.translate(-pos.x(), -pos.y());
00900 #endif
00901     }
00902 
00903     return br;
00904 }
00905 
00916 void QwtScaleDraw::minBorderDist(const QFont &font,
00917     int &start, int &end ) const
00918 {
00919     start = 0;
00920     end = 0;
00921 
00922     const QwtTickList &ticks = d_data->scldiv.ticks(QwtScaleDiv::MajorTick);
00923     if ( ticks.count() > 0 )
00924     {
00925 #ifdef __GNUC__
00926 #warning Wrong calculation for scales without bounding labels
00927 #endif
00928 
00929         const QRect labelRectMin = labelBoundingRect(font, ticks[0]);
00930         const QRect labelRectMax = labelBoundingRect(font, 
00931             ticks[ticks.count() - 1]);
00932 
00933         switch (d_data->orient)
00934         {
00935             case Left:
00936             case Right:
00937                 end = -labelRectMin.y();
00938                 start = labelRectMax.height() + labelRectMax.y();
00939                 break;
00940             case Top:
00941             case Bottom:
00942                 start = -labelRectMin.x();
00943                 end = labelRectMax.width() + labelRectMax.x();
00944                 break;
00945             case Round:
00946                 start = labelRectMin.width();
00947                 end = labelRectMax.width();
00948                 break;
00949         }
00950     }
00951 }
00952 
00962 int QwtScaleDraw::minLabelDist(const QFont &font) const
00963 {
00964     if ( d_data->orient == Round ) // no implementation
00965         return 0;
00966 
00967     const QwtTickList &ticks = d_data->scldiv.ticks(QwtScaleDiv::MajorTick);
00968     if (ticks.count() == 0)
00969         return 0;
00970 
00971     const QFontMetrics fm(font);
00972 
00973     const bool vertical = (d_data->orient == Left || d_data->orient == Right);
00974 
00975     QRect bRect1;
00976     QRect bRect2 = labelBoundingRect(font, ticks[0]);
00977     if ( vertical )
00978     {
00979         bRect2.setRect(-bRect2.bottom(), 0, bRect2.height(), bRect2.width());
00980     }
00981     int maxDist = 0;
00982 
00983     for (uint i = 1; i < (uint)ticks.count(); i++ )
00984     {
00985         bRect1 = bRect2;
00986         bRect2 = labelBoundingRect(font, ticks[i]);
00987         if ( vertical )
00988         {
00989             bRect2.setRect(-bRect2.bottom(), 0,
00990                 bRect2.height(), bRect2.width());
00991         }
00992 
00993         int dist = fm.leading(); // space between the labels
00994         if ( bRect1.right() > 0 )
00995             dist += bRect1.right();
00996         if ( bRect2.left() < 0 )
00997             dist += -bRect2.left();
00998 
00999         if ( dist > maxDist )
01000             maxDist = dist;
01001     }
01002 
01003     double angle = d_data->labelRotation / 180.0 * M_PI;
01004     if ( vertical )
01005         angle += M_PI / 2;
01006 
01007     if ( sin(angle) == 0.0 )
01008         return maxDist;
01009 
01010     const int fmHeight = fm.ascent() - 2; 
01011 
01012     // The distance we need until there is
01013     // the height of the label font. This height is needed
01014     // for the neighbour labal.
01015 
01016     int labelDist = (int)(fmHeight / sin(angle) * cos(angle));
01017     if ( labelDist < 0 )
01018         labelDist = -labelDist;
01019 
01020     // The cast above floored labelDist. We want to ceil.
01021     labelDist++; 
01022 
01023     // For text orientations close to the scale orientation 
01024 
01025     if ( labelDist > maxDist )
01026         labelDist = maxDist;
01027 
01028     // For text orientations close to the opposite of the 
01029     // scale orientation
01030 
01031     if ( labelDist < fmHeight )
01032         labelDist = fmHeight;
01033 
01034     return labelDist;
01035 }
01036 
01043 int QwtScaleDraw::minHeight( const QPen &pen, const QFont &font ) const
01044 {
01045     const int pw = qwtMax( 1, pen.width() );  // penwidth can be zero
01046 
01047     int h = 0;
01048     switch ( d_data->orient )
01049     {
01050         case Left:
01051         case Right:
01052         {
01053             const uint minorCount = 
01054                 d_data->scldiv.ticks(QwtScaleDiv::MinorTick).count() +
01055                 d_data->scldiv.ticks(QwtScaleDiv::MediumTick).count();
01056             const uint majorCount = 
01057                 d_data->scldiv.ticks(QwtScaleDiv::MajorTick).count();
01058 
01059             int bottomDist, topDist;
01060             minBorderDist(font, bottomDist, topDist);
01061 
01062             h = bottomDist + topDist;
01063             if ( majorCount >= 2 ) 
01064                 h += minLabelDist(font) * (majorCount - 1);
01065 
01066             int th = 2 * (majorCount + minorCount) * pw;
01067             if ( th > h )
01068                 h = th;
01069             break;
01070         }
01071         case Round:
01072             // compute the radial thickness
01073             h = pw + d_data->vpad + d_data->majLen + maxLabelWidth(font);
01074             break;
01075         case Top:
01076         case Bottom:
01077             h = pw + d_data->vpad + d_data->majLen + maxLabelHeight(font);
01078             break;
01079     }
01080     return h;
01081 }
01082 
01089 int QwtScaleDraw::minWidth( const QPen &pen, const QFont &font ) const
01090 {
01091     const int pw = qwtMax( 1, pen.width() );  // penwidth can be zero
01092 
01093     int w = 0;
01094 
01095     switch(d_data->orient)
01096     {
01097         case Left:
01098         case Right:
01099         {
01100             w = pw + d_data->hpad + d_data->majLen + maxLabelWidth(font);
01101             break;
01102         }
01103         case Round:
01104         {   
01105             w = pw + d_data->vpad + d_data->majLen + maxLabelWidth(font);
01106             break;
01107         }
01108         case Top:
01109         case Bottom:
01110         {
01111             const uint minorCount =
01112                 d_data->scldiv.ticks(QwtScaleDiv::MinorTick).count() +
01113                 d_data->scldiv.ticks(QwtScaleDiv::MediumTick).count();
01114             const uint majorCount =
01115                 d_data->scldiv.ticks(QwtScaleDiv::MajorTick).count();
01116 
01117             int leftDist, rightDist;
01118             minBorderDist(font, leftDist, rightDist);
01119 
01120             w = leftDist + rightDist + 
01121                 minLabelDist(font) * (majorCount - 1);
01122 
01123             int tw = 2 * (majorCount + minorCount) * pw;
01124             if ( tw > w )
01125                 w = tw;
01126 
01127             break;
01128         }
01129     }
01130     return w;
01131 }
01132 
01140 QString QwtScaleDraw::label(double value) const
01141 {
01142     // snprintf is C99 and therefore not portable :-(
01143     // sprintf is safe, when buffer is large enough for
01144     // a minus sign, 99 digits, a radix symbol,
01145     // an exponent character, a minus or plus sign, 3 digits,
01146     // and a '\0'.
01147     char buffer[128];
01148     sprintf(buffer, d_data->formatBuffer, value);
01149 
01150     return QString::fromLatin1(buffer);
01151 }
01152 
01154 int QwtScaleDraw::x() const
01155 {
01156     return d_data->xorg;
01157 }
01158 
01160 int QwtScaleDraw::y() const
01161 {
01162     return d_data->yorg;
01163 }
01164 
01166 int QwtScaleDraw::length() const
01167 {
01168     return d_data->len;
01169 }
01170 
01172 QwtScaleDraw::Orientation QwtScaleDraw::orientation() const 
01173 { 
01174     return d_data->orient; 
01175 }

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