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     d_data->scalePos = s;
00227     if ((s == BottomScale) || (s == TopScale))
00228         setOrientation(Qt::Horizontal);
00229     else if ((s == LeftScale) || (s == RightScale))
00230         setOrientation(Qt::Vertical);
00231     else
00232         layoutSlider();
00233 }
00234 
00236 QwtSlider::ScalePos QwtSlider::scalePosition() const
00237 {
00238     return d_data->scalePos;
00239 }
00240 
00245 void QwtSlider::setBorderWidth(int bd)
00246 {
00247     if ( bd < 0 )
00248         bd = 0;
00249 
00250     if ( bd != d_data->borderWidth )
00251     {
00252         d_data->borderWidth = bd;
00253         layoutSlider();
00254     }
00255 }
00256 
00261 void QwtSlider::setThumbLength(int thumbLength)
00262 {
00263     if ( thumbLength < 8 )
00264         thumbLength = 8;
00265 
00266     if ( thumbLength != d_data->thumbLength )
00267     {
00268         d_data->thumbLength = thumbLength;
00269         layoutSlider();
00270     }
00271 }
00272 
00277 void QwtSlider::setThumbWidth(int w)
00278 {
00279     if ( w < 4 )
00280         w = 4;
00281 
00282     if ( d_data->thumbWidth != w )
00283     {
00284         d_data->thumbWidth = w;
00285         layoutSlider();
00286     }
00287 }
00288 
00289 void QwtSlider::setScaleDraw(QwtScaleDraw *scaleDraw)
00290 {
00291     setAbstractScaleDraw(scaleDraw);
00292 }
00293 
00294 const QwtScaleDraw *QwtSlider::scaleDraw() const
00295 {
00296     return (QwtScaleDraw *)abstractScaleDraw();
00297 }
00298 
00299 QwtScaleDraw *QwtSlider::scaleDraw()
00300 {
00301     return (QwtScaleDraw *)abstractScaleDraw();
00302 }
00303 
00305 void QwtSlider::scaleChange()
00306 {
00307     layoutSlider();
00308 }
00309 
00310 
00312 void QwtSlider::fontChange(const QFont &f)
00313 {
00314     QwtAbstractSlider::fontChange( f );
00315     layoutSlider();
00316 }
00317 
00319 void QwtSlider::drawSlider(QPainter *p, const QRect &r)
00320 {
00321     QRect cr(r);
00322 
00323     if (d_data->bgStyle & BgTrough)
00324     {
00325         qDrawShadePanel(p, r.x(), r.y(),
00326             r.width(), r.height(),
00327 #if QT_VERSION < 0x040000
00328             colorGroup(), 
00329 #else
00330             palette(), 
00331 #endif
00332             true, d_data->borderWidth,0);
00333 
00334         cr.setRect(r.x() + d_data->borderWidth,
00335             r.y() + d_data->borderWidth,
00336             r.width() - 2 * d_data->borderWidth,
00337             r.height() - 2 * d_data->borderWidth);
00338 
00339         p->fillRect(cr.x(), cr.y(), cr.width(), cr.height(), 
00340 #if QT_VERSION < 0x040000
00341             colorGroup().brush(QColorGroup::Mid)
00342 #else
00343             palette().brush(QPalette::Mid)
00344 #endif
00345         );
00346     }
00347 
00348     if ( d_data->bgStyle & BgSlot)
00349     {
00350         int ws = 4;
00351         int ds = d_data->thumbLength / 2 - 4;
00352         if ( ds < 1 )
00353             ds = 1;
00354 
00355         QRect rSlot;
00356         if (orientation() == Qt::Horizontal)
00357         {
00358             if ( cr.height() & 1 )
00359                 ws++;
00360             rSlot = QRect(cr.x() + ds, 
00361                     cr.y() + (cr.height() - ws) / 2,
00362                     cr.width() - 2 * ds, ws);
00363         }
00364         else
00365         {
00366             if ( cr.width() & 1 )
00367                 ws++;
00368             rSlot = QRect(cr.x() + (cr.width() - ws) / 2, 
00369                     cr.y() + ds,
00370                     ws, cr.height() - 2 * ds);
00371         }
00372         p->fillRect(rSlot.x(), rSlot.y(), rSlot.width(), rSlot.height(),
00373 #if QT_VERSION < 0x040000
00374             colorGroup().brush(QColorGroup::Dark)
00375 #else
00376             palette().brush(QPalette::Dark)
00377 #endif
00378         );
00379         qDrawShadePanel(p, rSlot.x(), rSlot.y(),
00380             rSlot.width(), rSlot.height(), 
00381 #if QT_VERSION < 0x040000
00382             colorGroup(), 
00383 #else
00384             palette(), 
00385 #endif
00386             true, 1 ,0);
00387 
00388     }
00389 
00390     if ( isValid() )
00391         drawThumb(p, cr, xyPosition(value()));
00392 }
00393 
00395 void QwtSlider::drawThumb(QPainter *p, const QRect &sliderRect, int pos)
00396 {
00397     pos++; // shade line points one pixel below
00398     if (orientation() == Qt::Horizontal)
00399     {
00400         qDrawShadePanel(p, pos - d_data->thumbLength / 2, 
00401             sliderRect.y(), d_data->thumbLength, sliderRect.height(),
00402 #if QT_VERSION < 0x040000
00403             colorGroup(), 
00404 #else
00405             palette(), 
00406 #endif
00407             false, d_data->borderWidth, 
00408 #if QT_VERSION < 0x040000
00409             &colorGroup().brush(QColorGroup::Button)
00410 #else
00411             &palette().brush(QPalette::Button)
00412 #endif
00413         );
00414 
00415         qDrawShadeLine(p, pos, sliderRect.y(), 
00416             pos, sliderRect.y() + sliderRect.height() - 2, 
00417 #if QT_VERSION < 0x040000
00418             colorGroup(), 
00419 #else
00420             palette(), 
00421 #endif
00422             true, 1);
00423     }
00424     else // Vertical
00425     {
00426         qDrawShadePanel(p,sliderRect.x(), pos - d_data->thumbLength / 2, 
00427             sliderRect.width(), d_data->thumbLength,
00428 #if QT_VERSION < 0x040000
00429             colorGroup(),
00430 #else
00431             palette(), 
00432 #endif
00433             false, d_data->borderWidth, 
00434 #if QT_VERSION < 0x040000
00435             &colorGroup().brush(QColorGroup::Button)
00436 #else
00437             &palette().brush(QPalette::Button)
00438 #endif
00439         );
00440 
00441         qDrawShadeLine(p, sliderRect.x(), pos,
00442             sliderRect.x() + sliderRect.width() - 2, pos, 
00443 #if QT_VERSION < 0x040000
00444             colorGroup(), 
00445 #else
00446             palette(), 
00447 #endif
00448             true, 1);
00449     }
00450 }
00451 
00453 int QwtSlider::xyPosition(double v) const
00454 {
00455     return d_data->map.transform(v);
00456 }
00457 
00459 double QwtSlider::getValue(const QPoint &p)
00460 {
00461     return d_data->map.invTransform(
00462         orientation() == Qt::Horizontal ? p.x() : p.y());
00463 }
00464 
00465 
00472 void QwtSlider::getScrollMode(const QPoint &p, 
00473     int &scrollMode, int &direction )
00474 {
00475     if (!d_data->sliderRect.contains(p))
00476     {
00477         scrollMode = ScrNone;
00478         direction = 0;
00479         return;
00480     }
00481 
00482     const int pos = ( orientation() == Qt::Horizontal ) ? p.x() : p.y();
00483     const int markerPos = xyPosition(value());
00484 
00485     if ((pos > markerPos - d_data->thumbLength / 2)
00486         && (pos < markerPos + d_data->thumbLength / 2))
00487     {
00488         scrollMode = ScrMouse;
00489         direction = 0;
00490         return;
00491     }
00492 
00493     scrollMode = ScrPage;
00494     direction = (pos > markerPos) ? 1 : -1;
00495 
00496     if ( scaleDraw()->map().p1() > scaleDraw()->map().p2() )
00497         direction = -direction;
00498 }
00499 
00501 void QwtSlider::paintEvent(QPaintEvent *e)
00502 {
00503     const QRect &ur = e->rect();
00504     if ( ur.isValid() )
00505     {
00506 #if QT_VERSION < 0x040000
00507         QwtPaintBuffer paintBuffer(this, ur);
00508         draw(paintBuffer.painter(), ur);
00509 #else
00510         QPainter painter(this);
00511         draw(&painter, ur);
00512 #endif
00513     }
00514 }
00515 
00517 void QwtSlider::draw(QPainter *painter, const QRect&)
00518 {
00519     if (d_data->scalePos != NoScale)
00520     {
00521 #if QT_VERSION < 0x040000
00522         scaleDraw()->draw(painter, colorGroup());
00523 #else
00524         scaleDraw()->draw(painter, palette());
00525 #endif
00526     }
00527 
00528     drawSlider(painter, d_data->sliderRect);
00529 
00530     if ( hasFocus() )
00531         QwtPainter::drawFocusRect(painter, this, d_data->sliderRect);
00532 }
00533 
00535 void QwtSlider::resizeEvent(QResizeEvent *)
00536 {
00537     layoutSlider( false );
00538 }
00539 
00546 void QwtSlider::layoutSlider( bool update_geometry )
00547 {
00548     int sliderWidth = d_data->thumbWidth;
00549     int sld1 = d_data->thumbLength / 2 - 1;
00550     int sld2 = d_data->thumbLength / 2 + d_data->thumbLength % 2;
00551     if ( d_data->bgStyle & BgTrough )
00552     {
00553         sliderWidth += 2 * d_data->borderWidth;
00554         sld1 += d_data->borderWidth;
00555         sld2 += d_data->borderWidth;
00556     }
00557 
00558     int scd = 0;
00559     if ( d_data->scalePos != NoScale )
00560     {
00561         int d1, d2;
00562         scaleDraw()->getBorderDistHint(font(), d1, d2);
00563         scd = qwtMax(d1, d2);
00564     }
00565 
00566     int slo = scd - sld1;
00567     if ( slo < 0 )
00568         slo = 0;
00569 
00570     int x, y, length;
00571 
00572     const QRect r = rect();
00573     if (orientation() == Qt::Horizontal)
00574     {
00575         switch (d_data->scalePos)
00576         {
00577             case TopScale:
00578             {
00579                 d_data->sliderRect.setRect(
00580                     r.x() + d_data->xMargin + slo,
00581                     r.y() + r.height() -
00582                     d_data->yMargin - sliderWidth,
00583                     r.width() - 2 * d_data->xMargin - 2 * slo,
00584                     sliderWidth);
00585 
00586                 x = d_data->sliderRect.x() + sld1;
00587                 y = d_data->sliderRect.y() - d_data->scaleDist;
00588 
00589                 break;
00590             }
00591 
00592             case BottomScale:
00593             {
00594                 d_data->sliderRect.setRect(
00595                     r.x() + d_data->xMargin + slo,
00596                     r.y() + d_data->yMargin,
00597                     r.width() - 2 * d_data->xMargin - 2 * slo,
00598                     sliderWidth);
00599     
00600                 x = d_data->sliderRect.x() + sld1;
00601                 y = d_data->sliderRect.y() + d_data->sliderRect.height() 
00602                     + d_data->scaleDist;
00603 
00604                 break;
00605             }
00606 
00607             case NoScale: // like Bottom, but no scale. See QwtSlider().
00608             default:   // inconsistent orientation and scale position
00609             {
00610                 d_data->sliderRect.setRect(
00611                     r.x() + d_data->xMargin + slo,
00612                     r.y() + d_data->yMargin,
00613                     r.width() - 2 * d_data->xMargin - 2 * slo,
00614                     sliderWidth);
00615 
00616                 x = d_data->sliderRect.x() + sld1;
00617                 y = 0;
00618 
00619                 break;
00620             }
00621         }
00622         length = d_data->sliderRect.width() - (sld1 + sld2);
00623     }
00624     else // if (orientation() == Qt::Vertical
00625     {
00626         switch (d_data->scalePos)
00627         {
00628             case RightScale:
00629                 d_data->sliderRect.setRect(
00630                     r.x() + d_data->xMargin,
00631                     r.y() + d_data->yMargin + slo,
00632                     sliderWidth,
00633                     r.height() - 2 * d_data->yMargin - 2 * slo);
00634 
00635                 x = d_data->sliderRect.x() + d_data->sliderRect.width() 
00636                     + d_data->scaleDist;
00637                 y = d_data->sliderRect.y() + sld1;
00638 
00639                 break;
00640 
00641             case LeftScale:
00642                 d_data->sliderRect.setRect(
00643                     r.x() + r.width() - sliderWidth - d_data->xMargin,
00644                     r.y() + d_data->yMargin + slo,
00645                     sliderWidth,
00646                     r.height() - 2 * d_data->yMargin - 2 * slo);
00647 
00648                 x = d_data->sliderRect.x() - d_data->scaleDist;
00649                 y = d_data->sliderRect.y() + sld1;
00650 
00651                 break;
00652 
00653             case NoScale: // like Left, but no scale. See QwtSlider().
00654             default:   // inconsistent orientation and scale position
00655                 d_data->sliderRect.setRect(
00656                     r.x() + r.width() - sliderWidth - d_data->xMargin,
00657                     r.y() + d_data->yMargin + slo,
00658                     sliderWidth,
00659                     r.height() - 2 * d_data->yMargin - 2 * slo);
00660 
00661                 x = 0;
00662                 y = d_data->sliderRect.y() + sld1;
00663 
00664                 break;
00665         }
00666         length = d_data->sliderRect.height() - (sld1 + sld2);
00667     }
00668 
00669     scaleDraw()->move(x, y);
00670     scaleDraw()->setLength(length);
00671 
00672     d_data->map.setPaintXInterval(scaleDraw()->map().p1(),
00673         scaleDraw()->map().p2());
00674 
00675     if ( update_geometry )
00676     {
00677         d_data->sizeHintCache = QSize(); // invalidate
00678         updateGeometry();
00679         update();
00680     }
00681 }
00682 
00684 void QwtSlider::valueChange()
00685 {
00686     QwtAbstractSlider::valueChange();
00687     update();
00688 }
00689 
00690 
00692 void QwtSlider::rangeChange()
00693 {
00694     d_data->map.setScaleInterval(minValue(), maxValue());
00695 
00696     if (autoScale())
00697         rescale(minValue(), maxValue());
00698 
00699     QwtAbstractSlider::rangeChange();
00700     layoutSlider();
00701 }
00702 
00708 void QwtSlider::setMargins(int xMargin, int yMargin)
00709 {
00710     if ( xMargin < 0 )
00711         xMargin = 0;
00712     if ( yMargin < 0 )
00713         yMargin = 0;
00714 
00715     if ( xMargin != d_data->xMargin || yMargin != d_data->yMargin )
00716     {
00717         d_data->xMargin = xMargin;
00718         d_data->yMargin = yMargin;
00719         layoutSlider();
00720     }
00721 }
00722 
00726 void QwtSlider::setBgStyle(BGSTYLE st) 
00727 {
00728     d_data->bgStyle = st; 
00729     layoutSlider();
00730 }
00731 
00735 QwtSlider::BGSTYLE QwtSlider::bgStyle() const 
00736 { 
00737     return d_data->bgStyle; 
00738 }
00739 
00743 int QwtSlider::thumbLength() const 
00744 {
00745     return d_data->thumbLength;
00746 }
00747 
00751 int QwtSlider::thumbWidth() const 
00752 {
00753     return d_data->thumbWidth;
00754 }
00755 
00759 int QwtSlider::borderWidth() const 
00760 {
00761     return d_data->borderWidth;
00762 }
00763 
00767 QSize QwtSlider::sizeHint() const
00768 {
00769     return minimumSizeHint();
00770 }
00771 
00777 QSize QwtSlider::minimumSizeHint() const
00778 {
00779     if (!d_data->sizeHintCache.isEmpty()) 
00780         return d_data->sizeHintCache;
00781 
00782     int sliderWidth = d_data->thumbWidth;
00783     if (d_data->bgStyle & BgTrough)
00784         sliderWidth += 2 * d_data->borderWidth;
00785 
00786     int w = 0, h = 0;
00787     if (d_data->scalePos != NoScale)
00788     {
00789         int d1, d2;
00790         scaleDraw()->getBorderDistHint(font(), d1, d2);
00791         int msMbd = qwtMax(d1, d2);
00792 
00793         int mbd = d_data->thumbLength / 2;
00794         if (d_data->bgStyle & BgTrough)
00795             mbd += d_data->borderWidth;
00796 
00797         if ( mbd < msMbd )
00798             mbd = msMbd;
00799 
00800         const int sdExtent = scaleDraw()->extent( QPen(), font() );
00801         const int sdLength = scaleDraw()->minLength( QPen(), font() );
00802 
00803         h = sliderWidth + sdExtent + d_data->scaleDist;
00804         w = sdLength - 2 * msMbd + 2 * mbd;
00805     }
00806     else  // no scale
00807     {
00808         w = 200;
00809         h = sliderWidth;
00810     }
00811 
00812     if ( orientation() == Qt::Vertical )
00813         qSwap(w, h);
00814 
00815     w += 2 * d_data->xMargin;
00816     h += 2 * d_data->yMargin;
00817 
00818     d_data->sizeHintCache = QSize(w, h);
00819     return d_data->sizeHintCache;
00820 }

Generated on Mon Feb 26 21:22:38 2007 for Qwt User's Guide by  doxygen 1.4.6