# qwt_scale_widget.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 <qpainter.h>
    00013 #include <qevent.h>
    00014 #include "qwt_painter.h"
    00015 #include "qwt_color_map.h"
    00016 #include "qwt_scale_widget.h"
    00017 #include "qwt_scale_map.h"
    00018 #include "qwt_math.h"
    00019 #include "qwt_paint_buffer.h"
    00020 #include "qwt_scale_div.h"
    00021 #include "qwt_text.h"
    00022
    00023 class QwtScaleWidget::PrivateData
    00024 {
    00025 public:
    00026     PrivateData():
    00027         scaleDraw(NULL)
    00028     {
    00029         colorBar.colorMap = NULL;
    00030     }
    00031
    00032     ~PrivateData()
    00033     {
    00034         delete scaleDraw;
    00035         delete colorBar.colorMap;
    00036     }
    00037
    00038     QwtScaleDraw *scaleDraw;
    00039
    00040     int borderDist[2];
    00041     int minBorderDist[2];
    00042     int scaleLength;
    00043     int margin;
    00044     int penWidth;
    00045
    00046     int titleOffset;
    00047     int spacing;
    00048     QwtText title;
    00049
    00050     struct t_colorBar
    00051     {
    00052         bool isEnabled;
    00053         int width;
    00054         QwtDoubleInterval interval;
    00055         QwtColorMap *colorMap;
    00056     } colorBar;
    00057 };
    00058
    00063 QwtScaleWidget::QwtScaleWidget(QWidget *parent):
    00064     QWidget(parent)
    00065 {
    00066     initScale(QwtScaleDraw::LeftScale);
    00067 }
    00068
    00069 #if QT_VERSION < 0x040000
    00070
    00075 QwtScaleWidget::QwtScaleWidget(QWidget *parent, const char *name):
    00076     QWidget(parent, name)
    00077 {
    00078     initScale(QwtScaleDraw::LeftScale);
    00079 }
    00080 #endif
    00081
    00087 QwtScaleWidget::QwtScaleWidget(
    00088         QwtScaleDraw::Alignment align, QWidget *parent):
    00089     QWidget(parent)
    00090 {
    00091     initScale(align);
    00092 }
    00093
    00095 QwtScaleWidget::~QwtScaleWidget()
    00096 {
    00097     delete d_data;
    00098 }
    00099
    00101 void QwtScaleWidget::initScale(QwtScaleDraw::Alignment align)
    00102 {
    00103     d_data = new PrivateData;
    00104
    00105 #if QT_VERSION < 0x040000
    00106     setWFlags(Qt::WNoAutoErase);
    00107 #endif
    00108
    00109     d_data->borderDist[0] = 0;
    00110     d_data->borderDist[1] = 0;
    00111     d_data->minBorderDist[0] = 0;
    00112     d_data->minBorderDist[1] = 0;
    00113     d_data->margin = 4;
    00114     d_data->penWidth = 0;
    00115     d_data->titleOffset = 0;
    00116     d_data->spacing = 2;
    00117
    00118     d_data->scaleDraw = new QwtScaleDraw;
    00119     d_data->scaleDraw->setAlignment(align);
    00120     d_data->scaleDraw->setLength(10);
    00121
    00122     d_data->colorBar.colorMap = new QwtLinearColorMap();
    00123     d_data->colorBar.isEnabled = false;
    00124     d_data->colorBar.width = 10;
    00125
    00126     const int flags = Qt::AlignHCenter
    00127 #if QT_VERSION < 0x040000
    00128         | Qt::WordBreak | Qt::ExpandTabs;
    00129 #else
    00130         | Qt::TextExpandTabs | Qt::TextWordWrap;
    00131 #endif
    00132     d_data->title.setRenderFlags(flags);
    00133     d_data->title.setFont(font());
    00134
    00135     QSizePolicy policy(QSizePolicy::MinimumExpanding,
    00136         QSizePolicy::Fixed);
    00137     if ( d_data->scaleDraw->orientation() == Qt::Vertical )
    00138         policy.transpose();
    00139
    00140     setSizePolicy(policy);
    00141
    00142 #if QT_VERSION >= 0x040000
    00143     setAttribute(Qt::WA_WState_OwnSizePolicy, false);
    00144 #else
    00145     clearWState( WState_OwnSizePolicy );
    00146 #endif
    00147
    00148 }
    00149
    00150 void QwtScaleWidget::setTitle(const QString &title)
    00151 {
    00152     if ( d_data->title.text() != title )
    00153     {
    00154         d_data->title.setText(title);
    00155         layoutScale();
    00156     }
    00157 }
    00158
    00167 void QwtScaleWidget::setTitle(const QwtText &title)
    00168 {
    00169     QwtText t = title;
    00170     const int flags = title.renderFlags() & ~(Qt::AlignTop | Qt::AlignBottom);
    00171     t.setRenderFlags(flags);
    00172
    00173     if (t != d_data->title)
    00174     {
    00175         d_data->title = t;
    00176         layoutScale();
    00177     }
    00178 }
    00179
    00186 void QwtScaleWidget::setAlignment(QwtScaleDraw::Alignment alignment)
    00187 {
    00188 #if QT_VERSION >= 0x040000
    00189     if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
    00190 #else
    00191     if ( !testWState( WState_OwnSizePolicy ) )
    00192 #endif
    00193     {
    00194         QSizePolicy policy(QSizePolicy::MinimumExpanding,
    00195             QSizePolicy::Fixed);
    00196         if ( d_data->scaleDraw->orientation() == Qt::Vertical )
    00197             policy.transpose();
    00198         setSizePolicy(policy);
    00199
    00200 #if QT_VERSION >= 0x040000
    00201         setAttribute(Qt::WA_WState_OwnSizePolicy, false);
    00202 #else
    00203         clearWState( WState_OwnSizePolicy );
    00204 #endif
    00205     }
    00206
    00207     if (d_data->scaleDraw)
    00208         d_data->scaleDraw->setAlignment(alignment);
    00209     layoutScale();
    00210 }
    00211
    00212
    00217 QwtScaleDraw::Alignment QwtScaleWidget::alignment() const
    00218 {
    00219     if (!scaleDraw())
    00220         return QwtScaleDraw::LeftScale;
    00221
    00222     return scaleDraw()->alignment();
    00223 }
    00224
    00233 void QwtScaleWidget::setBorderDist(int dist1, int dist2)
    00234 {
    00235     if ( dist1 != d_data->borderDist[0] || dist2 != d_data->borderDist[1] )
    00236     {
    00237         d_data->borderDist[0] = dist1;
    00238         d_data->borderDist[1] = dist2;
    00239         layoutScale();
    00240     }
    00241 }
    00242
    00248 void QwtScaleWidget::setMargin(int margin)
    00249 {
    00250     margin = qwtMax( 0, margin );
    00251     if ( margin != d_data->margin )
    00252     {
    00253         d_data->margin = margin;
    00254         layoutScale();
    00255     }
    00256 }
    00257
    00263 void QwtScaleWidget::setSpacing(int spacing)
    00264 {
    00265     spacing = qwtMax( 0, spacing );
    00266     if ( spacing != d_data->spacing )
    00267     {
    00268         d_data->spacing = spacing;
    00269         layoutScale();
    00270     }
    00271 }
    00272
    00278 void QwtScaleWidget::setPenWidth(int width)
    00279 {
    00280     if ( width < 0 )
    00281         width = 0;
    00282
    00283     if ( width != d_data->penWidth )
    00284     {
    00285         d_data->penWidth = width;
    00286         layoutScale();
    00287     }
    00288 }
    00289
    00295 #if QT_VERSION < 0x040000
    00296 void QwtScaleWidget::setLabelAlignment(int alignment)
    00297 #else
    00298 void QwtScaleWidget::setLabelAlignment(Qt::Alignment alignment)
    00299 #endif
    00300 {
    00301     d_data->scaleDraw->setLabelAlignment(alignment);
    00302     layoutScale();
    00303 }
    00304
    00310 void QwtScaleWidget::setLabelRotation(double rotation)
    00311 {
    00312     d_data->scaleDraw->setLabelRotation(rotation);
    00313     layoutScale();
    00314 }
    00315
    00321 void QwtScaleWidget::setScaleDraw(QwtScaleDraw *sd)
    00322 {
    00323     if ( sd == NULL || sd == d_data->scaleDraw )
    00324         return;
    00325
    00326     if ( d_data->scaleDraw )
    00327         sd->setAlignment(d_data->scaleDraw->alignment());
    00328
    00329     delete d_data->scaleDraw;
    00330     d_data->scaleDraw = sd;
    00331
    00332     layoutScale();
    00333 }
    00334
    00339 const QwtScaleDraw *QwtScaleWidget::scaleDraw() const
    00340 {
    00341     return d_data->scaleDraw;
    00342 }
    00343
    00348 QwtScaleDraw *QwtScaleWidget::scaleDraw()
    00349 {
    00350     return d_data->scaleDraw;
    00351 }
    00352
    00357 QwtText QwtScaleWidget::title() const
    00358 {
    00359     return d_data->title;
    00360 }
    00361
    00366 int QwtScaleWidget::startBorderDist() const
    00367 {
    00368     return d_data->borderDist[0];
    00369 }
    00370
    00375 int QwtScaleWidget::endBorderDist() const
    00376 {
    00377     return d_data->borderDist[1];
    00378 }
    00379
    00384 int QwtScaleWidget::margin() const
    00385 {
    00386     return d_data->margin;
    00387 }
    00388
    00393 int QwtScaleWidget::spacing() const
    00394 {
    00395     return d_data->spacing;
    00396 }
    00397
    00402 int QwtScaleWidget::penWidth() const
    00403 {
    00404     return d_data->penWidth;
    00405 }
    00409 void QwtScaleWidget::paintEvent(QPaintEvent *e)
    00410 {
    00411     const QRect &ur = e->rect();
    00412     if ( ur.isValid() )
    00413     {
    00414 #if QT_VERSION < 0x040000
    00415         QwtPaintBuffer paintBuffer(this, ur);
    00416         draw(paintBuffer.painter());
    00417 #else
    00418         QPainter painter(this);
    00419         draw(&painter);
    00420 #endif
    00421     }
    00422 }
    00423
    00427 void QwtScaleWidget::draw(QPainter *painter) const
    00428 {
    00429     painter->save();
    00430
    00431     QPen scalePen = painter->pen();
    00432     scalePen.setWidth(d_data->penWidth);
    00433     painter->setPen(scalePen);
    00434
    00435 #if QT_VERSION < 0x040000
    00436     d_data->scaleDraw->draw(painter, colorGroup());
    00437 #else
    00438     d_data->scaleDraw->draw(painter, palette());
    00439 #endif
    00440     painter->restore();
    00441
    00442     if ( d_data->colorBar.isEnabled && d_data->colorBar.width > 0 &&
    00443         d_data->colorBar.interval.isValid() )
    00444     {
    00445         drawColorBar(painter, colorBarRect(rect()));
    00446     }
    00447
    00448     QRect r = rect();
    00449     if ( d_data->scaleDraw->orientation() == Qt::Horizontal )
    00450     {
    00451         r.setLeft(r.left() + d_data->borderDist[0]);
    00452         r.setWidth(r.width() - d_data->borderDist[1]);
    00453     }
    00454     else
    00455     {
    00456         r.setTop(r.top() + d_data->borderDist[0]);
    00457         r.setHeight(r.height() - d_data->borderDist[1]);
    00458     }
    00459
    00460     if ( !d_data->title.isEmpty() )
    00461     {
    00462         QRect tr = r;
    00463         switch(d_data->scaleDraw->alignment())
    00464         {
    00465             case QwtScaleDraw::LeftScale:
    00466                 tr.setRight( r.right() - d_data->titleOffset );
    00467                 break;
    00468
    00469             case QwtScaleDraw::RightScale:
    00470                 tr.setLeft( r.left() + d_data->titleOffset );
    00471                 break;
    00472
    00473             case QwtScaleDraw::BottomScale:
    00474                 tr.setTop( r.top() + d_data->titleOffset );
    00475                 break;
    00476
    00477             case QwtScaleDraw::TopScale:
    00478             default:
    00479                 tr.setBottom( r.bottom() - d_data->titleOffset );
    00480                 break;
    00481         }
    00482
    00483         drawTitle(painter, d_data->scaleDraw->alignment(), tr);
    00484     }
    00485 }
    00486
    00487 QRect QwtScaleWidget::colorBarRect(const QRect& rect) const
    00488 {
    00489     QRect cr = rect;
    00490
    00491     if ( d_data->scaleDraw->orientation() == Qt::Horizontal )
    00492     {
    00493         cr.setLeft(cr.left() + d_data->borderDist[0]);
    00494         cr.setWidth(cr.width() - d_data->borderDist[1] + 1);
    00495     }
    00496     else
    00497     {
    00498         cr.setTop(cr.top() + d_data->borderDist[0]);
    00499         cr.setHeight(cr.height() - d_data->borderDist[1] + 1);
    00500     }
    00501
    00502     switch(d_data->scaleDraw->alignment())
    00503     {
    00504         case QwtScaleDraw::LeftScale:
    00505         {
    00506             cr.setLeft( cr.right() - d_data->spacing
    00507                 - d_data->colorBar.width + 1 );
    00508             cr.setWidth(d_data->colorBar.width);
    00509             break;
    00510         }
    00511
    00512         case QwtScaleDraw::RightScale:
    00513         {
    00514             cr.setLeft( cr.left() + d_data->spacing );
    00515             cr.setWidth(d_data->colorBar.width);
    00516             break;
    00517         }
    00518
    00519         case QwtScaleDraw::BottomScale:
    00520         {
    00521             cr.setTop( cr.top() + d_data->spacing );
    00522             cr.setHeight(d_data->colorBar.width);
    00523             break;
    00524         }
    00525
    00526         case QwtScaleDraw::TopScale:
    00527         {
    00528             cr.setTop( cr.bottom() - d_data->spacing
    00529                 - d_data->colorBar.width + 1 );
    00530             cr.setHeight(d_data->colorBar.width);
    00531             break;
    00532         }
    00533     }
    00534
    00535     return cr;
    00536 }
    00537
    00541 void QwtScaleWidget::resizeEvent(QResizeEvent *)
    00542 {
    00543     layoutScale(false);
    00544 }
    00545
    00547 //  the current rect and fonts.
    00548 //  \param update_geometry   notify the layout system and call update
    00549 //         to redraw the scale
    00550
    00551 void QwtScaleWidget::layoutScale( bool update_geometry )
    00552 {
    00553     int bd0, bd1;
    00554     getBorderDistHint(bd0, bd1);
    00555     if ( d_data->borderDist[0] > bd0 )
    00556         bd0 = d_data->borderDist[0];
    00557     if ( d_data->borderDist[1] > bd1 )
    00558         bd1 = d_data->borderDist[1];
    00559
    00560     int colorBarWidth = 0;
    00561     if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() )
    00562         colorBarWidth = d_data->colorBar.width + d_data->spacing;
    00563
    00564     const QRect r = rect();
    00565     int x, y, length;
    00566
    00567     if ( d_data->scaleDraw->orientation() == Qt::Vertical )
    00568     {
    00569         y = r.top() + bd0;
    00570         length = r.height() - (bd0 + bd1);
    00571
    00572         if ( d_data->scaleDraw->alignment() == QwtScaleDraw::LeftScale )
    00573             x = r.right() - d_data->margin - colorBarWidth;
    00574         else
    00575             x = r.left() + d_data->margin + colorBarWidth;
    00576     }
    00577     else
    00578     {
    00579         x = r.left() + bd0;
    00580         length = r.width() - (bd0 + bd1);
    00581
    00582         if ( d_data->scaleDraw->alignment() == QwtScaleDraw::BottomScale )
    00583             y = r.top() + d_data->margin + colorBarWidth;
    00584         else
    00585             y = r.bottom() - d_data->margin - colorBarWidth;
    00586     }
    00587
    00588     d_data->scaleDraw->move(x, y);
    00589     d_data->scaleDraw->setLength(length);
    00590
    00591     d_data->titleOffset = d_data->margin + d_data->spacing +
    00592         colorBarWidth +
    00593         d_data->scaleDraw->extent(QPen(Qt::black, d_data->penWidth), font());
    00594
    00595     if ( update_geometry )
    00596     {
    00597       updateGeometry();
    00598       update();
    00599     }
    00600 }
    00601
    00602 void QwtScaleWidget::drawColorBar(QPainter *painter, const QRect& rect) const
    00603 {
    00604     if ( !d_data->colorBar.interval.isValid() )
    00605         return;
    00606
    00607     const QwtScaleDraw* sd = d_data->scaleDraw;
    00608
    00609     QwtPainter::drawColorBar(painter, *d_data->colorBar.colorMap,
    00610         d_data->colorBar.interval.normalized(), sd->map(),
    00611         sd->orientation(), rect);
    00612 }
    00613
    00621 void QwtScaleWidget::drawTitle(QPainter *painter,
    00622     QwtScaleDraw::Alignment align, const QRect &rect) const
    00623 {
    00624     QRect r;
    00625     double angle;
    00626     int flags = d_data->title.renderFlags() &
    00627         ~(Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter);
    00628
    00629     switch(align)
    00630     {
    00631         case QwtScaleDraw::LeftScale:
    00632             flags |= Qt::AlignTop;
    00633             angle = -90.0;
    00634             r.setRect(rect.left(), rect.bottom(), rect.height(), rect.width());
    00635             break;
    00636         case QwtScaleDraw::RightScale:
    00637             flags |= Qt::AlignTop;
    00638             angle = 90.0;
    00639             r.setRect(rect.right(), rect.top(), rect.height(), rect.width());
    00640             break;
    00641         case QwtScaleDraw::TopScale:
    00642             flags |= Qt::AlignTop;
    00643             angle = 0.0;
    00644             r = rect;
    00645             break;
    00646         case QwtScaleDraw::BottomScale:
    00647         default:
    00648             flags |= Qt::AlignBottom;
    00649             angle = 0.0;
    00650             r = rect;
    00651             break;
    00652     }
    00653
    00654     painter->save();
    00655     painter->setFont(font());
    00656 #if QT_VERSION < 0x040000
    00657     painter->setPen(colorGroup().color(QColorGroup::Text));
    00658 #else
    00659     painter->setPen(palette().color(QPalette::Text));
    00660 #endif
    00661
    00662     painter->translate(r.x(), r.y());
    00663     if (angle != 0.0)
    00664         painter->rotate(angle);
    00665
    00666     QwtText title = d_data->title;
    00667     title.setRenderFlags(flags);
    00668     title.draw(painter, QRect(0, 0, r.width(), r.height()));
    00669
    00670     painter->restore();
    00671 }
    00672
    00681 void QwtScaleWidget::scaleChange()
    00682 {
    00683     layoutScale();
    00684 }
    00685
    00689 QSize QwtScaleWidget::sizeHint() const
    00690 {
    00691     return minimumSizeHint();
    00692 }
    00693
    00697 QSize QwtScaleWidget::minimumSizeHint() const
    00698 {
    00699     const Qt::Orientation o = d_data->scaleDraw->orientation();
    00700
    00701     // Border Distance cannot be less than the scale borderDistHint
    00702     // Note, the borderDistHint is already included in minHeight/minWidth
    00703     int length = 0;
    00704     int mbd1, mbd2;
    00705     getBorderDistHint(mbd1, mbd2);
    00706     length += qwtMax( 0, d_data->borderDist[0] - mbd1 );
    00707     length += qwtMax( 0, d_data->borderDist[1] - mbd2 );
    00708     length += d_data->scaleDraw->minLength(
    00709         QPen(Qt::black, d_data->penWidth), font());
    00710
    00711     int dim = dimForLength(length, font());
    00712     if ( length < dim )
    00713     {
    00714         // compensate for long titles
    00715         length = dim;
    00716         dim = dimForLength(length, font());
    00717     }
    00718
    00719     QSize size(length + 2, dim);
    00720     if ( o == Qt::Vertical )
    00721         size.transpose();
    00722
    00723     return size;
    00724 }
    00725
    00732 int QwtScaleWidget::titleHeightForWidth(int width) const
    00733 {
    00734     return d_data->title.heightForWidth(width, font());
    00735 }
    00736
    00746 int QwtScaleWidget::dimForLength(int length, const QFont &scaleFont) const
    00747 {
    00748     int dim = d_data->margin;
    00749     dim += d_data->scaleDraw->extent(
    00750         QPen(Qt::black, d_data->penWidth), scaleFont);
    00751
    00752     if ( !d_data->title.isEmpty() )
    00753         dim += titleHeightForWidth(length) + d_data->spacing;
    00754
    00755     if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() )
    00756         dim += d_data->colorBar.width + d_data->spacing;
    00757
    00758     return dim;
    00759 }
    00760
    00774 void QwtScaleWidget::getBorderDistHint(int &start, int &end) const
    00775 {
    00776     d_data->scaleDraw->getBorderDistHint(font(), start, end);
    00777
    00778     if ( start < d_data->minBorderDist[0] )
    00779         start = d_data->minBorderDist[0];
    00780
    00781     if ( end < d_data->minBorderDist[1] )
    00782         end = d_data->minBorderDist[1];
    00783 }
    00784
    00793 void QwtScaleWidget::setMinBorderDist(int start, int end)
    00794 {
    00795     d_data->minBorderDist[0] = start;
    00796     d_data->minBorderDist[1] = end;
    00797 }
    00798
    00805 void QwtScaleWidget::getMinBorderDist(int &start, int &end) const
    00806 {
    00807     start = d_data->minBorderDist[0];
    00808     end = d_data->minBorderDist[1];
    00809 }
    00810
    00811 #if QT_VERSION < 0x040000
    00812
    00821 void QwtScaleWidget::fontChange(const QFont &oldFont)
    00822 {
    00823     QWidget::fontChange( oldFont );
    00824     layoutScale();
    00825 }
    00826
    00827 #endif
    00828
    00839 void QwtScaleWidget::setScaleDiv(
    00840     QwtScaleTransformation *transformation,
    00841     const QwtScaleDiv &scaleDiv)
    00842 {
    00843     QwtScaleDraw *sd = d_data->scaleDraw;
    00844     if (sd->scaleDiv() != scaleDiv ||
    00845         sd->map().transformation()->type() != transformation->type() )
    00846     {
    00847         sd->setTransformation(transformation);
    00848         sd->setScaleDiv(scaleDiv);
    00849         layoutScale();
    00850
    00851         emit scaleDivChanged();
    00852     }
    00853     else
    00854         delete transformation;
    00855 }
    00856
    00857 void QwtScaleWidget::setColorBarEnabled(bool on)
    00858 {
    00859     if ( on != d_data->colorBar.isEnabled )
    00860     {
    00861         d_data->colorBar.isEnabled = on;
    00862         layoutScale();
    00863     }
    00864 }
    00865
    00866 bool QwtScaleWidget::isColorBarEnabled() const
    00867 {
    00868     return d_data->colorBar.isEnabled;
    00869 }
    00870
    00871
    00872 void QwtScaleWidget::setColorBarWidth(int width)
    00873 {
    00874     if ( width != d_data->colorBar.width )
    00875     {
    00876         d_data->colorBar.width = width;
    00877         if ( isColorBarEnabled() )
    00878             layoutScale();
    00879     }
    00880 }
    00881
    00882 int QwtScaleWidget::colorBarWidth() const
    00883 {
    00884     return d_data->colorBar.width;
    00885 }
    00886
    00887 QwtDoubleInterval QwtScaleWidget::colorBarInterval() const
    00888 {
    00889     return d_data->colorBar.interval;
    00890 }
    00891
    00892 void QwtScaleWidget::setColorMap(const QwtDoubleInterval &interval,
    00893     const QwtColorMap &colorMap)
    00894 {
    00895     d_data->colorBar.interval = interval;
    00896
    00897     delete d_data->colorBar.colorMap;
    00898     d_data->colorBar.colorMap = colorMap.copy();
    00899
    00900     if ( isColorBarEnabled() )
    00901         layoutScale();
    00902 }
    00903
    00904 const QwtColorMap &QwtScaleWidget::colorMap() const
    00905 {
    00906     return *d_data->colorBar.colorMap;
    00907 }