00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <qpen.h>
00013 #include <qpainter.h>
00014 #include "qwt_math.h"
00015 #include "qwt_painter.h"
00016 #include "qwt_polygon.h"
00017 #include "qwt_scale_div.h"
00018 #include "qwt_scale_map.h"
00019 #include "qwt_scale_draw.h"
00020
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 len(0),
00034 alignment(QwtScaleDraw::BottomScale),
00035 labelAlignment(0),
00036 labelRotation(0.0)
00037 {
00038 }
00039
00040 QPoint pos;
00041 int len;
00042
00043 Alignment alignment;
00044
00045 #if QT_VERSION < 0x040000
00046 int labelAlignment;
00047 #else
00048 Qt::Alignment labelAlignment;
00049 #endif
00050 double labelRotation;
00051 };
00052
00060 QwtScaleDraw::QwtScaleDraw()
00061 {
00062 d_data = new QwtScaleDraw::PrivateData;
00063 setLength(100);
00064 }
00065
00067 QwtScaleDraw::QwtScaleDraw(const QwtScaleDraw &other):
00068 QwtAbstractScaleDraw(other)
00069 {
00070 d_data = new QwtScaleDraw::PrivateData(*other.d_data);
00071 }
00072
00074 QwtScaleDraw::~QwtScaleDraw()
00075 {
00076 delete d_data;
00077 }
00078
00080 QwtScaleDraw &QwtScaleDraw::operator=(const QwtScaleDraw &other)
00081 {
00082 *(QwtAbstractScaleDraw*)this = (const QwtAbstractScaleDraw &)other;
00083 *d_data = *other.d_data;
00084 return *this;
00085 }
00086
00091 QwtScaleDraw::Alignment QwtScaleDraw::alignment() const
00092 {
00093 return d_data->alignment;
00094 }
00095
00102 void QwtScaleDraw::setAlignment(Alignment align)
00103 {
00104 d_data->alignment = align;
00105 }
00106
00115 Qt::Orientation QwtScaleDraw::orientation() const
00116 {
00117 switch(d_data->alignment)
00118 {
00119 case TopScale:
00120 case BottomScale:
00121 return Qt::Horizontal;
00122 case LeftScale:
00123 case RightScale:
00124 default:
00125 return Qt::Vertical;
00126 }
00127 }
00128
00139 void QwtScaleDraw::getBorderDistHint(const QFont &font,
00140 int &start, int &end ) const
00141 {
00142 start = 0;
00143 end = 0;
00144
00145 if ( !hasComponent(QwtAbstractScaleDraw::Labels) )
00146 return;
00147
00148 const QwtValueList &ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
00149 if ( ticks.count() == 0 )
00150 return;
00151
00152 QRect lr = labelRect(font, ticks[0]);
00153
00154
00155 int off = qwtAbs(map().transform(ticks[0]) - qRound(map().p1()));
00156
00157 if ( orientation() == Qt::Vertical )
00158 end = lr.bottom() + 1 - off;
00159 else
00160 start = -lr.left() - off;
00161
00162 const int lastTick = ticks.count() - 1;
00163 lr = labelRect(font, ticks[lastTick]);
00164
00165
00166 off = qwtAbs(map().transform(ticks[lastTick]) - qRound(map().p2()));
00167
00168 if ( orientation() == Qt::Vertical )
00169 start = -lr.top() - off;
00170 else
00171 end = lr.right() + 1 - off;
00172
00173
00174
00175
00176 if ( start < 0 )
00177 start = 0;
00178 if ( end < 0 )
00179 end = 0;
00180 }
00181
00192 int QwtScaleDraw::minLabelDist(const QFont &font) const
00193 {
00194 if ( !hasComponent(QwtAbstractScaleDraw::Labels) )
00195 return 0;
00196
00197 const QwtValueList &ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
00198 if (ticks.count() == 0)
00199 return 0;
00200
00201 const QFontMetrics fm(font);
00202
00203 const bool vertical = (orientation() == Qt::Vertical);
00204
00205 QRect bRect1;
00206 QRect bRect2 = labelRect(font, ticks[0]);
00207 if ( vertical )
00208 {
00209 bRect2.setRect(-bRect2.bottom(), 0, bRect2.height(), bRect2.width());
00210 }
00211 int maxDist = 0;
00212
00213 for (uint i = 1; i < (uint)ticks.count(); i++ )
00214 {
00215 bRect1 = bRect2;
00216 bRect2 = labelRect(font, ticks[i]);
00217 if ( vertical )
00218 {
00219 bRect2.setRect(-bRect2.bottom(), 0,
00220 bRect2.height(), bRect2.width());
00221 }
00222
00223 int dist = fm.leading();
00224 if ( bRect1.right() > 0 )
00225 dist += bRect1.right();
00226 if ( bRect2.left() < 0 )
00227 dist += -bRect2.left();
00228
00229 if ( dist > maxDist )
00230 maxDist = dist;
00231 }
00232
00233 double angle = labelRotation() / 180.0 * M_PI;
00234 if ( vertical )
00235 angle += M_PI / 2;
00236
00237 if ( sin(angle) == 0.0 )
00238 return maxDist;
00239
00240 const int fmHeight = fm.ascent() - 2;
00241
00242
00243
00244
00245
00246 int labelDist = (int)(fmHeight / sin(angle) * cos(angle));
00247 if ( labelDist < 0 )
00248 labelDist = -labelDist;
00249
00250
00251 labelDist++;
00252
00253
00254
00255 if ( labelDist > maxDist )
00256 labelDist = maxDist;
00257
00258
00259
00260
00261 if ( labelDist < fmHeight )
00262 labelDist = fmHeight;
00263
00264 return labelDist;
00265 }
00266
00280 int QwtScaleDraw::extent(const QPen &pen, const QFont &font) const
00281 {
00282 int d = 0;
00283
00284 if ( hasComponent(QwtAbstractScaleDraw::Labels) )
00285 {
00286 if ( orientation() == Qt::Vertical )
00287 d = maxLabelWidth(font);
00288 else
00289 d = maxLabelHeight(font);
00290
00291 if ( d > 0 )
00292 d += spacing();
00293 }
00294
00295 if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
00296 {
00297 d += majTickLength();
00298 }
00299
00300 if ( hasComponent(QwtAbstractScaleDraw::Backbone) )
00301 {
00302 const int pw = qwtMax( 1, pen.width() );
00303 d += pw;
00304 }
00305
00306 d = qwtMax(d, minimumExtent());
00307 return d;
00308 }
00309
00318 int QwtScaleDraw::minLength(const QPen &pen, const QFont &font) const
00319 {
00320 int startDist, endDist;
00321 getBorderDistHint(font, startDist, endDist);
00322
00323 const QwtScaleDiv &sd = scaleDiv();
00324
00325 const uint minorCount =
00326 sd.ticks(QwtScaleDiv::MinorTick).count() +
00327 sd.ticks(QwtScaleDiv::MediumTick).count();
00328 const uint majorCount =
00329 sd.ticks(QwtScaleDiv::MajorTick).count();
00330
00331 int lengthForLabels = 0;
00332 if ( hasComponent(QwtAbstractScaleDraw::Labels) )
00333 {
00334 if ( majorCount >= 2 )
00335 lengthForLabels = minLabelDist(font) * (majorCount - 1);
00336 }
00337
00338 int lengthForTicks = 0;
00339 if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
00340 {
00341 const int pw = qwtMax( 1, pen.width() );
00342 lengthForTicks = 2 * (majorCount + minorCount) * pw;
00343 }
00344
00345 return startDist + endDist + qwtMax(lengthForLabels, lengthForTicks);
00346 }
00347
00356 QPoint QwtScaleDraw::labelPosition( double value) const
00357 {
00358 const int tval = map().transform(value);
00359 int dist = spacing() + 1;
00360 if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
00361 dist += majTickLength();
00362
00363 int px = 0;
00364 int py = 0;
00365
00366 switch(alignment())
00367 {
00368 case RightScale:
00369 {
00370 px = d_data->pos.x() + dist;
00371 py = tval;
00372 break;
00373 }
00374 case LeftScale:
00375 {
00376 px = d_data->pos.x() - dist;
00377 py = tval;
00378 break;
00379 }
00380 case BottomScale:
00381 {
00382 px = tval;
00383 py = d_data->pos.y() + dist;
00384 break;
00385 }
00386 case TopScale:
00387 {
00388 px = tval;
00389 py = d_data->pos.y() - dist;
00390 break;
00391 }
00392 }
00393
00394 return QPoint(px, py);
00395 }
00396
00406 void QwtScaleDraw::drawTick(QPainter *painter, double value, int len) const
00407 {
00408 if ( len <= 0 )
00409 return;
00410
00411 int pw2 = qwtMin((int)painter->pen().width(), len) / 2;
00412
00413 QwtScaleMap scaleMap = map();
00414 const QwtMetricsMap metricsMap = QwtPainter::metricsMap();
00415 QPoint pos = d_data->pos;
00416
00417 if ( !metricsMap.isIdentity() )
00418 {
00419
00420
00421
00422
00423
00424 QwtPainter::resetMetricsMap();
00425
00426 pos = metricsMap.layoutToDevice(pos);
00427
00428 if ( orientation() == Qt::Vertical )
00429 {
00430 scaleMap.setPaintInterval(
00431 metricsMap.layoutToDeviceY((int)scaleMap.p1()),
00432 metricsMap.layoutToDeviceY((int)scaleMap.p2())
00433 );
00434 len = metricsMap.layoutToDeviceX(len);
00435 }
00436 else
00437 {
00438 scaleMap.setPaintInterval(
00439 metricsMap.layoutToDeviceX((int)scaleMap.p1()),
00440 metricsMap.layoutToDeviceX((int)scaleMap.p2())
00441 );
00442 len = metricsMap.layoutToDeviceY(len);
00443 }
00444 }
00445
00446 const int tval = scaleMap.transform(value);
00447
00448 switch(alignment())
00449 {
00450 case LeftScale:
00451 {
00452 #if QT_VERSION < 0x040000
00453 QwtPainter::drawLine(painter, pos.x() + pw2, tval,
00454 pos.x() - len - 2 * pw2, tval);
00455 #else
00456 QwtPainter::drawLine(painter, pos.x() - pw2, tval,
00457 pos.x() - len, tval);
00458 #endif
00459 break;
00460 }
00461
00462 case RightScale:
00463 {
00464 #if QT_VERSION < 0x040000
00465 QwtPainter::drawLine(painter, pos.x(), tval,
00466 pos.x() + len + pw2, tval);
00467 #else
00468 QwtPainter::drawLine(painter, pos.x() + pw2, tval,
00469 pos.x() + len, tval);
00470 #endif
00471 break;
00472 }
00473
00474 case BottomScale:
00475 {
00476 #if QT_VERSION < 0x040000
00477 QwtPainter::drawLine(painter, tval, pos.y(),
00478 tval, pos.y() + len + 2 * pw2);
00479 #else
00480 QwtPainter::drawLine(painter, tval, pos.y() + pw2,
00481 tval, pos.y() + len);
00482 #endif
00483 break;
00484 }
00485
00486 case TopScale:
00487 {
00488 #if QT_VERSION < 0x040000
00489 QwtPainter::drawLine(painter, tval, pos.y() + pw2,
00490 tval, pos.y() - len - 2 * pw2);
00491 #else
00492 QwtPainter::drawLine(painter, tval, pos.y() - pw2,
00493 tval, pos.y() - len);
00494 #endif
00495 break;
00496 }
00497 }
00498 QwtPainter::setMetricsMap(metricsMap);
00499 }
00500
00507 void QwtScaleDraw::drawBackbone(QPainter *painter) const
00508 {
00509 const int bw2 = painter->pen().width() / 2;
00510
00511 const QPoint &pos = d_data->pos;
00512 const int len = d_data->len - 1;
00513
00514 switch(alignment())
00515 {
00516 case LeftScale:
00517 QwtPainter::drawLine(painter, pos.x() - bw2,
00518 pos.y(), pos.x() - bw2, pos.y() + len );
00519 break;
00520 case RightScale:
00521 QwtPainter::drawLine(painter, pos.x() + bw2,
00522 pos.y(), pos.x() + bw2, pos.y() + len);
00523 break;
00524 case TopScale:
00525 QwtPainter::drawLine(painter, pos.x(), pos.y() - bw2,
00526 pos.x() + len, pos.y() - bw2);
00527 break;
00528 case BottomScale:
00529 QwtPainter::drawLine(painter, pos.x(), pos.y() + bw2,
00530 pos.x() + len, pos.y() + bw2);
00531 break;
00532 }
00533 }
00534
00566 void QwtScaleDraw::move(const QPoint &pos)
00567 {
00568 d_data->pos = pos;
00569 updateMap();
00570 }
00571
00576 QPoint QwtScaleDraw::pos() const
00577 {
00578 return d_data->pos;
00579 }
00580
00589 void QwtScaleDraw::setLength(int length)
00590 {
00591 d_data->len = qwtMax(length, 10);
00592 updateMap();
00593 }
00594
00599 int QwtScaleDraw::length() const
00600 {
00601 return d_data->len;
00602 }
00603
00612 void QwtScaleDraw::drawLabel(QPainter *painter, double value) const
00613 {
00614 QwtText lbl = tickLabel(painter->font(), value);
00615 if ( lbl.isEmpty() )
00616 return;
00617
00618 const QPoint pos = labelPosition(value);
00619
00620 QSize labelSize = lbl.textSize(painter->font());
00621 if ( labelSize.height() % 2 )
00622 labelSize.setHeight(labelSize.height() + 1);
00623
00624 const QwtMatrix m = labelMatrix( pos, labelSize);
00625
00626 painter->save();
00627 #if QT_VERSION < 0x040000
00628 painter->setWorldMatrix(m, true);
00629 #else
00630 painter->setMatrix(m, true);
00631 #endif
00632
00633 lbl.draw (painter, QRect(QPoint(0, 0), labelSize) );
00634 painter->restore();
00635 }
00636
00646 QwtMatrix QwtScaleDraw::labelMatrix(
00647 const QPoint &pos, const QSize &size) const
00648 {
00649 QwtMatrix m;
00650 m.translate(pos.x(), pos.y());
00651 m.rotate(labelRotation());
00652
00653 int flags = labelAlignment();
00654 if ( flags == 0 )
00655 {
00656 switch(alignment())
00657 {
00658 case RightScale:
00659 {
00660 if ( flags == 0 )
00661 flags = Qt::AlignRight | Qt::AlignVCenter;
00662 break;
00663 }
00664 case LeftScale:
00665 {
00666 if ( flags == 0 )
00667 flags = Qt::AlignLeft | Qt::AlignVCenter;
00668 break;
00669 }
00670 case BottomScale:
00671 {
00672 if ( flags == 0 )
00673 flags = Qt::AlignHCenter | Qt::AlignBottom;
00674 break;
00675 }
00676 case TopScale:
00677 {
00678 if ( flags == 0 )
00679 flags = Qt::AlignHCenter | Qt::AlignTop;
00680 break;
00681 }
00682 }
00683 }
00684
00685 const int w = size.width();
00686 const int h = size.height();
00687
00688 int x, y;
00689
00690 if ( flags & Qt::AlignLeft )
00691 x = -w;
00692 else if ( flags & Qt::AlignRight )
00693 x = -(w % 2);
00694 else
00695 x = -(w / 2);
00696
00697 if ( flags & Qt::AlignTop )
00698 y = -h ;
00699 else if ( flags & Qt::AlignBottom )
00700 y = -(h % 2);
00701 else
00702 y = -(h/2);
00703
00704 m.translate(x, y);
00705
00706 return m;
00707 }
00708
00717 QRect QwtScaleDraw::labelRect(const QFont &font, double value) const
00718 {
00719 QwtText lbl = tickLabel(font, value);
00720 if ( lbl.isEmpty() )
00721 return QRect(0, 0, 0, 0);
00722
00723 const QPoint pos = labelPosition(value);
00724
00725 QSize labelSize = lbl.textSize(font);
00726 if ( labelSize.height() % 2 )
00727 {
00728 labelSize.setHeight(labelSize.height() + 1);
00729 }
00730
00731 const QwtMatrix m = labelMatrix(pos, labelSize);
00732
00733 #if 0
00734 QRect br = QwtMetricsMap::translate(m, QRect(QPoint(0, 0), labelSize));
00735 #else
00736 QwtPolygon pol(4);
00737 pol.setPoint(0, 0, 0);
00738 pol.setPoint(1, 0, labelSize.height() - 1 );
00739 pol.setPoint(2, labelSize.width() - 1, 0);
00740 pol.setPoint(3, labelSize.width() - 1, labelSize.height() - 1 );
00741
00742 pol = QwtMetricsMap::translate(m, pol);
00743 QRect br = pol.boundingRect();
00744 #endif
00745
00746 #if QT_VERSION < 0x040000
00747 br.moveBy(-pos.x(), -pos.y());
00748 #else
00749 br.translate(-pos.x(), -pos.y());
00750 #endif
00751
00752 return br;
00753 }
00754
00761 QSize QwtScaleDraw::labelSize(const QFont &font, double value) const
00762 {
00763 return labelRect(font, value).size();
00764 }
00765
00779 void QwtScaleDraw::setLabelRotation(double rotation)
00780 {
00781 d_data->labelRotation = rotation;
00782 }
00783
00788 double QwtScaleDraw::labelRotation() const
00789 {
00790 return d_data->labelRotation;
00791 }
00792
00818 #if QT_VERSION < 0x040000
00819 void QwtScaleDraw::setLabelAlignment(int alignment)
00820 #else
00821 void QwtScaleDraw::setLabelAlignment(Qt::Alignment alignment)
00822 #endif
00823 {
00824 d_data->labelAlignment = alignment;
00825 }
00826
00831 #if QT_VERSION < 0x040000
00832 int QwtScaleDraw::labelAlignment() const
00833 #else
00834 Qt::Alignment QwtScaleDraw::labelAlignment() const
00835 #endif
00836 {
00837 return d_data->labelAlignment;
00838 }
00839
00844 int QwtScaleDraw::maxLabelWidth(const QFont &font) const
00845 {
00846 int maxWidth = 0;
00847
00848 const QwtValueList &ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
00849 for (uint i = 0; i < (uint)ticks.count(); i++)
00850 {
00851 const double v = ticks[i];
00852 if ( scaleDiv().contains(v) )
00853 {
00854 const int w = labelSize(font, ticks[i]).width();
00855 if ( w > maxWidth )
00856 maxWidth = w;
00857 }
00858 }
00859
00860 return maxWidth;
00861 }
00862
00867 int QwtScaleDraw::maxLabelHeight(const QFont &font) const
00868 {
00869 int maxHeight = 0;
00870
00871 const QwtValueList &ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
00872 for (uint i = 0; i < (uint)ticks.count(); i++)
00873 {
00874 const double v = ticks[i];
00875 if ( scaleDiv().contains(v) )
00876 {
00877 const int h = labelSize(font, ticks[i]).height();
00878 if ( h > maxHeight )
00879 maxHeight = h;
00880 }
00881 }
00882
00883 return maxHeight;
00884 }
00885
00886 void QwtScaleDraw::updateMap()
00887 {
00888 QwtScaleMap &sm = scaleMap();
00889 if ( orientation() == Qt::Vertical )
00890 sm.setPaintInterval(d_data->pos.y() + d_data->len - 1, d_data->pos.y());
00891 else
00892 sm.setPaintInterval(d_data->pos.x(), d_data->pos.x() + d_data->len - 1);
00893 }