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

qwt_dial.cpp

Go to the documentation of this file.
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 #include <iostream>
00011 #include <math.h>
00012 #include <qpainter.h>
00013 #include <qpixmap.h>
00014 #include "qwt_math.h"
00015 #include "qwt_paint_buffer.h"
00016 #include "qwt_painter.h"
00017 #include "qwt_dial_needle.h"
00018 #include "qwt_dial.h"
00019 
00020 QwtDialScaleDraw::QwtDialScaleDraw(QwtDial *parent):
00021   d_parent(parent)
00022 {
00023 }
00024 
00025 QString QwtDialScaleDraw::label(double value) const
00026 {
00027   if ( d_parent == NULL )
00028     return QwtScaleDraw::label(value);
00029 
00030   return d_parent->scaleLabel(value);
00031 }
00032 
00044 QwtDial::QwtDial(QWidget* parent, const char* name):
00045       QwtSliderBase(Qt::Horizontal, parent, name, 
00046       WRepaintNoErase|WResizeNoErase),
00047   d_visibleBackground(FALSE),
00048   d_frameShadow(Sunken),
00049   d_lineWidth(0),
00050     d_mode(RotateNeedle),
00051     d_wrapping(FALSE),
00052   d_origin(90.0),
00053   d_minScaleArc(0.0),
00054   d_maxScaleArc(0.0),
00055   d_scaleDraw(0),
00056     d_maxMajIntv(36),
00057     d_maxMinIntv(10),
00058     d_scaleStep(0.0),
00059   d_needle(0)
00060 {
00061   setFocusPolicy(QWidget::TabFocus);
00062 
00063     QPalette p = palette();
00064     for ( int i = 0; i < QPalette::NColorGroups; i++ )
00065     {
00066     const QPalette::ColorGroup cg = (QPalette::ColorGroup)i;
00067 
00068     // Base: background color of the circle inside the frame.
00069     // Foreground: background color of the circle inside the scale
00070 
00071         p.setColor(cg, QColorGroup::Foreground, 
00072       p.color(cg, QColorGroup::Base));
00073     }
00074     setPalette(p);
00075 
00076   d_scaleDraw = new QwtDialScaleDraw(this);
00077     d_scaleDraw->setGeometry(0, 0, 0, QwtScaleDraw::Round);
00078 
00079   setScaleArc(0.0, 360.0); // scale as a full circle
00080   setRange(0.0, 360.0, 1.0); // degrees as deafult
00081 }
00082 
00084 QwtDial::~QwtDial() 
00085 {
00086   delete d_scaleDraw;
00087   delete d_needle;
00088 }
00089 
00099 void QwtDial::showBackground(bool show)
00100 {
00101   if ( d_visibleBackground != show )
00102   {
00103     d_visibleBackground = show;
00104 
00105     if ( d_visibleBackground )
00106       clearMask();
00107     else
00108     {
00109           const QRect r = boundingRect();
00110 
00111           QRegion region(QRect(r.x() - 1, r.y() - 1,
00112               r.width() + 2, r.height() + 2), QRegion::Ellipse);
00113 
00114           setMask(region);
00115     }
00116     update();
00117   }
00118 }
00119 
00126 bool QwtDial::hasVisibleBackground() const 
00127 { 
00128   return d_visibleBackground; 
00129 }
00130 
00137 void QwtDial::setFrameShadow(Shadow shadow)
00138 {
00139   if ( shadow != d_frameShadow )
00140   {
00141     d_frameShadow = shadow;
00142     if ( lineWidth() > 0 )
00143       update();
00144   }
00145 }
00146 
00153 QwtDial::Shadow QwtDial::frameShadow() const 
00154 { 
00155   return d_frameShadow; 
00156 }
00157 
00164 void QwtDial::setLineWidth(int lineWidth)
00165 {
00166   if ( lineWidth < 0 )
00167     lineWidth = 0;
00168 
00169   if ( d_lineWidth != lineWidth )
00170   {
00171     d_lineWidth = lineWidth;
00172     update();
00173   }
00174 }
00175 
00181 int QwtDial::lineWidth() const 
00182 { 
00183   return d_lineWidth; 
00184 }
00185 
00191 QRect QwtDial::contentsRect() const
00192 {
00193   const int lw = lineWidth();
00194 
00195   QRect r = boundingRect();
00196   if ( lw > 0 )
00197   {
00198     r.setRect(r.x() + lw, r.y() + lw, 
00199       r.width() - 2 * lw, r.height() - 2 * lw);
00200   }
00201   return r;
00202 }
00203 
00209 QRect QwtDial::boundingRect() const
00210 {
00211   const int radius = QMIN(width(), height()) / 2;
00212   const QPoint center = rect().center();
00213 
00214   int x = center.x() + width() % 2 - radius;
00215   if ( width() % 2 == 0 )
00216     x++;
00217 
00218   int y = center.y() - radius;
00219   if ( height() % 2 == 0 )
00220     y++;
00221 
00222   return QRect(x, y, 2 * radius, 2 * radius);
00223 }
00224 
00230 QRect QwtDial::scaleContentsRect() const
00231 {
00232     const QPen scalePen(colorGroup().text(), 0, NoPen);
00233 
00234   int scaleDist = 0;
00235   if ( d_scaleDraw )
00236   {
00237     scaleDist = QMAX(
00238       d_scaleDraw->maxWidth(scalePen, fontMetrics()),
00239           d_scaleDraw->maxHeight(scalePen, fontMetrics()));
00240   }
00241 
00242   const QRect rect = contentsRect();
00243 
00244   return QRect(rect.x() + scaleDist, rect.y() + scaleDist,
00245     rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist);
00246 }
00247 
00262 void QwtDial::setMode(Mode mode)
00263 {   
00264     if ( mode != d_mode )
00265     {
00266         d_mode = mode;
00267         update(); 
00268     }
00269 }       
00270 
00284 QwtDial::Mode QwtDial::mode() const
00285 {
00286     return d_mode;
00287 }
00288 
00289 void QwtDial::setWrapping(bool wrapping)
00290 {
00291   d_wrapping = wrapping;
00292 } 
00293 
00294 bool QwtDial::wrapping() const
00295 {
00296   return d_wrapping;
00297 }
00298 
00300 void QwtDial::resizeEvent(QResizeEvent *e)
00301 {
00302   QWidget::resizeEvent(e);
00303 
00304   if ( !hasVisibleBackground() )
00305   {
00306     const QRect r = boundingRect();
00307   
00308     QRegion region(QRect(r.x() - 1, r.y() - 1, 
00309       r.width() + 2, r.height() + 2), QRegion::Ellipse);
00310 
00311     setMask(region);
00312   }
00313 }
00314 
00316 void QwtDial::paintEvent(QPaintEvent *e)
00317 {
00318     const QRect &ur = e->rect();
00319     if ( ur.isValid() )
00320     {
00321         QwtPaintBuffer paintBuffer(this, ur);
00322 
00323     QPainter *painter = paintBuffer.painter();
00324 
00325     drawFrame(painter);
00326     drawContents(painter);
00327 
00328 #if 0
00329       if ( hasFocus() )
00330     {
00331       QRect focusRect = contentsRect();
00332 
00333       const int margin = 2;
00334       focusRect.setRect(focusRect.x() + margin, focusRect.y() + margin,
00335         focusRect.width() - 2 * margin, focusRect.height() - margin);
00336 
00337       painter->setBrush(Qt::NoBrush);
00338       painter->setPen(QPen(colorGroup().mid(), 0, Qt::DotLine));
00339       painter->drawEllipse(focusRect);
00340     }
00341 #endif
00342     }
00343 }
00344 
00351 void QwtDial::drawFrame(QPainter *painter)
00352 {
00353   const int lw = lineWidth();
00354 
00355   QRect r = boundingRect();
00356   r.setRect(r.x() + lw / 2, r.y() + lw / 2,
00357     r.width() - lw, r.height() - lw);
00358 
00359   if ( lw > 0 )
00360   {
00361     switch(d_frameShadow)
00362     {
00363       case QFrame::Raised:
00364         QwtPainter::drawRoundFrame(painter, r, lw, FALSE);
00365         break;
00366       case QFrame::Sunken:
00367         QwtPainter::drawRoundFrame(painter, r, lw, TRUE);
00368         break;
00369       default: // Plain
00370       {
00371         painter->setPen(QPen(Qt::black, lw));
00372         painter->drawEllipse(r);
00373       }
00374     }
00375   }
00376 }
00377 
00390 void QwtDial::drawContents(QPainter *painter) const
00391 {
00392   if ( colorGroup().base() != colorGroup().background() )
00393   {
00394     painter->setPen(NoPen);
00395     painter->setBrush(colorGroup().base());
00396     painter->drawEllipse(contentsRect());
00397   }
00398 
00399     QPalette::ColorGroup cg;
00400     if ( isEnabled() )
00401         cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
00402     else
00403         cg = QPalette::Disabled;
00404 
00405   const QRect insideScaleRect = scaleContentsRect();
00406   if ( colorGroup().base() != colorGroup().background() )
00407   {
00408     painter->setPen(NoPen);
00409     painter->setBrush(colorGroup().base());
00410     painter->drawEllipse(insideScaleRect);
00411   }
00412 
00413   const QPoint center = insideScaleRect.center();
00414   const int radius = insideScaleRect.width() / 2;
00415 
00416 #if 0
00417   const int margin = 4;
00418 #endif
00419   
00420     if ( colorGroup().foreground() != colorGroup().base() )
00421     {
00422         painter->setPen(NoPen);
00423         painter->setBrush(colorGroup().foreground());
00424         painter->drawEllipse(insideScaleRect);
00425     }
00426 
00427   painter->save();
00428   drawScaleContents(painter, center, radius);
00429   painter->restore();
00430 
00431   double direction = d_origin;
00432 
00433   if (isValid())
00434   {
00435     direction = d_origin + d_minScaleArc;
00436     if ( maxValue() > minValue() && d_maxScaleArc > d_minScaleArc )
00437     {
00438       const double ratio = 
00439         (value() - minValue()) / (maxValue() - minValue());
00440       direction += ratio * (d_maxScaleArc - d_minScaleArc);
00441     }
00442 
00443     if ( direction >= 360.0 )
00444       direction -= 360.0;
00445   }
00446 
00447   double origin = d_origin;
00448   if ( mode() == RotateScale )
00449   {
00450     origin -= direction - d_origin;
00451     direction = d_origin;
00452   }
00453 
00454   painter->save();
00455   drawScale(painter, center, radius, origin, d_minScaleArc, d_maxScaleArc);
00456   painter->restore();
00457 
00458   if ( isValid() )
00459   {
00460     painter->save();
00461     drawNeedle(painter, center, radius, direction, cg);
00462     painter->restore();
00463   }
00464 }
00465 
00475 void QwtDial::drawNeedle(QPainter *painter, const QPoint &center, 
00476   int radius, double direction, QPalette::ColorGroup cg) const
00477 {
00478   if ( d_needle )
00479   {
00480     direction = 360.0 - direction; // counter clockwise
00481     d_needle->draw(painter, center, radius, direction, cg);
00482   }
00483 }
00484 
00485 void QwtDial::drawScale(QPainter *painter, const QPoint &center,
00486   int radius, double origin, double minArc, double maxArc) const
00487 {
00488   if ( d_scaleDraw == NULL )
00489     return;
00490 
00491   origin -= 270.0; // hardcoded origin of QwtScaleDraw
00492 
00493   double angle = maxArc - minArc;
00494     if ( angle > 360.0 )
00495         angle = fmod(angle, 360.0);
00496 
00497   minArc += origin;
00498   if ( minArc < -360.0 )
00499     minArc = fmod(minArc, 360.0);
00500   
00501   maxArc = minArc + angle;
00502   if ( maxArc > 360.0 )
00503   {
00504     // QwtScaleDraw::setAngleRange accepts only values
00505     // in the range [-360.0..360.0]
00506     minArc -= 360.0;
00507     maxArc -= 360.0;
00508   }
00509   
00510   d_scaleDraw->setAngleRange(minArc, maxArc);
00511     d_scaleDraw->setGeometry(center.x() - radius, center.y() - radius,
00512         2 * radius, QwtScaleDraw::Round);
00513 
00514   painter->setFont(font());
00515   painter->setPen(colorGroup().text());
00516     d_scaleDraw->draw(painter);
00517 }
00518 
00527 void QwtDial::drawScaleContents(QPainter *, 
00528   const QPoint &, int) const
00529 {
00530   // empty default implementation
00531 }
00532 
00540 void QwtDial::setNeedle(QwtDialNeedle *needle)
00541 {
00542   if ( needle != d_needle )
00543   {
00544     if ( d_needle )
00545       delete d_needle;
00546 
00547     d_needle = needle;
00548     update();
00549   }
00550 }
00551 
00557 const QwtDialNeedle *QwtDial::needle() const 
00558 { 
00559   return d_needle; 
00560 }
00561 
00567 QwtDialNeedle *QwtDial::needle() 
00568 { 
00569   return d_needle; 
00570 }
00571 
00572 void QwtDial::rangeChange()
00573 {
00574   updateScale();
00575 }
00576 
00577 void QwtDial::updateScale()
00578 {
00579   if ( d_scaleDraw )
00580   {
00581     d_scaleDraw->setScale(minValue(), maxValue(),
00582       d_maxMajIntv, d_maxMinIntv, d_scaleStep);
00583   }
00584 }
00585 
00586 void QwtDial::setScaleDraw(QwtDialScaleDraw *scaleDraw)
00587 {
00588     if ( scaleDraw != d_scaleDraw )
00589     {
00590         if ( d_scaleDraw )
00591             delete d_scaleDraw;
00592     
00593         d_scaleDraw = scaleDraw;
00594     updateScale();
00595         update();
00596     }
00597 }
00598 
00599 void QwtDial::setScale(int maxMajIntv, int maxMinIntv, double step)
00600 {
00601   d_maxMajIntv = maxMajIntv;
00602   d_maxMinIntv = maxMinIntv;
00603   d_scaleStep = step;
00604 
00605   updateScale();
00606 }
00607 
00608 QString QwtDial::scaleLabel(double value) const
00609 {
00610 #if 1
00611     if ( value == -0 )
00612         value = 0;
00613 #endif
00614 
00615     QString text;
00616     text.sprintf("%g", value);
00617 
00618     return text;
00619 }
00620 
00621 void QwtDial::setOrigin(double origin)
00622 {
00623   d_origin = origin;
00624   update();
00625 }
00626 
00627 double QwtDial::origin() const
00628 {
00629   return d_origin;
00630 }
00631 
00632 void QwtDial::setScaleArc(double minArc, double maxArc)
00633 {
00634   // ueberdenken
00635 
00636   if ( minArc != 360.0 && minArc != -360.0 )
00637     minArc = fmod(minArc, 360.0);
00638   if ( maxArc != 360.0 && maxArc != -360.0 )
00639     maxArc = fmod(maxArc, 360.0);
00640 
00641   d_minScaleArc = QMIN(minArc, maxArc);
00642   d_maxScaleArc = QMAX(minArc, maxArc);
00643   if ( d_maxScaleArc - d_minScaleArc > 360.0 )
00644     d_maxScaleArc = d_minScaleArc + 360.0;
00645   
00646   update();
00647 }
00648 
00649 void QwtDial::valueChange()
00650 {
00651   update();
00652   QwtSliderBase::valueChange();
00653 }
00654 
00658 QSize QwtDial::sizeHint() const
00659 {
00660   int sh = 0;
00661   if ( d_scaleDraw )
00662       sh = d_scaleDraw->minHeight( QPen(), fontMetrics() );
00663 
00664     const int d = 6 * sh + 2 * lineWidth();
00665     
00666     return QSize( d, d );
00667 }
00668 
00674 QSize QwtDial::minimumSizeHint() const
00675 {   
00676   int sh = 0;
00677   if ( d_scaleDraw )
00678       sh = d_scaleDraw->minHeight( QPen(), fontMetrics() );
00679 
00680     const int d = 3 * sh + 2 * lineWidth();
00681     
00682     return QSize( d, d );
00683 }
00684 
00685 static double line2Radians(const QPoint &p1, const QPoint &p2)
00686 {
00687     const QPoint p = p2 - p1;
00688 
00689     double angle;
00690     if ( p.x() == 0 )
00691         angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
00692     else
00693     {
00694         angle = atan(double(-p.y()) / double(p.x()));
00695         if ( p.x() < 0 )
00696             angle += M_PI;
00697         if ( angle < 0.0 )
00698             angle += 2 * M_PI;
00699     }
00700     return 360.0 - angle * 180.0 / M_PI;
00701 }
00702 
00703 double QwtDial::getValue(const QPoint &p)
00704 {
00705   if ( d_maxScaleArc == d_minScaleArc || maxValue() == minValue() )
00706     return minValue();
00707 
00708   double dir = line2Radians(rect().center(), p) - d_origin;
00709   if ( dir < 0.0 )
00710     dir += 360.0;
00711 
00712   double value;
00713 
00714     if ( mode() == RotateScale )
00715   {
00716     value = 360.0 - dir;
00717   }
00718   else
00719   {
00720     const double ratio = 
00721       (dir - d_minScaleArc) / (d_maxScaleArc - d_minScaleArc);
00722     value = minValue() + ratio * (maxValue() - minValue());
00723   }
00724 
00725   if ( d_scrollMode == ScrMouse )
00726   {
00727     if ( value - d_mouseOffset < 0.0 )
00728       value += 360.0;
00729     if ( value - d_mouseOffset >= 360.0 )
00730       value -= 360.0;
00731   }
00732 
00733   return value;
00734 }
00735 
00736 void QwtDial::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00737 {
00738   direction = 0;
00739 
00740     const QRegion region(contentsRect(), QRegion::Ellipse);
00741     if ( !region.contains(p) || p == rect().center() )
00742     scrollMode = ScrNone;
00743   else
00744     scrollMode = ScrMouse;
00745 }
00746 

Generated on Fri Nov 7 14:11:45 2003 for Qwt Developer's Guide by doxygen 1.3.2