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 
00320 void QwtSlider::setScaleDraw(QwtScaleDraw *scaleDraw)
00321 {
00322     setAbstractScaleDraw(scaleDraw);
00323 }
00324 
00325 const QwtScaleDraw *QwtSlider::scaleDraw() const
00326 {
00327     return (QwtScaleDraw *)abstractScaleDraw();
00328 }
00329 
00330 QwtScaleDraw *QwtSlider::scaleDraw()
00331 {
00332     return (QwtScaleDraw *)abstractScaleDraw();
00333 }
00334 
00336 void QwtSlider::scaleChange()
00337 {
00338     layoutSlider();
00339 }
00340 
00341 
00343 void QwtSlider::fontChange(const QFont &f)
00344 {
00345     QwtAbstractSlider::fontChange( f );
00346     layoutSlider();
00347 }
00348 
00350 void QwtSlider::drawSlider(QPainter *p, const QRect &r)
00351 {
00352     QRect cr(r);
00353 
00354     if (d_data->bgStyle & BgTrough)
00355     {
00356         qDrawShadePanel(p, r.x(), r.y(),
00357             r.width(), r.height(),
00358 #if QT_VERSION < 0x040000
00359             colorGroup(), 
00360 #else
00361             palette(), 
00362 #endif
00363             true, d_data->borderWidth,0);
00364 
00365         cr.setRect(r.x() + d_data->borderWidth,
00366             r.y() + d_data->borderWidth,
00367             r.width() - 2 * d_data->borderWidth,
00368             r.height() - 2 * d_data->borderWidth);
00369 
00370         p->fillRect(cr.x(), cr.y(), cr.width(), cr.height(), 
00371 #if QT_VERSION < 0x040000
00372             colorGroup().brush(QColorGroup::Mid)
00373 #else
00374             palette().brush(QPalette::Mid)
00375 #endif
00376         );
00377     }
00378 
00379     if ( d_data->bgStyle & BgSlot)
00380     {
00381         int ws = 4;
00382         int ds = d_data->thumbLength / 2 - 4;
00383         if ( ds < 1 )
00384             ds = 1;
00385 
00386         QRect rSlot;
00387         if (orientation() == Qt::Horizontal)
00388         {
00389             if ( cr.height() & 1 )
00390                 ws++;
00391             rSlot = QRect(cr.x() + ds, 
00392                     cr.y() + (cr.height() - ws) / 2,
00393                     cr.width() - 2 * ds, ws);
00394         }
00395         else
00396         {
00397             if ( cr.width() & 1 )
00398                 ws++;
00399             rSlot = QRect(cr.x() + (cr.width() - ws) / 2, 
00400                     cr.y() + ds,
00401                     ws, cr.height() - 2 * ds);
00402         }
00403         p->fillRect(rSlot.x(), rSlot.y(), rSlot.width(), rSlot.height(),
00404 #if QT_VERSION < 0x040000
00405             colorGroup().brush(QColorGroup::Dark)
00406 #else
00407             palette().brush(QPalette::Dark)
00408 #endif
00409         );
00410         qDrawShadePanel(p, rSlot.x(), rSlot.y(),
00411             rSlot.width(), rSlot.height(), 
00412 #if QT_VERSION < 0x040000
00413             colorGroup(), 
00414 #else
00415             palette(), 
00416 #endif
00417             true, 1 ,0);
00418 
00419     }
00420 
00421     if ( isValid() )
00422         drawThumb(p, cr, xyPosition(value()));
00423 }
00424 
00426 void QwtSlider::drawThumb(QPainter *p, const QRect &sliderRect, int pos)
00427 {
00428     pos++; // shade line points one pixel below
00429     if (orientation() == Qt::Horizontal)
00430     {
00431         qDrawShadePanel(p, pos - d_data->thumbLength / 2, 
00432             sliderRect.y(), d_data->thumbLength, sliderRect.height(),
00433 #if QT_VERSION < 0x040000
00434             colorGroup(), 
00435 #else
00436             palette(), 
00437 #endif
00438             false, d_data->borderWidth, 
00439 #if QT_VERSION < 0x040000
00440             &colorGroup().brush(QColorGroup::Button)
00441 #else
00442             &palette().brush(QPalette::Button)
00443 #endif
00444         );
00445 
00446         qDrawShadeLine(p, pos, sliderRect.y(), 
00447             pos, sliderRect.y() + sliderRect.height() - 2, 
00448 #if QT_VERSION < 0x040000
00449             colorGroup(), 
00450 #else
00451             palette(), 
00452 #endif
00453             true, 1);
00454     }
00455     else // Vertical
00456     {
00457         qDrawShadePanel(p,sliderRect.x(), pos - d_data->thumbLength / 2, 
00458             sliderRect.width(), d_data->thumbLength,
00459 #if QT_VERSION < 0x040000
00460             colorGroup(),
00461 #else
00462             palette(), 
00463 #endif
00464             false, d_data->borderWidth, 
00465 #if QT_VERSION < 0x040000
00466             &colorGroup().brush(QColorGroup::Button)
00467 #else
00468             &palette().brush(QPalette::Button)
00469 #endif
00470         );
00471 
00472         qDrawShadeLine(p, sliderRect.x(), pos,
00473             sliderRect.x() + sliderRect.width() - 2, pos, 
00474 #if QT_VERSION < 0x040000
00475             colorGroup(), 
00476 #else
00477             palette(), 
00478 #endif
00479             true, 1);
00480     }
00481 }
00482 
00484 int QwtSlider::xyPosition(double v) const
00485 {
00486     return d_data->map.transform(v);
00487 }
00488 
00490 double QwtSlider::getValue(const QPoint &p)
00491 {
00492     return d_data->map.invTransform(
00493         orientation() == Qt::Horizontal ? p.x() : p.y());
00494 }
00495 
00496 
00503 void QwtSlider::getScrollMode(const QPoint &p, 
00504     int &scrollMode, int &direction )
00505 {
00506     if (!d_data->sliderRect.contains(p))
00507     {
00508         scrollMode = ScrNone;
00509         direction = 0;
00510         return;
00511     }
00512 
00513     const int pos = ( orientation() == Qt::Horizontal ) ? p.x() : p.y();
00514     const int markerPos = xyPosition(value());
00515 
00516     if ((pos > markerPos - d_data->thumbLength / 2)
00517         && (pos < markerPos + d_data->thumbLength / 2))
00518     {
00519         scrollMode = ScrMouse;
00520         direction = 0;
00521         return;
00522     }
00523 
00524     scrollMode = ScrPage;
00525     direction = (pos > markerPos) ? 1 : -1;
00526 
00527     if ( scaleDraw()->map().p1() > scaleDraw()->map().p2() )
00528         direction = -direction;
00529 }
00530 
00532 void QwtSlider::paintEvent(QPaintEvent *e)
00533 {
00534     const QRect &ur = e->rect();
00535     if ( ur.isValid() )
00536     {
00537 #if QT_VERSION < 0x040000
00538         QwtPaintBuffer paintBuffer(this, ur);
00539         draw(paintBuffer.painter(), ur);
00540 #else
00541         QPainter painter(this);
00542         draw(&painter, ur);
00543 #endif
00544     }
00545 }
00546 
00548 void QwtSlider::draw(QPainter *painter, const QRect&)
00549 {
00550     if (d_data->scalePos != NoScale)
00551     {
00552 #if QT_VERSION < 0x040000
00553         scaleDraw()->draw(painter, colorGroup());
00554 #else
00555         scaleDraw()->draw(painter, palette());
00556 #endif
00557     }
00558 
00559     drawSlider(painter, d_data->sliderRect);
00560 
00561     if ( hasFocus() )
00562         QwtPainter::drawFocusRect(painter, this, d_data->sliderRect);
00563 }
00564 
00566 void QwtSlider::resizeEvent(QResizeEvent *)
00567 {
00568     layoutSlider( false );
00569 }
00570 
00577 void QwtSlider::layoutSlider( bool update_geometry )
00578 {
00579     int sliderWidth = d_data->thumbWidth;
00580     int sld1 = d_data->thumbLength / 2 - 1;
00581     int sld2 = d_data->thumbLength / 2 + d_data->thumbLength % 2;
00582     if ( d_data->bgStyle & BgTrough )
00583     {
00584         sliderWidth += 2 * d_data->borderWidth;
00585         sld1 += d_data->borderWidth;
00586         sld2 += d_data->borderWidth;
00587     }
00588 
00589     int scd = 0;
00590     if ( d_data->scalePos != NoScale )
00591     {
00592         int d1, d2;
00593         scaleDraw()->getBorderDistHint(font(), d1, d2);
00594         scd = qwtMax(d1, d2);
00595     }
00596 
00597     int slo = scd - sld1;
00598     if ( slo < 0 )
00599         slo = 0;
00600 
00601     int x, y, length;
00602 
00603     const QRect r = rect();
00604     if (orientation() == Qt::Horizontal)
00605     {
00606         switch (d_data->scalePos)
00607         {
00608             case TopScale:
00609             {
00610                 d_data->sliderRect.setRect(
00611                     r.x() + d_data->xMargin + slo,
00612                     r.y() + r.height() -
00613                     d_data->yMargin - sliderWidth,
00614                     r.width() - 2 * d_data->xMargin - 2 * slo,
00615                     sliderWidth);
00616 
00617                 x = d_data->sliderRect.x() + sld1;
00618                 y = d_data->sliderRect.y() - d_data->scaleDist;
00619 
00620                 break;
00621             }
00622 
00623             case BottomScale:
00624             {
00625                 d_data->sliderRect.setRect(
00626                     r.x() + d_data->xMargin + slo,
00627                     r.y() + d_data->yMargin,
00628                     r.width() - 2 * d_data->xMargin - 2 * slo,
00629                     sliderWidth);
00630     
00631                 x = d_data->sliderRect.x() + sld1;
00632                 y = d_data->sliderRect.y() + d_data->sliderRect.height() 
00633                     + d_data->scaleDist;
00634 
00635                 break;
00636             }
00637 
00638             case NoScale: // like Bottom, but no scale. See QwtSlider().
00639             default:   // inconsistent orientation and scale position
00640             {
00641                 d_data->sliderRect.setRect(
00642                     r.x() + d_data->xMargin + slo,
00643                     r.y() + d_data->yMargin,
00644                     r.width() - 2 * d_data->xMargin - 2 * slo,
00645                     sliderWidth);
00646 
00647                 x = d_data->sliderRect.x() + sld1;
00648                 y = 0;
00649 
00650                 break;
00651             }
00652         }
00653         length = d_data->sliderRect.width() - (sld1 + sld2);
00654     }
00655     else // if (orientation() == Qt::Vertical
00656     {
00657         switch (d_data->scalePos)
00658         {
00659             case RightScale:
00660                 d_data->sliderRect.setRect(
00661                     r.x() + d_data->xMargin,
00662                     r.y() + d_data->yMargin + slo,
00663                     sliderWidth,
00664                     r.height() - 2 * d_data->yMargin - 2 * slo);
00665 
00666                 x = d_data->sliderRect.x() + d_data->sliderRect.width() 
00667                     + d_data->scaleDist;
00668                 y = d_data->sliderRect.y() + sld1;
00669 
00670                 break;
00671 
00672             case LeftScale:
00673                 d_data->sliderRect.setRect(
00674                     r.x() + r.width() - sliderWidth - d_data->xMargin,
00675                     r.y() + d_data->yMargin + slo,
00676                     sliderWidth,
00677                     r.height() - 2 * d_data->yMargin - 2 * slo);
00678 
00679                 x = d_data->sliderRect.x() - d_data->scaleDist;
00680                 y = d_data->sliderRect.y() + sld1;
00681 
00682                 break;
00683 
00684             case NoScale: // like Left, but no scale. See QwtSlider().
00685             default:   // inconsistent orientation and scale position
00686                 d_data->sliderRect.setRect(
00687                     r.x() + r.width() - sliderWidth - d_data->xMargin,
00688                     r.y() + d_data->yMargin + slo,
00689                     sliderWidth,
00690                     r.height() - 2 * d_data->yMargin - 2 * slo);
00691 
00692                 x = 0;
00693                 y = d_data->sliderRect.y() + sld1;
00694 
00695                 break;
00696         }
00697         length = d_data->sliderRect.height() - (sld1 + sld2);
00698     }
00699 
00700     scaleDraw()->move(x, y);
00701     scaleDraw()->setLength(length);
00702 
00703     d_data->map.setPaintXInterval(scaleDraw()->map().p1(),
00704         scaleDraw()->map().p2());
00705 
00706     if ( update_geometry )
00707     {
00708         d_data->sizeHintCache = QSize(); // invalidate
00709         updateGeometry();
00710         update();
00711     }
00712 }
00713 
00715 void QwtSlider::valueChange()
00716 {
00717     QwtAbstractSlider::valueChange();
00718     update();
00719 }
00720 
00721 
00723 void QwtSlider::rangeChange()
00724 {
00725     d_data->map.setScaleInterval(minValue(), maxValue());
00726 
00727     if (autoScale())
00728         rescale(minValue(), maxValue());
00729 
00730     QwtAbstractSlider::rangeChange();
00731     layoutSlider();
00732 }
00733 
00739 void QwtSlider::setMargins(int xMargin, int yMargin)
00740 {
00741     if ( xMargin < 0 )
00742         xMargin = 0;
00743     if ( yMargin < 0 )
00744         yMargin = 0;
00745 
00746     if ( xMargin != d_data->xMargin || yMargin != d_data->yMargin )
00747     {
00748         d_data->xMargin = xMargin;
00749         d_data->yMargin = yMargin;
00750         layoutSlider();
00751     }
00752 }
00753 
00757 void QwtSlider::setBgStyle(BGSTYLE st) 
00758 {
00759     d_data->bgStyle = st; 
00760     layoutSlider();
00761 }
00762 
00766 QwtSlider::BGSTYLE QwtSlider::bgStyle() const 
00767 { 
00768     return d_data->bgStyle; 
00769 }
00770 
00774 int QwtSlider::thumbLength() const 
00775 {
00776     return d_data->thumbLength;
00777 }
00778 
00782 int QwtSlider::thumbWidth() const 
00783 {
00784     return d_data->thumbWidth;
00785 }
00786 
00790 int QwtSlider::borderWidth() const 
00791 {
00792     return d_data->borderWidth;
00793 }
00794 
00798 QSize QwtSlider::sizeHint() const
00799 {
00800     return minimumSizeHint();
00801 }
00802 
00808 QSize QwtSlider::minimumSizeHint() const
00809 {
00810     if (!d_data->sizeHintCache.isEmpty()) 
00811         return d_data->sizeHintCache;
00812 
00813     int sliderWidth = d_data->thumbWidth;
00814     if (d_data->bgStyle & BgTrough)
00815         sliderWidth += 2 * d_data->borderWidth;
00816 
00817     int w = 0, h = 0;
00818     if (d_data->scalePos != NoScale)
00819     {
00820         int d1, d2;
00821         scaleDraw()->getBorderDistHint(font(), d1, d2);
00822         int msMbd = qwtMax(d1, d2);
00823 
00824         int mbd = d_data->thumbLength / 2;
00825         if (d_data->bgStyle & BgTrough)
00826             mbd += d_data->borderWidth;
00827 
00828         if ( mbd < msMbd )
00829             mbd = msMbd;
00830 
00831         const int sdExtent = scaleDraw()->extent( QPen(), font() );
00832         const int sdLength = scaleDraw()->minLength( QPen(), font() );
00833 
00834         h = sliderWidth + sdExtent + d_data->scaleDist;
00835         w = sdLength - 2 * msMbd + 2 * mbd;
00836     }
00837     else  // no scale
00838     {
00839         w = 200;
00840         h = sliderWidth;
00841     }
00842 
00843     if ( orientation() == Qt::Vertical )
00844         qSwap(w, h);
00845 
00846     w += 2 * d_data->xMargin;
00847     h += 2 * d_data->yMargin;
00848 
00849     d_data->sizeHintCache = QSize(w, h);
00850     return d_data->sizeHintCache;
00851 }

Generated on Thu May 1 15:44:09 2008 for Qwt User's Guide by  doxygen 1.5.0