qwt_slider.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 <math.h>
00013 #include <qevent.h>
00014 #include <qdrawutil.h>
00015 #include <qpainter.h>
00016 #include "qwt_painter.h"
00017 #include "qwt_paint_buffer.h"
00018 #include "qwt_scale_draw.h"
00019 #include "qwt_scale_map.h"
00020 #include "qwt_slider.h"
00021 
00022 class QwtSlider::PrivateData
00023 {
00024 public:
00025     QRect sliderRect;
00026 
00027     int thumbLength;
00028     int thumbWidth;
00029     int borderWidth;
00030     int scaleDist;
00031     int xMargin;
00032     int yMargin;
00033 
00034     QwtSlider::ScalePos scalePos;
00035     QwtSlider::BGSTYLE bgStyle;
00036 
00037     /*
00038       Scale and values might have different maps. This is
00039       confusing and I can't see strong arguments for such
00040       a feature. TODO ...
00041      */
00042     QwtScaleMap map; // linear map
00043     mutable QSize sizeHintCache;
00044 };
00045 
00064 QwtSlider::QwtSlider(QWidget *parent,
00065         Qt::Orientation orientation, ScalePos scalePos, BGSTYLE bgStyle): 
00066     QwtAbstractSlider(orientation, parent)
00067 {
00068     initSlider(orientation, scalePos, bgStyle);
00069 }
00070 
00071 #if QT_VERSION < 0x040000
00072 
00081 QwtSlider::QwtSlider(QWidget *parent, const char* name):
00082     QwtAbstractSlider(Qt::Horizontal, parent)
00083 {
00084     setName(name);
00085     initSlider(Qt::Horizontal, NoScale, BgTrough);
00086 }
00087 #endif
00088 
00089 void QwtSlider::initSlider(Qt::Orientation orientation, 
00090     ScalePos scalePos, BGSTYLE bgStyle)
00091 {
00092     if (orientation == Qt::Vertical) 
00093         setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
00094     else
00095         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00096 
00097 #if QT_VERSION >= 0x040000
00098     setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00099 #else
00100     clearWState( WState_OwnSizePolicy );
00101 #endif
00102 
00103 
00104 #if QT_VERSION < 0x040000
00105     setWFlags(Qt::WNoAutoErase);
00106 #endif
00107 
00108     d_data = new QwtSlider::PrivateData;
00109 
00110     d_data->borderWidth = 2;
00111     d_data->scaleDist = 4;
00112     d_data->scalePos = scalePos;
00113     d_data->xMargin = 0;
00114     d_data->yMargin = 0;
00115     d_data->bgStyle = bgStyle;
00116 
00117     if (bgStyle == BgSlot)
00118     {
00119         d_data->thumbLength = 16;
00120         d_data->thumbWidth = 30;
00121     }
00122     else
00123     {
00124         d_data->thumbLength = 31;
00125         d_data->thumbWidth = 16;
00126     }
00127 
00128     d_data->sliderRect.setRect(0,0,8,8);
00129 
00130     QwtScaleDraw::Alignment align;
00131     if ( orientation == Qt::Vertical )
00132     {
00133         // enforce a valid combination of scale position and orientation
00134         if ((d_data->scalePos == BottomScale) || (d_data->scalePos == TopScale))
00135             d_data->scalePos = NoScale;
00136         // adopt the policy of layoutSlider (NoScale lays out like Left)
00137         if (d_data->scalePos == RightScale)
00138            align = QwtScaleDraw::RightScale;
00139         else
00140            align = QwtScaleDraw::LeftScale;
00141     }
00142     else
00143     {
00144         // enforce a valid combination of scale position and orientation
00145         if ((d_data->scalePos == LeftScale) || (d_data->scalePos == RightScale))
00146             d_data->scalePos = NoScale;
00147         // adopt the policy of layoutSlider (NoScale lays out like Bottom)
00148         if (d_data->scalePos == TopScale)
00149            align = QwtScaleDraw::TopScale;
00150         else
00151            align = QwtScaleDraw::BottomScale;
00152     }
00153 
00154     scaleDraw()->setAlignment(align);
00155     scaleDraw()->setLength(100);
00156 
00157     setRange(0.0, 100.0, 1.0);
00158     setValue(0.0);
00159 }
00160 
00161 QwtSlider::~QwtSlider()
00162 {
00163     delete d_data;
00164 }
00165 
00174 void QwtSlider::setOrientation(Qt::Orientation o) 
00175 {
00176     if ( o == orientation() )
00177         return;
00178 
00179     if (o == Qt::Horizontal)
00180     {
00181         if ((d_data->scalePos == LeftScale) || (d_data->scalePos == RightScale))
00182             d_data->scalePos = NoScale;
00183     }
00184     else // if (o == Qt::Vertical)
00185     {
00186         if ((d_data->scalePos == BottomScale) || (d_data->scalePos == TopScale))
00187             d_data->scalePos = NoScale;
00188     }
00189 
00190 #if QT_VERSION >= 0x040000
00191     if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
00192 #else
00193     if ( !testWState( WState_OwnSizePolicy ) ) 
00194 #endif
00195     {
00196         QSizePolicy sp = sizePolicy();
00197         sp.transpose();
00198         setSizePolicy(sp);
00199 
00200 #if QT_VERSION >= 0x040000
00201         setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00202 #else
00203         clearWState( WState_OwnSizePolicy );
00204 #endif
00205     }
00206 
00207     QwtAbstractSlider::setOrientation(o);
00208     layoutSlider();
00209 }
00210 
00224 void QwtSlider::setScalePosition(ScalePos s)
00225 {
00226     if ( d_data->scalePos == s )
00227         return;
00228 
00229     d_data->scalePos = s;
00230 
00231     switch(d_data->scalePos)
00232     {
00233         case BottomScale:
00234         {
00235             setOrientation(Qt::Horizontal);
00236             scaleDraw()->setAlignment(QwtScaleDraw::BottomScale);
00237             break;
00238         }
00239         case TopScale:
00240         {
00241             setOrientation(Qt::Horizontal);
00242             scaleDraw()->setAlignment(QwtScaleDraw::TopScale);
00243             break;
00244         }
00245         case LeftScale:
00246         {
00247             setOrientation(Qt::Vertical);
00248             scaleDraw()->setAlignment(QwtScaleDraw::LeftScale);
00249             break;
00250         }
00251         case RightScale:
00252         {
00253             setOrientation(Qt::Vertical);
00254             scaleDraw()->setAlignment(QwtScaleDraw::RightScale);
00255             break;
00256         }
00257         default:
00258         {
00259             // nothing
00260         }
00261     }
00262 
00263     layoutSlider();
00264 }
00265 
00267 QwtSlider::ScalePos QwtSlider::scalePosition() const
00268 {
00269     return d_data->scalePos;
00270 }
00271 
00276 void QwtSlider::setBorderWidth(int bd)
00277 {
00278     if ( bd < 0 )
00279         bd = 0;
00280 
00281     if ( bd != d_data->borderWidth )
00282     {
00283         d_data->borderWidth = bd;
00284         layoutSlider();
00285     }
00286 }
00287 
00292 void QwtSlider::setThumbLength(int thumbLength)
00293 {
00294     if ( thumbLength < 8 )
00295         thumbLength = 8;
00296 
00297     if ( thumbLength != d_data->thumbLength )
00298     {
00299         d_data->thumbLength = thumbLength;
00300         layoutSlider();
00301     }
00302 }
00303 
00308 void QwtSlider::setThumbWidth(int w)
00309 {
00310     if ( w < 4 )
00311         w = 4;
00312 
00313     if ( d_data->thumbWidth != w )
00314     {
00315         d_data->thumbWidth = w;
00316         layoutSlider();
00317     }
00318 }
00319 
00331 void QwtSlider::setScaleDraw(QwtScaleDraw *scaleDraw)
00332 {
00333     const QwtScaleDraw *previousScaleDraw = this->scaleDraw();
00334     if ( scaleDraw == NULL || scaleDraw == previousScaleDraw )
00335         return;
00336 
00337     if ( previousScaleDraw )
00338         scaleDraw->setAlignment(previousScaleDraw->alignment());
00339 
00340     setAbstractScaleDraw(scaleDraw);
00341     layoutSlider();
00342 }
00343 
00348 const QwtScaleDraw *QwtSlider::scaleDraw() const
00349 {
00350     return (QwtScaleDraw *)abstractScaleDraw();
00351 }
00352 
00357 QwtScaleDraw *QwtSlider::scaleDraw()
00358 {
00359     return (QwtScaleDraw *)abstractScaleDraw();
00360 }
00361 
00363 void QwtSlider::scaleChange()
00364 {
00365     layoutSlider();
00366 }
00367 
00368 
00370 void QwtSlider::fontChange(const QFont &f)
00371 {
00372     QwtAbstractSlider::fontChange( f );
00373     layoutSlider();
00374 }
00375 
00377 void QwtSlider::drawSlider(QPainter *p, const QRect &r)
00378 {
00379     QRect cr(r);
00380 
00381     if (d_data->bgStyle & BgTrough)
00382     {
00383         qDrawShadePanel(p, r.x(), r.y(),
00384             r.width(), r.height(),
00385 #if QT_VERSION < 0x040000
00386             colorGroup(), 
00387 #else
00388             palette(), 
00389 #endif
00390             true, d_data->borderWidth,0);
00391 
00392         cr.setRect(r.x() + d_data->borderWidth,
00393             r.y() + d_data->borderWidth,
00394             r.width() - 2 * d_data->borderWidth,
00395             r.height() - 2 * d_data->borderWidth);
00396 
00397         p->fillRect(cr.x(), cr.y(), cr.width(), cr.height(), 
00398 #if QT_VERSION < 0x040000
00399             colorGroup().brush(QColorGroup::Mid)
00400 #else
00401             palette().brush(QPalette::Mid)
00402 #endif
00403         );
00404     }
00405 
00406     if ( d_data->bgStyle & BgSlot)
00407     {
00408         int ws = 4;
00409         int ds = d_data->thumbLength / 2 - 4;
00410         if ( ds < 1 )
00411             ds = 1;
00412 
00413         QRect rSlot;
00414         if (orientation() == Qt::Horizontal)
00415         {
00416             if ( cr.height() & 1 )
00417                 ws++;
00418             rSlot = QRect(cr.x() + ds, 
00419                     cr.y() + (cr.height() - ws) / 2,
00420                     cr.width() - 2 * ds, ws);
00421         }
00422         else
00423         {
00424             if ( cr.width() & 1 )
00425                 ws++;
00426             rSlot = QRect(cr.x() + (cr.width() - ws) / 2, 
00427                     cr.y() + ds,
00428                     ws, cr.height() - 2 * ds);
00429         }
00430         p->fillRect(rSlot.x(), rSlot.y(), rSlot.width(), rSlot.height(),
00431 #if QT_VERSION < 0x040000
00432             colorGroup().brush(QColorGroup::Dark)
00433 #else
00434             palette().brush(QPalette::Dark)
00435 #endif
00436         );
00437         qDrawShadePanel(p, rSlot.x(), rSlot.y(),
00438             rSlot.width(), rSlot.height(), 
00439 #if QT_VERSION < 0x040000
00440             colorGroup(), 
00441 #else
00442             palette(), 
00443 #endif
00444             true, 1 ,0);
00445 
00446     }
00447 
00448     if ( isValid() )
00449         drawThumb(p, cr, xyPosition(value()));
00450 }
00451 
00453 void QwtSlider::drawThumb(QPainter *p, const QRect &sliderRect, int pos)
00454 {
00455     pos++; // shade line points one pixel below
00456     if (orientation() == Qt::Horizontal)
00457     {
00458         qDrawShadePanel(p, pos - d_data->thumbLength / 2, 
00459             sliderRect.y(), d_data->thumbLength, sliderRect.height(),
00460 #if QT_VERSION < 0x040000
00461             colorGroup(), 
00462 #else
00463             palette(), 
00464 #endif
00465             false, d_data->borderWidth, 
00466 #if QT_VERSION < 0x040000
00467             &colorGroup().brush(QColorGroup::Button)
00468 #else
00469             &palette().brush(QPalette::Button)
00470 #endif
00471         );
00472 
00473         qDrawShadeLine(p, pos, sliderRect.y(), 
00474             pos, sliderRect.y() + sliderRect.height() - 2, 
00475 #if QT_VERSION < 0x040000
00476             colorGroup(), 
00477 #else
00478             palette(), 
00479 #endif
00480             true, 1);
00481     }
00482     else // Vertical
00483     {
00484         qDrawShadePanel(p,sliderRect.x(), pos - d_data->thumbLength / 2, 
00485             sliderRect.width(), d_data->thumbLength,
00486 #if QT_VERSION < 0x040000
00487             colorGroup(),
00488 #else
00489             palette(), 
00490 #endif
00491             false, d_data->borderWidth, 
00492 #if QT_VERSION < 0x040000
00493             &colorGroup().brush(QColorGroup::Button)
00494 #else
00495             &palette().brush(QPalette::Button)
00496 #endif
00497         );
00498 
00499         qDrawShadeLine(p, sliderRect.x(), pos,
00500             sliderRect.x() + sliderRect.width() - 2, pos, 
00501 #if QT_VERSION < 0x040000
00502             colorGroup(), 
00503 #else
00504             palette(), 
00505 #endif
00506             true, 1);
00507     }
00508 }
00509 
00511 int QwtSlider::xyPosition(double v) const
00512 {
00513     return d_data->map.transform(v);
00514 }
00515 
00517 double QwtSlider::getValue(const QPoint &p)
00518 {
00519     return d_data->map.invTransform(
00520         orientation() == Qt::Horizontal ? p.x() : p.y());
00521 }
00522 
00523 
00530 void QwtSlider::getScrollMode(const QPoint &p, 
00531     int &scrollMode, int &direction )
00532 {
00533     if (!d_data->sliderRect.contains(p))
00534     {
00535         scrollMode = ScrNone;
00536         direction = 0;
00537         return;
00538     }
00539 
00540     const int pos = ( orientation() == Qt::Horizontal ) ? p.x() : p.y();
00541     const int markerPos = xyPosition(value());
00542 
00543     if ((pos > markerPos - d_data->thumbLength / 2)
00544         && (pos < markerPos + d_data->thumbLength / 2))
00545     {
00546         scrollMode = ScrMouse;
00547         direction = 0;
00548         return;
00549     }
00550 
00551     scrollMode = ScrPage;
00552     direction = (pos > markerPos) ? 1 : -1;
00553 
00554     if ( scaleDraw()->map().p1() > scaleDraw()->map().p2() )
00555         direction = -direction;
00556 }
00557 
00559 void QwtSlider::paintEvent(QPaintEvent *e)
00560 {
00561     const QRect &ur = e->rect();
00562     if ( ur.isValid() )
00563     {
00564 #if QT_VERSION < 0x040000
00565         QwtPaintBuffer paintBuffer(this, ur);
00566         draw(paintBuffer.painter(), ur);
00567 #else
00568         QPainter painter(this);
00569         draw(&painter, ur);
00570 #endif
00571     }
00572 }
00573 
00575 void QwtSlider::draw(QPainter *painter, const QRect&)
00576 {
00577     if (d_data->scalePos != NoScale)
00578     {
00579 #if QT_VERSION < 0x040000
00580         scaleDraw()->draw(painter, colorGroup());
00581 #else
00582         scaleDraw()->draw(painter, palette());
00583 #endif
00584     }
00585 
00586     drawSlider(painter, d_data->sliderRect);
00587 
00588     if ( hasFocus() )
00589         QwtPainter::drawFocusRect(painter, this, d_data->sliderRect);
00590 }
00591 
00593 void QwtSlider::resizeEvent(QResizeEvent *)
00594 {
00595     layoutSlider( false );
00596 }
00597 
00604 void QwtSlider::layoutSlider( bool update_geometry )
00605 {
00606     int sliderWidth = d_data->thumbWidth;
00607     int sld1 = d_data->thumbLength / 2 - 1;
00608     int sld2 = d_data->thumbLength / 2 + d_data->thumbLength % 2;
00609     if ( d_data->bgStyle & BgTrough )
00610     {
00611         sliderWidth += 2 * d_data->borderWidth;
00612         sld1 += d_data->borderWidth;
00613         sld2 += d_data->borderWidth;
00614     }
00615 
00616     int scd = 0;
00617     if ( d_data->scalePos != NoScale )
00618     {
00619         int d1, d2;
00620         scaleDraw()->getBorderDistHint(font(), d1, d2);
00621         scd = qwtMax(d1, d2);
00622     }
00623 
00624     int slo = scd - sld1;
00625     if ( slo < 0 )
00626         slo = 0;
00627 
00628     int x, y, length;
00629 
00630     const QRect r = rect();
00631     if (orientation() == Qt::Horizontal)
00632     {
00633         switch (d_data->scalePos)
00634         {
00635             case TopScale:
00636             {
00637                 d_data->sliderRect.setRect(
00638                     r.x() + d_data->xMargin + slo,
00639                     r.y() + r.height() -
00640                     d_data->yMargin - sliderWidth,
00641                     r.width() - 2 * d_data->xMargin - 2 * slo,
00642                     sliderWidth);
00643 
00644                 x = d_data->sliderRect.x() + sld1;
00645                 y = d_data->sliderRect.y() - d_data->scaleDist;
00646 
00647                 break;
00648             }
00649 
00650             case BottomScale:
00651             {
00652                 d_data->sliderRect.setRect(
00653                     r.x() + d_data->xMargin + slo,
00654                     r.y() + d_data->yMargin,
00655                     r.width() - 2 * d_data->xMargin - 2 * slo,
00656                     sliderWidth);
00657     
00658                 x = d_data->sliderRect.x() + sld1;
00659                 y = d_data->sliderRect.y() + d_data->sliderRect.height() 
00660                     + d_data->scaleDist;
00661 
00662                 break;
00663             }
00664 
00665             case NoScale: // like Bottom, but no scale. See QwtSlider().
00666             default:   // inconsistent orientation and scale position
00667             {
00668                 d_data->sliderRect.setRect(
00669                     r.x() + d_data->xMargin + slo,
00670                     r.y() + d_data->yMargin,
00671                     r.width() - 2 * d_data->xMargin - 2 * slo,
00672                     sliderWidth);
00673 
00674                 x = d_data->sliderRect.x() + sld1;
00675                 y = 0;
00676 
00677                 break;
00678             }
00679         }
00680         length = d_data->sliderRect.width() - (sld1 + sld2);
00681     }
00682     else // if (orientation() == Qt::Vertical
00683     {
00684         switch (d_data->scalePos)
00685         {
00686             case RightScale:
00687                 d_data->sliderRect.setRect(
00688                     r.x() + d_data->xMargin,
00689                     r.y() + d_data->yMargin + slo,
00690                     sliderWidth,
00691                     r.height() - 2 * d_data->yMargin - 2 * slo);
00692 
00693                 x = d_data->sliderRect.x() + d_data->sliderRect.width() 
00694                     + d_data->scaleDist;
00695                 y = d_data->sliderRect.y() + sld1;
00696 
00697                 break;
00698 
00699             case LeftScale:
00700                 d_data->sliderRect.setRect(
00701                     r.x() + r.width() - sliderWidth - d_data->xMargin,
00702                     r.y() + d_data->yMargin + slo,
00703                     sliderWidth,
00704                     r.height() - 2 * d_data->yMargin - 2 * slo);
00705 
00706                 x = d_data->sliderRect.x() - d_data->scaleDist;
00707                 y = d_data->sliderRect.y() + sld1;
00708 
00709                 break;
00710 
00711             case NoScale: // like Left, but no scale. See QwtSlider().
00712             default:   // inconsistent orientation and scale position
00713                 d_data->sliderRect.setRect(
00714                     r.x() + r.width() - sliderWidth - d_data->xMargin,
00715                     r.y() + d_data->yMargin + slo,
00716                     sliderWidth,
00717                     r.height() - 2 * d_data->yMargin - 2 * slo);
00718 
00719                 x = 0;
00720                 y = d_data->sliderRect.y() + sld1;
00721 
00722                 break;
00723         }
00724         length = d_data->sliderRect.height() - (sld1 + sld2);
00725     }
00726 
00727     scaleDraw()->move(x, y);
00728     scaleDraw()->setLength(length);
00729 
00730     d_data->map.setPaintXInterval(scaleDraw()->map().p1(),
00731         scaleDraw()->map().p2());
00732 
00733     if ( update_geometry )
00734     {
00735         d_data->sizeHintCache = QSize(); // invalidate
00736         updateGeometry();
00737         update();
00738     }
00739 }
00740 
00742 void QwtSlider::valueChange()
00743 {
00744     QwtAbstractSlider::valueChange();
00745     update();
00746 }
00747 
00748 
00750 void QwtSlider::rangeChange()
00751 {
00752     d_data->map.setScaleInterval(minValue(), maxValue());
00753 
00754     if (autoScale())
00755         rescale(minValue(), maxValue());
00756 
00757     QwtAbstractSlider::rangeChange();
00758     layoutSlider();
00759 }
00760 
00766 void QwtSlider::setMargins(int xMargin, int yMargin)
00767 {
00768     if ( xMargin < 0 )
00769         xMargin = 0;
00770     if ( yMargin < 0 )
00771         yMargin = 0;
00772 
00773     if ( xMargin != d_data->xMargin || yMargin != d_data->yMargin )
00774     {
00775         d_data->xMargin = xMargin;
00776         d_data->yMargin = yMargin;
00777         layoutSlider();
00778     }
00779 }
00780 
00784 void QwtSlider::setBgStyle(BGSTYLE st) 
00785 {
00786     d_data->bgStyle = st; 
00787     layoutSlider();
00788 }
00789 
00793 QwtSlider::BGSTYLE QwtSlider::bgStyle() const 
00794 { 
00795     return d_data->bgStyle; 
00796 }
00797 
00801 int QwtSlider::thumbLength() const 
00802 {
00803     return d_data->thumbLength;
00804 }
00805 
00809 int QwtSlider::thumbWidth() const 
00810 {
00811     return d_data->thumbWidth;
00812 }
00813 
00817 int QwtSlider::borderWidth() const 
00818 {
00819     return d_data->borderWidth;
00820 }
00821 
00825 QSize QwtSlider::sizeHint() const
00826 {
00827     return minimumSizeHint();
00828 }
00829 
00835 QSize QwtSlider::minimumSizeHint() const
00836 {
00837     if (!d_data->sizeHintCache.isEmpty()) 
00838         return d_data->sizeHintCache;
00839 
00840     int sliderWidth = d_data->thumbWidth;
00841     if (d_data->bgStyle & BgTrough)
00842         sliderWidth += 2 * d_data->borderWidth;
00843 
00844     int w = 0, h = 0;
00845     if (d_data->scalePos != NoScale)
00846     {
00847         int d1, d2;
00848         scaleDraw()->getBorderDistHint(font(), d1, d2);
00849         int msMbd = qwtMax(d1, d2);
00850 
00851         int mbd = d_data->thumbLength / 2;
00852         if (d_data->bgStyle & BgTrough)
00853             mbd += d_data->borderWidth;
00854 
00855         if ( mbd < msMbd )
00856             mbd = msMbd;
00857 
00858         const int sdExtent = scaleDraw()->extent( QPen(), font() );
00859         const int sdLength = scaleDraw()->minLength( QPen(), font() );
00860 
00861         h = sliderWidth + sdExtent + d_data->scaleDist;
00862         w = sdLength - 2 * msMbd + 2 * mbd;
00863     }
00864     else  // no scale
00865     {
00866         w = 200;
00867         h = sliderWidth;
00868     }
00869 
00870     if ( orientation() == Qt::Vertical )
00871         qSwap(w, h);
00872 
00873     w += 2 * d_data->xMargin;
00874     h += 2 * d_data->yMargin;
00875 
00876     d_data->sizeHintCache = QSize(w, h);
00877     return d_data->sizeHintCache;
00878 }

Generated on Sat May 24 18:47:40 2008 for Qwt User's Guide by  doxygen 1.5.0