Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

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 
00066 QwtSlider::QwtSlider(QWidget *parent,
00067         Qt::Orientation orientation, ScalePos scalePos, BGSTYLE bgStyle): 
00068     QwtAbstractSlider(orientation, parent)
00069 {
00070     if (orientation == Qt::Vertical) 
00071         setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
00072     else
00073         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00074 
00075 #if QT_VERSION >= 0x040000
00076     setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00077 #else
00078     clearWState( WState_OwnSizePolicy );
00079 #endif
00080 
00081 
00082 #if QT_VERSION < 0x040000
00083     setWFlags(Qt::WNoAutoErase);
00084 #endif
00085 
00086     d_data = new QwtSlider::PrivateData;
00087 
00088     d_data->borderWidth = 2;
00089     d_data->scaleDist = 4;
00090     d_data->scalePos = scalePos;
00091     d_data->xMargin = 0;
00092     d_data->yMargin = 0;
00093     d_data->bgStyle = bgStyle;
00094 
00095     if (bgStyle == BgSlot)
00096     {
00097         d_data->thumbLength = 16;
00098         d_data->thumbWidth = 30;
00099     }
00100     else
00101     {
00102         d_data->thumbLength = 31;
00103         d_data->thumbWidth = 16;
00104     }
00105 
00106     d_data->sliderRect.setRect(0,0,8,8);
00107 
00108     QwtScaleDraw::Orientation so;
00109     if ( orientation == Qt::Vertical )
00110     {
00111         // enforce a valid combination of scale position and orientation
00112         if ((d_data->scalePos == Bottom) || (d_data->scalePos == Top))
00113             d_data->scalePos = None;
00114         // adopt the policy of layoutSlider (None lays out like Left)
00115         if (d_data->scalePos == Right)
00116            so = QwtScaleDraw::Right;
00117         else
00118            so = QwtScaleDraw::Left;
00119     }
00120     else
00121     {
00122         // enforce a valid combination of scale position and orientation
00123         if ((d_data->scalePos == Left) || (d_data->scalePos == Right))
00124             d_data->scalePos = None;
00125         // adopt the policy of layoutSlider (None lays out like Bottom)
00126         if (d_data->scalePos == Top)
00127            so = QwtScaleDraw::Top;
00128         else
00129            so = QwtScaleDraw::Bottom;
00130     }
00131 
00132     scaleDraw()->setGeometry(0,0,100,so);
00133 
00134     setRange(0.0, 100.0, 1.0);
00135     setValue(0.0);
00136 }
00137 
00138 QwtSlider::~QwtSlider()
00139 {
00140     delete d_data;
00141 }
00142 
00151 void QwtSlider::setOrientation(Qt::Orientation o) 
00152 {
00153     if ( o == orientation() )
00154         return;
00155 
00156     if (o == Qt::Horizontal)
00157     {
00158         if ((d_data->scalePos == Left) || (d_data->scalePos == Right))
00159             d_data->scalePos = None;
00160     }
00161     else // if (o == Qt::Vertical)
00162     {
00163         if ((d_data->scalePos == Bottom) || (d_data->scalePos == Top))
00164             d_data->scalePos = None;
00165     }
00166 
00167 #if QT_VERSION >= 0x040000
00168     if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
00169 #else
00170     if ( !testWState( WState_OwnSizePolicy ) ) 
00171 #endif
00172     {
00173         QSizePolicy sp = sizePolicy();
00174         sp.transpose();
00175         setSizePolicy(sp);
00176 
00177 #if QT_VERSION >= 0x040000
00178         setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00179 #else
00180         clearWState( WState_OwnSizePolicy );
00181 #endif
00182     }
00183 
00184     QwtAbstractSlider::setOrientation(o);
00185     layoutSlider();
00186 }
00187 
00200 void QwtSlider::setScalePosition(ScalePos s)
00201 {
00202     d_data->scalePos = s;
00203     if ((s == Bottom) || (s == Top))
00204         setOrientation(Qt::Horizontal);
00205     else if ((s == Left) || (s == Right))
00206         setOrientation(Qt::Vertical);
00207     else
00208         layoutSlider();
00209 }
00210 
00212 QwtSlider::ScalePos QwtSlider::scalePosition() const
00213 {
00214     return d_data->scalePos;
00215 }
00216 
00221 void QwtSlider::setBorderWidth(int bd)
00222 {
00223     if ( bd < 0 )
00224         bd = 0;
00225 
00226     if ( bd != d_data->borderWidth )
00227     {
00228         d_data->borderWidth = bd;
00229         layoutSlider();
00230     }
00231 }
00232 
00237 void QwtSlider::setThumbLength(int thumbLength)
00238 {
00239     if ( thumbLength < 8 )
00240         thumbLength = 8;
00241 
00242     if ( thumbLength != d_data->thumbLength )
00243     {
00244         d_data->thumbLength = thumbLength;
00245         layoutSlider();
00246     }
00247 }
00248 
00253 void QwtSlider::setThumbWidth(int w)
00254 {
00255     if ( w < 4 )
00256         w = 4;
00257 
00258     if ( d_data->thumbWidth != w )
00259     {
00260         d_data->thumbWidth = w;
00261         layoutSlider();
00262     }
00263 }
00264 
00265 
00267 void QwtSlider::scaleChange()
00268 {
00269     layoutSlider();
00270 }
00271 
00272 
00274 void QwtSlider::fontChange(const QFont &f)
00275 {
00276     QwtAbstractSlider::fontChange( f );
00277     layoutSlider();
00278 }
00279 
00281 void QwtSlider::drawSlider(QPainter *p, const QRect &r)
00282 {
00283     QRect cr(r);
00284 
00285     if (d_data->bgStyle & BgTrough)
00286     {
00287         qDrawShadePanel(p, r.x(), r.y(),
00288             r.width(), r.height(),
00289 #if QT_VERSION < 0x040000
00290             colorGroup(), 
00291 #else
00292             palette(), 
00293 #endif
00294             true, d_data->borderWidth,0);
00295 
00296         cr.setRect(r.x() + d_data->borderWidth,
00297             r.y() + d_data->borderWidth,
00298             r.width() - 2 * d_data->borderWidth,
00299             r.height() - 2 * d_data->borderWidth);
00300 
00301         p->fillRect(cr.x(), cr.y(), cr.width(), cr.height(), 
00302 #if QT_VERSION < 0x040000
00303             colorGroup().brush(QColorGroup::Mid)
00304 #else
00305             palette().brush(QPalette::Mid)
00306 #endif
00307         );
00308     }
00309 
00310     if ( d_data->bgStyle & BgSlot)
00311     {
00312         int ws = 4;
00313         int ds = d_data->thumbLength / 2 - 4;
00314         if ( ds < 1 )
00315             ds = 1;
00316 
00317         QRect rSlot;
00318         if (orientation() == Qt::Horizontal)
00319         {
00320             if ( cr.height() & 1 )
00321                 ws++;
00322             rSlot = QRect(cr.x() + ds, 
00323                     cr.y() + (cr.height() - ws) / 2,
00324                     cr.width() - 2 * ds, ws);
00325         }
00326         else
00327         {
00328             if ( cr.width() & 1 )
00329                 ws++;
00330             rSlot = QRect(cr.x() + (cr.width() - ws) / 2, 
00331                     cr.y() + ds,
00332                     ws, cr.height() - 2 * ds);
00333         }
00334         p->fillRect(rSlot.x(), rSlot.y(), rSlot.width(), rSlot.height(),
00335 #if QT_VERSION < 0x040000
00336             colorGroup().brush(QColorGroup::Dark)
00337 #else
00338             palette().brush(QPalette::Dark)
00339 #endif
00340         );
00341         qDrawShadePanel(p, rSlot.x(), rSlot.y(),
00342             rSlot.width(), rSlot.height(), 
00343 #if QT_VERSION < 0x040000
00344             colorGroup(), 
00345 #else
00346             palette(), 
00347 #endif
00348             true, 1 ,0);
00349 
00350     }
00351 
00352     if ( isValid() )
00353         drawThumb(p, cr, xyPosition(value()));
00354 }
00355 
00357 void QwtSlider::drawThumb(QPainter *p, const QRect &sliderRect, int pos)
00358 {
00359     pos++; // shade line points one pixel below
00360     if (orientation() == Qt::Horizontal)
00361     {
00362         qDrawShadePanel(p, pos - d_data->thumbLength / 2, 
00363             sliderRect.y(), d_data->thumbLength, sliderRect.height(),
00364 #if QT_VERSION < 0x040000
00365             colorGroup(), 
00366 #else
00367             palette(), 
00368 #endif
00369             false, d_data->borderWidth, 
00370 #if QT_VERSION < 0x040000
00371             &colorGroup().brush(QColorGroup::Button)
00372 #else
00373             &palette().brush(QPalette::Button)
00374 #endif
00375         );
00376 
00377         qDrawShadeLine(p, pos, sliderRect.y(), 
00378             pos, sliderRect.y() + sliderRect.height() - 2, 
00379 #if QT_VERSION < 0x040000
00380             colorGroup(), 
00381 #else
00382             palette(), 
00383 #endif
00384             true, 1);
00385     }
00386     else // Vertical
00387     {
00388         qDrawShadePanel(p,sliderRect.x(), pos - d_data->thumbLength / 2, 
00389             sliderRect.width(), d_data->thumbLength,
00390 #if QT_VERSION < 0x040000
00391             colorGroup(),
00392 #else
00393             palette(), 
00394 #endif
00395             false, d_data->borderWidth, 
00396 #if QT_VERSION < 0x040000
00397             &colorGroup().brush(QColorGroup::Button)
00398 #else
00399             &palette().brush(QPalette::Button)
00400 #endif
00401         );
00402 
00403         qDrawShadeLine(p, sliderRect.x(), pos,
00404             sliderRect.x() + sliderRect.width() - 2, pos, 
00405 #if QT_VERSION < 0x040000
00406             colorGroup(), 
00407 #else
00408             palette(), 
00409 #endif
00410             true, 1);
00411     }
00412 }
00413 
00415 int QwtSlider::xyPosition(double v) const
00416 {
00417     return d_data->map.transform(v);
00418 }
00419 
00421 double QwtSlider::getValue(const QPoint &p)
00422 {
00423     return d_data->map.invTransform(
00424         orientation() == Qt::Horizontal ? p.x() : p.y());
00425 }
00426 
00427 
00434 void QwtSlider::getScrollMode(const QPoint &p, 
00435     int &scrollMode, int &direction )
00436 {
00437     if (!d_data->sliderRect.contains(p))
00438     {
00439         scrollMode = ScrNone;
00440         direction = 0;
00441         return;
00442     }
00443 
00444     const int pos = ( orientation() == Qt::Horizontal ) ? p.x() : p.y();
00445     const int markerPos = xyPosition(value());
00446 
00447     if ((pos > markerPos - d_data->thumbLength / 2)
00448         && (pos < markerPos + d_data->thumbLength / 2))
00449     {
00450         scrollMode = ScrMouse;
00451         direction = 0;
00452         return;
00453     }
00454 
00455     scrollMode = ScrPage;
00456     direction = (pos > markerPos) ? 1 : -1;
00457     if ( scaleDraw()->map().p1() > scaleDraw()->map().p2() )
00458         direction = -direction;
00459 }
00460 
00462 void QwtSlider::paintEvent(QPaintEvent *e)
00463 {
00464     const QRect &ur = e->rect();
00465     if ( ur.isValid() )
00466     {
00467 #if QT_VERSION < 0x040000
00468         QwtPaintBuffer paintBuffer(this, ur);
00469         draw(paintBuffer.painter(), ur);
00470 #else
00471         QPainter painter(this);
00472         draw(&painter, ur);
00473 #endif
00474     }
00475 }
00476 
00478 void QwtSlider::draw(QPainter *painter, const QRect&)
00479 {
00480     if (d_data->scalePos != None)
00481     {
00482 #if QT_VERSION < 0x040000
00483         scaleDraw()->draw(painter, colorGroup());
00484 #else
00485         scaleDraw()->draw(painter, palette());
00486 #endif
00487     }
00488 
00489     drawSlider(painter, d_data->sliderRect);
00490 
00491     if ( hasFocus() )
00492         QwtPainter::drawFocusRect(painter, this, d_data->sliderRect);
00493 }
00494 
00496 void QwtSlider::resizeEvent(QResizeEvent *)
00497 {
00498     layoutSlider( false );
00499 }
00500 
00507 void QwtSlider::layoutSlider( bool update_geometry )
00508 {
00509     int sliderWidth = d_data->thumbWidth;
00510     int sld1 = d_data->thumbLength / 2 - 1;
00511     int sld2 = d_data->thumbLength / 2 + d_data->thumbLength % 2;
00512     if ( d_data->bgStyle & BgTrough )
00513     {
00514         sliderWidth += 2 * d_data->borderWidth;
00515         sld1 += d_data->borderWidth;
00516         sld2 += d_data->borderWidth;
00517     }
00518 
00519     int scd = 0;
00520     if ( d_data->scalePos != None )
00521     {
00522         int d1, d2;
00523         scaleDraw()->minBorderDist(font(), d1, d2);
00524         scd = qwtMax(d1, d2);
00525     }
00526 
00527     int slo = scd - sld1;
00528     if ( slo < 0 )
00529         slo = 0;
00530 
00531     const QRect r = rect();
00532     if (orientation() == Qt::Horizontal)
00533     {
00534         switch (d_data->scalePos)
00535         {
00536             case Top:
00537                 d_data->sliderRect.setRect(
00538                     r.x() + d_data->xMargin + slo,
00539                     r.y() + r.height() -
00540                     d_data->yMargin - sliderWidth,
00541                     r.width() - 2 * d_data->xMargin - 2 * slo,
00542                     sliderWidth);
00543                 scaleDraw()->setGeometry(
00544                     d_data->sliderRect.x() + sld1,
00545                     d_data->sliderRect.y() - d_data->scaleDist,
00546                     d_data->sliderRect.width() - sld1 - sld2,
00547                     QwtScaleDraw::Top);
00548                 break;
00549 
00550             case Bottom:
00551                 d_data->sliderRect.setRect(
00552                     r.x() + d_data->xMargin + slo,
00553                     r.y() + d_data->yMargin,
00554                     r.width() - 2 * d_data->xMargin - 2 * slo,
00555                     sliderWidth);
00556                 scaleDraw()->setGeometry(
00557                     d_data->sliderRect.x() + sld1,
00558                     d_data->sliderRect.y() + d_data->sliderRect.height() + d_data->scaleDist,
00559                     d_data->sliderRect.width() - sld1 - sld2,
00560                     QwtScaleDraw::Bottom);
00561                 break;
00562 
00563             case None: // like Bottom, but no scale. See QwtSlider().
00564             default:   // inconsistent orientation and scale position
00565                 d_data->sliderRect.setRect(
00566                     r.x() + d_data->xMargin + slo,
00567                     r.y() + d_data->yMargin,
00568                     r.width() - 2 * d_data->xMargin - 2 * slo,
00569                     sliderWidth);
00570                 scaleDraw()->setGeometry(
00571                     d_data->sliderRect.x() + sld1,
00572                     0,
00573                     d_data->sliderRect.width() - sld1 - sld2,
00574                     QwtScaleDraw::Bottom);
00575                 break;
00576         }
00577     }
00578     else // if (orientation() == Qt::Vertical
00579     {
00580         switch (d_data->scalePos)
00581         {
00582             case Right:
00583                 d_data->sliderRect.setRect(
00584                     r.x() + d_data->xMargin,
00585                     r.y() + d_data->yMargin + slo,
00586                     sliderWidth,
00587                     r.height() - 2 * d_data->yMargin - 2 * slo);
00588                 scaleDraw()->setGeometry(
00589                     d_data->sliderRect.x() + d_data->sliderRect.width() + d_data->scaleDist,
00590                     d_data->sliderRect.y() + sld1,
00591                     d_data->sliderRect.height() - sld1 - sld2,
00592                     QwtScaleDraw::Right);
00593                 break;
00594 
00595             case Left:
00596                 d_data->sliderRect.setRect(
00597                     r.x() + r.width() - sliderWidth - d_data->xMargin,
00598                     r.y() + d_data->yMargin + slo,
00599                     sliderWidth,
00600                     r.height() - 2 * d_data->yMargin - 2 * slo);
00601                 scaleDraw()->setGeometry(
00602                     d_data->sliderRect.x() - d_data->scaleDist,
00603                     d_data->sliderRect.y() + sld1,
00604                     d_data->sliderRect.height() - sld1 - sld2,
00605                     QwtScaleDraw::Left);
00606                 break;
00607 
00608             case None: // like Left, but no scale. See QwtSlider().
00609             default:   // inconsistent orientation and scale position
00610                 d_data->sliderRect.setRect(
00611                     r.x() + r.width() - sliderWidth - d_data->xMargin,
00612                     r.y() + d_data->yMargin + slo,
00613                     sliderWidth,
00614                     r.height() - 2 * d_data->yMargin - 2 * slo);
00615                 scaleDraw()->setGeometry(
00616                     0, d_data->sliderRect.y() + sld1,
00617                     d_data->sliderRect.height() - sld1 - sld2,
00618                     QwtScaleDraw::Left);
00619                 break;
00620         }
00621     }
00622 
00623     d_data->map.setPaintXInterval(scaleDraw()->map().p1(),
00624         scaleDraw()->map().p2());
00625 
00626     if ( update_geometry )
00627     {
00628         d_data->sizeHintCache = QSize(); // invalidate
00629         updateGeometry();
00630         update();
00631     }
00632 }
00633 
00635 void QwtSlider::valueChange()
00636 {
00637     QwtAbstractSlider::valueChange();
00638     update();
00639 }
00640 
00641 
00643 void QwtSlider::rangeChange()
00644 {
00645     d_data->map.setScaleInterval(minValue(), maxValue());
00646 
00647     if (autoScale())
00648         rescale(minValue(), maxValue());
00649 
00650     QwtAbstractSlider::rangeChange();
00651     layoutSlider();
00652 }
00653 
00659 void QwtSlider::setMargins(int xMargin, int yMargin)
00660 {
00661     if ( xMargin < 0 )
00662         xMargin = 0;
00663     if ( yMargin < 0 )
00664         yMargin = 0;
00665 
00666     if ( xMargin != d_data->xMargin || yMargin != d_data->yMargin )
00667     {
00668         d_data->xMargin = xMargin;
00669         d_data->yMargin = yMargin;
00670         layoutSlider();
00671     }
00672 }
00673 
00677 void QwtSlider::setBgStyle(BGSTYLE st) 
00678 {
00679     d_data->bgStyle = st; 
00680     layoutSlider();
00681 }
00682 
00686 QwtSlider::BGSTYLE QwtSlider::bgStyle() const 
00687 { 
00688     return d_data->bgStyle; 
00689 }
00690 
00694 int QwtSlider::thumbLength() const 
00695 {
00696     return d_data->thumbLength;
00697 }
00698 
00702 int QwtSlider::thumbWidth() const 
00703 {
00704     return d_data->thumbWidth;
00705 }
00706 
00710 int QwtSlider::borderWidth() const 
00711 {
00712     return d_data->borderWidth;
00713 }
00714 
00718 QSize QwtSlider::sizeHint() const
00719 {
00720     return minimumSizeHint();
00721 }
00722 
00728 QSize QwtSlider::minimumSizeHint() const
00729 {
00730     if (!d_data->sizeHintCache.isEmpty()) 
00731         return d_data->sizeHintCache;
00732 
00733     int w = 0, h = 0;
00734 
00735     int sliderWidth = d_data->thumbWidth;
00736     if (d_data->bgStyle & BgTrough)
00737         sliderWidth += 2 * d_data->borderWidth;
00738 
00739     if (d_data->scalePos != None)
00740     {
00741         int msWidth = scaleDraw()->minWidth( QPen(), font() );
00742         int msHeight = scaleDraw()->minHeight( QPen(), font() );
00743         
00744         int d1, d2;
00745         scaleDraw()->minBorderDist(font(), d1, d2);
00746         int msMbd = qwtMax(d1, d2);
00747 
00748         int mbd = d_data->thumbLength / 2;
00749         if (d_data->bgStyle & BgTrough)
00750             mbd += d_data->borderWidth;
00751 
00752         if ( mbd < msMbd )
00753             mbd = msMbd;
00754 
00755         if (orientation() == Qt::Vertical)
00756         {
00757             w = 2 * d_data->xMargin + sliderWidth + msWidth + d_data->scaleDist;
00758             h = msHeight - 2 * msMbd + 2 * mbd + 2 * d_data->yMargin;
00759         }
00760         else
00761         {
00762             w = msWidth - 2 * msMbd + 2 * mbd + 2 * d_data->xMargin;
00763             h = 2 * d_data->yMargin + sliderWidth  + msHeight + d_data->scaleDist;
00764         }
00765     }
00766     else  // no scale
00767     {
00768         if (orientation() == Qt::Vertical)
00769         {
00770             w = 2 * d_data->xMargin + sliderWidth;
00771             h = 200 + 2 * d_data->yMargin;
00772         }
00773         else
00774         {
00775             w = 200 + 2 * d_data->xMargin;
00776             h = 2 * d_data->yMargin + sliderWidth;
00777         }
00778     }
00779     d_data->sizeHintCache = QSize(w, h);
00780     return d_data->sizeHintCache;
00781 }

Generated on Wed Aug 31 23:02:30 2005 for Qwt User's Guide by  doxygen 1.4.1