00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
#include <math.h>
00011
#include <qpainter.h>
00012
#include <qpixmap.h>
00013
#include <qevent.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
double QwtDial::d_previousDir = -1.0;
00021
00027 QwtDialScaleDraw::QwtDialScaleDraw(
QwtDial *parent):
00028 d_parent(parent),
00029 d_penWidth(1),
00030 d_visibleLabels(TRUE)
00031 {
00032 }
00033
00043 void QwtDialScaleDraw::showLabels(
bool enable)
00044 {
00045 d_visibleLabels = enable;
00046 }
00047
00052 bool QwtDialScaleDraw::visibleLabels()
const
00053
{
00054
return d_visibleLabels;
00055 }
00056
00064 void QwtDialScaleDraw::setPenWidth(uint penWidth)
00065 {
00066 d_penWidth = penWidth;
00067 }
00068
00073 uint
QwtDialScaleDraw::penWidth()
const
00074
{
00075
return d_penWidth;
00076 }
00077
00085 QString
QwtDialScaleDraw::label(
double value)
const
00086
{
00087
if ( !d_visibleLabels )
00088
return QString::null;
00089
00090
if ( d_parent == NULL )
00091
return QwtScaleDraw::label(value);
00092
00093
return d_parent->
scaleLabel(value);
00094 }
00095
00107 QwtDial::QwtDial(QWidget* parent,
const char* name):
00108
QwtSliderBase(Qt::Horizontal, parent, name,
00109 Qt::WRepaintNoErase|Qt::WResizeNoErase),
00110 d_visibleBackground(FALSE),
00111 d_frameShadow(Sunken),
00112 d_lineWidth(0),
00113 d_mode(RotateNeedle),
00114 d_origin(90.0),
00115 d_minScaleArc(0.0),
00116 d_maxScaleArc(0.0),
00117 d_scaleDraw(0),
00118 d_maxMajIntv(36),
00119 d_maxMinIntv(10),
00120 d_scaleStep(0.0),
00121 d_needle(0)
00122 {
00123 setBackgroundMode(NoBackground);
00124 setFocusPolicy(QWidget::TabFocus);
00125
00126 QPalette p = palette();
00127
for (
int i = 0; i < QPalette::NColorGroups; i++ )
00128 {
00129
const QPalette::ColorGroup cg = (QPalette::ColorGroup)i;
00130
00131
00132
00133
00134 p.setColor(cg, QColorGroup::Foreground,
00135 p.color(cg, QColorGroup::Base));
00136 }
00137 setPalette(p);
00138
00139 d_scaleDraw =
new QwtDialScaleDraw(
this);
00140 d_scaleDraw->
setGeometry(0, 0, 0, QwtScaleDraw::Round);
00141
00142
setScaleArc(0.0, 360.0);
00143
setRange(0.0, 360.0, 1.0, 10);
00144 }
00145
00147 QwtDial::~QwtDial()
00148 {
00149
delete d_scaleDraw;
00150
delete d_needle;
00151 }
00152
00161 void QwtDial::showBackground(
bool show)
00162 {
00163
if ( d_visibleBackground != show )
00164 {
00165 d_visibleBackground = show;
00166
00167
if ( d_visibleBackground )
00168 clearMask();
00169
else
00170 setMask(QRegion(
boundingRect(), QRegion::Ellipse));
00171
00172 update();
00173 }
00174 }
00175
00181 bool QwtDial::hasVisibleBackground()
const
00182
{
00183
return d_visibleBackground;
00184 }
00185
00191 void QwtDial::setFrameShadow(Shadow shadow)
00192 {
00193
if ( shadow != d_frameShadow )
00194 {
00195 d_frameShadow = shadow;
00196
if (
lineWidth() > 0 )
00197 update();
00198 }
00199 }
00200
00206 QwtDial::Shadow QwtDial::frameShadow()
const
00207
{
00208
return d_frameShadow;
00209 }
00210
00217 void QwtDial::setLineWidth(
int lineWidth)
00218 {
00219
if ( lineWidth < 0 )
00220 lineWidth = 0;
00221
00222
if ( d_lineWidth != lineWidth )
00223 {
00224 d_lineWidth = lineWidth;
00225 update();
00226 }
00227 }
00228
00234 int QwtDial::lineWidth()
const
00235
{
00236
return d_lineWidth;
00237 }
00238
00243 QRect
QwtDial::contentsRect()
const
00244
{
00245
const int lw =
lineWidth();
00246
00247 QRect r =
boundingRect();
00248
if ( lw > 0 )
00249 {
00250 r.setRect(r.x() + lw, r.y() + lw,
00251 r.width() - 2 * lw, r.height() - 2 * lw);
00252 }
00253
return r;
00254 }
00255
00260 QRect
QwtDial::boundingRect()
const
00261
{
00262
const int radius = QMIN(width(), height()) / 2;
00263
00264 QRect r(0, 0, 2 * radius, 2 * radius);
00265 r.moveCenter(rect().center());
00266
return r;
00267 }
00268
00273 QRect
QwtDial::scaleContentsRect()
const
00274
{
00275
const QPen scalePen(colorGroup().text(), 0, Qt::NoPen);
00276
00277
int scaleDist = 0;
00278
if ( d_scaleDraw )
00279 {
00280 scaleDist = QMAX(
00281 d_scaleDraw->
maxWidth(scalePen, fontMetrics()),
00282 d_scaleDraw->
maxHeight(scalePen, fontMetrics()));
00283 scaleDist++;
00284 }
00285
00286
const QRect rect =
contentsRect();
00287
return QRect(rect.x() + scaleDist, rect.y() + scaleDist,
00288 rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist);
00289 }
00290
00306 void QwtDial::setMode(Mode mode)
00307 {
00308
if ( mode != d_mode )
00309 {
00310 d_mode = mode;
00311 update();
00312 }
00313 }
00314
00329 QwtDial::Mode QwtDial::mode()
const
00330
{
00331
return d_mode;
00332 }
00333
00344 void QwtDial::setWrapping(
bool wrapping)
00345 {
00346
setPeriodic(wrapping);
00347 }
00348
00357 bool QwtDial::wrapping()
const
00358
{
00359
return periodic();
00360 }
00361
00363 void QwtDial::resizeEvent(QResizeEvent *e)
00364 {
00365 QWidget::resizeEvent(e);
00366
00367
if ( !
hasVisibleBackground() )
00368 setMask(QRegion(
boundingRect(), QRegion::Ellipse));
00369 }
00370
00372 void QwtDial::paintEvent(QPaintEvent *e)
00373 {
00374
const QRect &ur = e->rect();
00375
if ( ur.isValid() )
00376 {
00377
QwtPaintBuffer paintBuffer(
this, ur);
00378
00379 QPainter *painter = paintBuffer.
painter();
00380
00381
drawContents(painter);
00382
drawFrame(painter);
00383
00384
if ( hasFocus() )
00385
drawFocusIndicator(painter);
00386 }
00387 }
00388
00394 void QwtDial::drawFocusIndicator(QPainter *painter)
const
00395
{
00396
if ( !
isReadOnly() )
00397 {
00398 QRect focusRect =
contentsRect();
00399
00400
const int margin = 2;
00401 focusRect.setRect(
00402 focusRect.x() + margin,
00403 focusRect.y() + margin,
00404 focusRect.width() - 2 * margin,
00405 focusRect.height() - 2 * margin);
00406
00407 QColor color = colorGroup().color(QColorGroup::Base);
00408
if (color.isValid())
00409 {
00410
int h, s, v;
00411 color.hsv(&h, &s, &v);
00412 color = (v > 128) ? Qt::gray.dark(120) : Qt::gray.light(120);
00413 }
00414
else
00415 color = Qt::darkGray;
00416
00417 painter->save();
00418 painter->setBrush(Qt::NoBrush);
00419 painter->setPen(QPen(color, 0, Qt::DotLine));
00420 painter->drawEllipse(focusRect);
00421 painter->restore();
00422 }
00423 }
00424
00431 void QwtDial::drawFrame(QPainter *painter)
00432 {
00433
const int lw =
lineWidth();
00434
const int off = (lw + 1) % 2;
00435
00436 QRect r =
boundingRect();
00437 r.setRect(r.x() + lw / 2 - off, r.y() + lw / 2 - off,
00438 r.width() - lw + off + 1, r.height() - lw + off + 1);
00439
00440
if ( lw > 0 )
00441 {
00442
switch(d_frameShadow)
00443 {
00444
case QwtDial::Raised:
00445
QwtPainter::drawRoundFrame(painter, r,
00446 lw, colorGroup(), FALSE);
00447
break;
00448
case QwtDial::Sunken:
00449
QwtPainter::drawRoundFrame(painter, r,
00450 lw, colorGroup(), TRUE);
00451
break;
00452
default:
00453 {
00454 painter->save();
00455 painter->setPen(QPen(Qt::black, lw));
00456 painter->setBrush(Qt::NoBrush);
00457 painter->drawEllipse(r);
00458 painter->restore();
00459 }
00460 }
00461 }
00462 }
00463
00475 void QwtDial::drawContents(QPainter *painter)
const
00476
{
00477
if ( backgroundMode() == NoBackground ||
00478 colorGroup().brush(QColorGroup::Base) !=
00479 colorGroup().brush(QColorGroup::Background) )
00480 {
00481
00482
00483
00484
00485 painter->save();
00486 painter->setPen(Qt::NoPen);
00487 painter->setBrush(colorGroup().brush(QColorGroup::Base));
00488
00489
00490
00491
00492
00493
00494 QRect br =
boundingRect();
00495
#if QT_VERSION < 300
00496
#ifdef _WS_WIN32_
00497
00498 br.setTop(br.top()-1);
00499 br.setLeft(br.left()-1);
00500 br.setBottom(br.bottom()+1);
00501 br.setRight(br.right()+1);
00502
#endif
00503
#endif
00504
painter->setClipRegion(QRegion(painter->xForm(br), QRegion::Ellipse));
00505 painter->drawRect(br);
00506 painter->restore();
00507 }
00508
00509
00510
const QRect insideScaleRect =
scaleContentsRect();
00511
if ( colorGroup().brush(QColorGroup::Foreground) !=
00512 colorGroup().brush(QColorGroup::Base) )
00513 {
00514 painter->save();
00515 painter->setPen(Qt::NoPen);
00516 painter->setBrush(colorGroup().brush(QColorGroup::Foreground));
00517
00518 painter->setClipRegion(
00519 QRegion(painter->xForm(insideScaleRect), QRegion::Ellipse));
00520 painter->drawRect(insideScaleRect);
00521 painter->restore();
00522 }
00523
00524
const QPoint center = insideScaleRect.center();
00525
const int radius = insideScaleRect.width() / 2;
00526
00527 painter->save();
00528
drawScaleContents(painter, center, radius);
00529 painter->restore();
00530
00531
double direction = d_origin;
00532
00533
if (
isValid())
00534 {
00535 direction = d_origin + d_minScaleArc;
00536
if (
maxValue() >
minValue() && d_maxScaleArc > d_minScaleArc )
00537 {
00538
const double ratio =
00539 (
value() -
minValue()) / (
maxValue() -
minValue());
00540 direction += ratio * (d_maxScaleArc - d_minScaleArc);
00541 }
00542
00543
if ( direction >= 360.0 )
00544 direction -= 360.0;
00545 }
00546
00547
double origin = d_origin;
00548
if (
mode() == RotateScale )
00549 {
00550 origin -= direction - d_origin;
00551 direction = d_origin;
00552 }
00553
00554 painter->save();
00555
drawScale(painter, center, radius, origin, d_minScaleArc, d_maxScaleArc);
00556 painter->restore();
00557
00558
if (
isValid() )
00559 {
00560 QPalette::ColorGroup cg;
00561
if ( isEnabled() )
00562 cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
00563
else
00564 cg = QPalette::Disabled;
00565
00566 painter->save();
00567
drawNeedle(painter, center, radius, direction, cg);
00568 painter->restore();
00569 }
00570 }
00571
00584 void QwtDial::drawNeedle(QPainter *painter,
const QPoint ¢er,
00585
int radius,
double direction, QPalette::ColorGroup cg)
const
00586
{
00587
if ( d_needle )
00588 {
00589 direction = 360.0 - direction;
00590 d_needle->
draw(painter, center, radius, direction, cg);
00591 }
00592 }
00593
00606 void QwtDial::drawScale(QPainter *painter,
const QPoint ¢er,
00607
int radius,
double origin,
double minArc,
double maxArc)
const
00608
{
00609
if ( d_scaleDraw == NULL )
00610
return;
00611
00612 origin -= 270.0;
00613
00614
double angle = maxArc - minArc;
00615
if ( angle > 360.0 )
00616 angle = fmod(angle, 360.0);
00617
00618 minArc += origin;
00619
if ( minArc < -360.0 )
00620 minArc = fmod(minArc, 360.0);
00621
00622 maxArc = minArc + angle;
00623
if ( maxArc > 360.0 )
00624 {
00625
00626
00627 minArc -= 360.0;
00628 maxArc -= 360.0;
00629 }
00630
00631 painter->setFont(font());
00632 painter->setPen(QPen(colorGroup().text(), d_scaleDraw->
penWidth()));
00633
00634 d_scaleDraw->
setAngleRange(minArc, maxArc);
00635 d_scaleDraw->
setGeometry(
00636 center.x() - radius + 1,
00637 center.y() - radius + 1,
00638 2 * radius, QwtScaleDraw::Round);
00639
00640 d_scaleDraw->
draw(painter);
00641 }
00642
00643 void QwtDial::drawScaleContents(QPainter *,
00644
const QPoint &,
int)
const
00645
{
00646
00647 }
00648
00659 void QwtDial::setNeedle(
QwtDialNeedle *needle)
00660 {
00661
if ( needle != d_needle )
00662 {
00663
if ( d_needle )
00664
delete d_needle;
00665
00666 d_needle = needle;
00667 update();
00668 }
00669 }
00670
00675 const QwtDialNeedle *
QwtDial::needle()
const
00676
{
00677
return d_needle;
00678 }
00679
00684 QwtDialNeedle *
QwtDial::needle()
00685 {
00686
return d_needle;
00687 }
00688
00690 void QwtDial::rangeChange()
00691 {
00692
updateScale();
00693 }
00694
00699 void QwtDial::updateScale()
00700 {
00701
if ( d_scaleDraw )
00702 {
00703 d_scaleDraw->
setScale(
minValue(),
maxValue(),
00704 d_maxMajIntv, d_maxMinIntv, d_scaleStep);
00705 }
00706 }
00707
00713 void QwtDial::setScaleDraw(
QwtDialScaleDraw *scaleDraw)
00714 {
00715
if ( scaleDraw != d_scaleDraw )
00716 {
00717
if ( d_scaleDraw )
00718
delete d_scaleDraw;
00719
00720 d_scaleDraw = scaleDraw;
00721
updateScale();
00722 update();
00723 }
00724 }
00725
00730 void QwtDial::setScale(
int maxMajIntv,
int maxMinIntv,
double step)
00731 {
00732 d_maxMajIntv = maxMajIntv;
00733 d_maxMinIntv = maxMinIntv;
00734 d_scaleStep = step;
00735
00736
updateScale();
00737 }
00738
00754 void QwtDial::setScaleOptions(
int options)
00755 {
00756
if ( options == 0 )
00757
setScaleDraw(NULL);
00758
00759
if ( d_scaleDraw == NULL )
00760
return;
00761
00762
int flags = d_scaleDraw->
options();
00763
if ( options & ScaleBackbone )
00764 flags |= QwtScaleDraw::Backbone;
00765
else
00766 flags &= ~
QwtScaleDraw::Backbone;
00767 d_scaleDraw->
setOptions(flags);
00768
00769
if ( !(options & ScaleTicks) )
00770 d_scaleDraw->
setTickLength(0, 0, 0);
00771
00772 d_scaleDraw->
showLabels(options & ScaleLabel);
00773 }
00774
00776 void QwtDial::setScaleTicks(
int minLen,
int medLen,
00777
int majLen,
int penWidth)
00778 {
00779
if ( d_scaleDraw )
00780 {
00781 d_scaleDraw->
setTickLength(minLen, medLen, majLen);
00782 d_scaleDraw->
setPenWidth(penWidth);
00783 }
00784 }
00785
00789 QString
QwtDial::scaleLabel(
double value)
const
00790
{
00791
#if 1
00792
if ( value == -0 )
00793 value = 0;
00794
#endif
00795
00796 QString text;
00797 text.sprintf(
"%g", value);
00798
00799
return text;
00800 }
00801
00810 void QwtDial::setOrigin(
double origin)
00811 {
00812 d_origin = origin;
00813 update();
00814 }
00815
00822 double QwtDial::origin()
const
00823
{
00824
return d_origin;
00825 }
00826
00833 void QwtDial::setScaleArc(
double minArc,
double maxArc)
00834 {
00835
if ( minArc != 360.0 && minArc != -360.0 )
00836 minArc = fmod(minArc, 360.0);
00837
if ( maxArc != 360.0 && maxArc != -360.0 )
00838 maxArc = fmod(maxArc, 360.0);
00839
00840 d_minScaleArc = QMIN(minArc, maxArc);
00841 d_maxScaleArc = QMAX(minArc, maxArc);
00842
if ( d_maxScaleArc - d_minScaleArc > 360.0 )
00843 d_maxScaleArc = d_minScaleArc + 360.0;
00844
00845 update();
00846 }
00847
00849 void QwtDial::valueChange()
00850 {
00851 update();
00852
QwtSliderBase::valueChange();
00853 }
00854
00858 QSize
QwtDial::sizeHint()
const
00859
{
00860
int sh = 0;
00861
if ( d_scaleDraw )
00862 sh = d_scaleDraw->
minHeight( QPen(), fontMetrics() );
00863
00864
const int d = 6 * sh + 2 *
lineWidth();
00865
00866
return QSize( d, d );
00867 }
00868
00874 QSize
QwtDial::minimumSizeHint()
const
00875
{
00876
int sh = 0;
00877
if ( d_scaleDraw )
00878 sh = d_scaleDraw->
minHeight( QPen(), fontMetrics() );
00879
00880
const int d = 3 * sh + 2 *
lineWidth();
00881
00882
return QSize( d, d );
00883 }
00884
00885
static double line2Radians(
const QPoint &p1,
const QPoint &p2)
00886 {
00887
const QPoint p = p2 - p1;
00888
00889
double angle;
00890
if ( p.x() == 0 )
00891 angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
00892
else
00893 {
00894 angle = atan(
double(-p.y()) / double(p.x()));
00895
if ( p.x() < 0 )
00896 angle += M_PI;
00897
if ( angle < 0.0 )
00898 angle += 2 * M_PI;
00899 }
00900
return 360.0 - angle * 180.0 / M_PI;
00901 }
00902
00909 double QwtDial::getValue(
const QPoint &pos)
00910 {
00911
if ( d_maxScaleArc == d_minScaleArc ||
maxValue() ==
minValue() )
00912
return minValue();
00913
00914
double dir = line2Radians(rect().center(), pos) - d_origin;
00915
if ( dir < 0.0 )
00916 dir += 360.0;
00917
00918
if (
mode() == RotateScale )
00919 dir = 360.0 - dir;
00920
00921
00922
00923
00924
const double completeCircle = 360.0 / (d_maxScaleArc - d_minScaleArc)
00925 * (
maxValue() -
minValue());
00926
00927
double posValue =
minValue() + completeCircle * dir / 360.0;
00928
00929
if ( d_scrollMode == ScrMouse )
00930 {
00931
if ( d_previousDir >= 0.0 )
00932 {
00933
00934
00935
00936
bool clockWise = FALSE;
00937
00938
const double angle = dir - d_previousDir;
00939
if ( (angle >= 0.0 && angle <= 180.0) || angle < -180.0 )
00940 clockWise = TRUE;
00941
00942
if ( clockWise )
00943 {
00944
if ( dir < d_previousDir && d_mouseOffset > 0.0 )
00945 {
00946
00947 d_mouseOffset -= completeCircle;
00948 }
00949
00950
if (
wrapping() )
00951 {
00952
if ( posValue - d_mouseOffset >
maxValue() )
00953 {
00954
00955
00956
00957 d_mouseOffset = posValue -
minValue();
00958 }
00959 }
00960
else
00961 {
00962
if ( posValue - d_mouseOffset >
maxValue() ||
00963
value() ==
maxValue() )
00964 {
00965
00966
00967
00968 d_mouseOffset = posValue -
maxValue();
00969 }
00970 }
00971 }
00972
else
00973 {
00974
if ( dir > d_previousDir && d_mouseOffset < 0.0 )
00975 {
00976
00977 d_mouseOffset += completeCircle;
00978 }
00979
00980
if (
wrapping() )
00981 {
00982
if ( posValue - d_mouseOffset <
minValue() )
00983 {
00984
00985
00986
00987 d_mouseOffset = posValue -
maxValue();
00988 }
00989 }
00990
else
00991 {
00992
if ( posValue - d_mouseOffset <
minValue() ||
00993
value() ==
minValue() )
00994 {
00995
00996
00997
00998 d_mouseOffset = posValue -
minValue();
00999 }
01000 }
01001 }
01002 }
01003 d_previousDir = dir;
01004 }
01005
01006
return posValue;
01007 }
01008
01012 void QwtDial::getScrollMode(
const QPoint &p,
int &scrollMode,
int &direction)
01013 {
01014 direction = 0;
01015 scrollMode = ScrNone;
01016
01017
const QRegion region(
contentsRect(), QRegion::Ellipse);
01018
if ( region.contains(p) && p != rect().center() )
01019 {
01020 scrollMode = ScrMouse;
01021 d_previousDir = -1.0;
01022 }
01023 }
01024
01044 void QwtDial::keyPressEvent(QKeyEvent *e)
01045 {
01046
if (
isReadOnly() )
01047 {
01048
#if QT_VERSION >= 300
01049
e->ignore();
01050
#endif
01051
return;
01052 }
01053
01054
if ( !
isValid() )
01055
return;
01056
01057
double previous =
prevValue();
01058
switch ( e->key() )
01059 {
01060
case Qt::Key_Down:
01061
case Qt::Key_Left:
01062
QwtDblRange::incValue(-1);
01063
break;
01064
case Qt::Key_Prior:
01065
QwtDblRange::incValue(-
pageSize());
01066
break;
01067
case Qt::Key_Home:
01068
setValue(
minValue());
01069
break;
01070
01071
case Qt::Key_Up:
01072
case Qt::Key_Right:
01073
QwtDblRange::incValue(1);
01074
break;
01075
case Qt::Key_Next:
01076
QwtDblRange::incValue(
pageSize());
01077
break;
01078
case Qt::Key_End:
01079
setValue(
maxValue());
01080
break;
01081
default:;
01082
#if QT_VERSION >= 300
01083
e->ignore();
01084
#endif
01085
}
01086
01087
if (
value() != previous)
01088 emit
sliderMoved(
value());
01089 }
01090