qwt_dial.cpp 19 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

Bryant's avatar
Bryant committed
10 11
#include "qwt_dial.h"
#include "qwt_dial_needle.h"
pixhawk's avatar
pixhawk committed
12 13 14
#include "qwt_math.h"
#include "qwt_scale_engine.h"
#include "qwt_scale_map.h"
Bryant's avatar
Bryant committed
15
#include "qwt_round_scale_draw.h"
pixhawk's avatar
pixhawk committed
16
#include "qwt_painter.h"
Bryant's avatar
Bryant committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#include <qpainter.h>
#include <qpalette.h>
#include <qpixmap.h>
#include <qevent.h>
#include <qalgorithms.h>
#include <qmath.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qapplication.h>

static inline double qwtAngleDist( double a1, double a2 )
{
    double dist = qAbs( a2 - a1 );
    if ( dist > 360.0 )
        dist -= 360.0;

    return dist;
}

static inline bool qwtIsOnArc( double angle, double min, double max )
{
    if ( min < max )
    {
        return ( angle >= min ) && ( angle <= max );
    }
    else
    {
        return ( angle >= min ) || ( angle <= max );
    }
}

static inline double qwtBoundedAngle( double min, double angle, double max )
{
    double from = qwtNormalizeDegrees( min );
    double to = qwtNormalizeDegrees( max );

    double a;

    if ( qwtIsOnArc( angle, from, to ) )
    {
        a = angle;
        if ( a < min )
            a += 360.0;
    }
    else
    {
        if ( qwtAngleDist( angle, from ) <
            qwtAngleDist( angle, to ) )
        {
            a = min;
        }
        else
        {
            a = max;
        }
    }

    return a;
}
pixhawk's avatar
pixhawk committed
76 77 78 79 80

class QwtDial::PrivateData
{
public:
    PrivateData():
Bryant's avatar
Bryant committed
81 82 83 84 85 86 87 88 89 90
        frameShadow( Sunken ),
        lineWidth( 0 ),
        mode( RotateNeedle ),
        origin( 90.0 ),
        minScaleArc( 0.0 ),
        maxScaleArc( 0.0 ),
        needle( NULL ),
        arcOffset( 0.0 ),
        mouseOffset( 0.0 )
    {
pixhawk's avatar
pixhawk committed
91 92
    }

Bryant's avatar
Bryant committed
93 94
    ~PrivateData()
    {
pixhawk's avatar
pixhawk committed
95 96 97 98 99 100 101 102 103 104 105
        delete needle;
    }
    Shadow frameShadow;
    int lineWidth;

    QwtDial::Mode mode;

    double origin;
    double minScaleArc;
    double maxScaleArc;

Bryant's avatar
Bryant committed
106
    double scalePenWidth;
pixhawk's avatar
pixhawk committed
107 108
    QwtDialNeedle *needle;

Bryant's avatar
Bryant committed
109 110
    double arcOffset;
    double mouseOffset;
pixhawk's avatar
pixhawk committed
111

Bryant's avatar
Bryant committed
112 113
    QPixmap pixmapCache;
};
pixhawk's avatar
pixhawk committed
114 115 116 117 118

/*!
  \brief Constructor
  \param parent Parent widget

Bryant's avatar
Bryant committed
119 120 121
  Create a dial widget with no needle. The scale is initialized
  to [ 0.0, 360.0 ] and 360 steps ( QwtAbstractSlider::setTotalSteps() ).
  The origin of the scale is at 90°,
pixhawk's avatar
pixhawk committed
122

Bryant's avatar
Bryant committed
123
  The value is set to 0.0.
pixhawk's avatar
pixhawk committed
124

Bryant's avatar
Bryant committed
125
  The default mode is QwtDial::RotateNeedle.
126
*/
Bryant's avatar
Bryant committed
127 128
QwtDial::QwtDial( QWidget* parent ):
    QwtAbstractSlider( parent )
pixhawk's avatar
pixhawk committed
129 130 131
{
    d_data = new PrivateData;

Bryant's avatar
Bryant committed
132
    setFocusPolicy( Qt::TabFocus );
pixhawk's avatar
pixhawk committed
133 134

    QPalette p = palette();
Bryant's avatar
Bryant committed
135 136 137 138
    for ( int i = 0; i < QPalette::NColorGroups; i++ )
    {
        const QPalette::ColorGroup colorGroup =
            static_cast<QPalette::ColorGroup>( i );
pixhawk's avatar
pixhawk committed
139 140

        // Base: background color of the circle inside the frame.
Bryant's avatar
Bryant committed
141 142 143 144
        // WindowText: background color of the circle inside the scale

        p.setColor( colorGroup, QPalette::WindowText,
            p.color( colorGroup, QPalette::Base ) );
pixhawk's avatar
pixhawk committed
145
    }
Bryant's avatar
Bryant committed
146
    setPalette( p );
pixhawk's avatar
pixhawk committed
147

Bryant's avatar
Bryant committed
148 149
    QwtRoundScaleDraw* scaleDraw = new QwtRoundScaleDraw();
    scaleDraw->setRadius( 0 );
pixhawk's avatar
pixhawk committed
150

Bryant's avatar
Bryant committed
151
    setScaleDraw( scaleDraw );
pixhawk's avatar
pixhawk committed
152

Bryant's avatar
Bryant committed
153
    setScaleArc( 0.0, 360.0 ); // scale as a full circle
pixhawk's avatar
pixhawk committed
154

Bryant's avatar
Bryant committed
155 156
    setScaleMaxMajor( 10 );
    setScaleMaxMinor( 5 );
pixhawk's avatar
pixhawk committed
157

Bryant's avatar
Bryant committed
158
    setValue( 0.0 );
pixhawk's avatar
pixhawk committed
159 160
}

Bryant's avatar
Bryant committed
161 162
//!  Destructor
QwtDial::~QwtDial()
163
{
Bryant's avatar
Bryant committed
164
    delete d_data;
pixhawk's avatar
pixhawk committed
165 166 167 168
}

/*!
  Sets the frame shadow value from the frame style.
Bryant's avatar
Bryant committed
169

pixhawk's avatar
pixhawk committed
170 171 172
  \param shadow Frame shadow
  \sa setLineWidth(), QFrame::setFrameShadow()
*/
Bryant's avatar
Bryant committed
173
void QwtDial::setFrameShadow( Shadow shadow )
pixhawk's avatar
pixhawk committed
174
{
Bryant's avatar
Bryant committed
175 176 177 178
    if ( shadow != d_data->frameShadow )
    {
        invalidateCache();

pixhawk's avatar
pixhawk committed
179 180 181 182 183 184 185 186
        d_data->frameShadow = shadow;
        if ( lineWidth() > 0 )
            update();
    }
}

/*!
  \return Frame shadow
Bryant's avatar
Bryant committed
187
  /sa setFrameShadow(), lineWidth(), QFrame::frameShadow()
pixhawk's avatar
pixhawk committed
188
*/
189 190 191
QwtDial::Shadow QwtDial::frameShadow() const
{
    return d_data->frameShadow;
pixhawk's avatar
pixhawk committed
192 193 194
}

/*!
Bryant's avatar
Bryant committed
195
  Sets the line width of the frame
pixhawk's avatar
pixhawk committed
196 197 198 199

  \param lineWidth Line width
  \sa setFrameShadow()
*/
Bryant's avatar
Bryant committed
200
void QwtDial::setLineWidth( int lineWidth )
pixhawk's avatar
pixhawk committed
201 202 203 204
{
    if ( lineWidth < 0 )
        lineWidth = 0;

Bryant's avatar
Bryant committed
205 206 207 208
    if ( d_data->lineWidth != lineWidth )
    {
        invalidateCache();

pixhawk's avatar
pixhawk committed
209 210 211 212 213 214 215 216 217
        d_data->lineWidth = lineWidth;
        update();
    }
}

/*!
  \return Line width of the frame
  \sa setLineWidth(), frameShadow(), lineWidth()
*/
218 219 220
int QwtDial::lineWidth() const
{
    return d_data->lineWidth;
pixhawk's avatar
pixhawk committed
221 222 223
}

/*!
Bryant's avatar
Bryant committed
224 225
  \return bounding rectangle of the circle inside the frame
  \sa setLineWidth(), scaleInnerRect(), boundingRect()
pixhawk's avatar
pixhawk committed
226
*/
Bryant's avatar
Bryant committed
227
QRect QwtDial::innerRect() const
pixhawk's avatar
pixhawk committed
228 229
{
    const int lw = lineWidth();
Bryant's avatar
Bryant committed
230
    return boundingRect().adjusted( lw, lw, -lw, -lw );
pixhawk's avatar
pixhawk committed
231 232 233
}

/*!
Bryant's avatar
Bryant committed
234 235
  \return bounding rectangle of the dial including the frame
  \sa setLineWidth(), scaleInnerRect(), innerRect()
pixhawk's avatar
pixhawk committed
236 237 238
*/
QRect QwtDial::boundingRect() const
{
Bryant's avatar
Bryant committed
239 240 241 242 243 244
    const QRect cr = contentsRect();

    const double dim = qMin( cr.width(), cr.height() );

    QRect inner( 0, 0, dim, dim );
    inner.moveCenter( cr.center() );
pixhawk's avatar
pixhawk committed
245

Bryant's avatar
Bryant committed
246
    return inner;
pixhawk's avatar
pixhawk committed
247 248 249
}

/*!
Bryant's avatar
Bryant committed
250 251
  \return rectangle inside the scale
  \sa setLineWidth(), boundingRect(), innerRect()
pixhawk's avatar
pixhawk committed
252
*/
Bryant's avatar
Bryant committed
253
QRect QwtDial::scaleInnerRect() const
pixhawk's avatar
pixhawk committed
254
{
Bryant's avatar
Bryant committed
255 256 257 258 259 260
    QRect rect = innerRect();

    const QwtAbstractScaleDraw *sd = scaleDraw();
    if ( sd )
    {
        int scaleDist = qCeil( sd->extent( font() ) );
pixhawk's avatar
pixhawk committed
261
        scaleDist++; // margin
Bryant's avatar
Bryant committed
262 263

        rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
pixhawk's avatar
pixhawk committed
264 265
    }

Bryant's avatar
Bryant committed
266
    return rect;
pixhawk's avatar
pixhawk committed
267 268 269
}

/*!
Bryant's avatar
Bryant committed
270
  \brief Change the mode of the dial.
271 272
  \param mode New mode

Bryant's avatar
Bryant committed
273
  In case of QwtDial::RotateNeedle the needle is rotating, in case of
pixhawk's avatar
pixhawk committed
274 275
  QwtDial::RotateScale, the needle points to origin()
  and the scale is rotating.
276

pixhawk's avatar
pixhawk committed
277 278 279
  The default mode is QwtDial::RotateNeedle.

  \sa mode(), setValue(), setOrigin()
280
*/
Bryant's avatar
Bryant committed
281
void QwtDial::setMode( Mode mode )
282
{
Bryant's avatar
Bryant committed
283 284 285 286
    if ( mode != d_data->mode )
    {
        invalidateCache();

pixhawk's avatar
pixhawk committed
287
        d_data->mode = mode;
Bryant's avatar
Bryant committed
288
        sliderChange();
pixhawk's avatar
pixhawk committed
289
    }
290
}
pixhawk's avatar
pixhawk committed
291

292
/*!
Bryant's avatar
Bryant committed
293
  \return Mode of the dial.
pixhawk's avatar
pixhawk committed
294 295 296 297 298 299 300
  \sa setMode(), origin(), setScaleArc(), value()
*/
QwtDial::Mode QwtDial::mode() const
{
    return d_data->mode;
}

301
/*!
Bryant's avatar
Bryant committed
302 303 304
  Invalidate the internal caches used to speed up repainting
 */
void QwtDial::invalidateCache()
pixhawk's avatar
pixhawk committed
305
{
Bryant's avatar
Bryant committed
306
    d_data->pixmapCache = QPixmap();
307
}
pixhawk's avatar
pixhawk committed
308

309
/*!
Bryant's avatar
Bryant committed
310 311
   Paint the dial
   \param event Paint event
312
*/
Bryant's avatar
Bryant committed
313
void QwtDial::paintEvent( QPaintEvent *event )
pixhawk's avatar
pixhawk committed
314
{
Bryant's avatar
Bryant committed
315 316
    QPainter painter( this );
    painter.setClipRegion( event->region() );
pixhawk's avatar
pixhawk committed
317

Bryant's avatar
Bryant committed
318 319 320
    QStyleOption opt;
    opt.init(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
pixhawk's avatar
pixhawk committed
321

Bryant's avatar
Bryant committed
322 323 324 325
    if ( d_data->mode == QwtDial::RotateScale )
    {
        painter.save();
        painter.setRenderHint( QPainter::Antialiasing, true );
pixhawk's avatar
pixhawk committed
326

Bryant's avatar
Bryant committed
327
        drawContents( &painter );
pixhawk's avatar
pixhawk committed
328 329

        painter.restore();
Bryant's avatar
Bryant committed
330
    }
pixhawk's avatar
pixhawk committed
331

Bryant's avatar
Bryant committed
332 333 334 335 336 337 338 339 340 341 342 343
    const QRect r = contentsRect();
    if ( r.size() != d_data->pixmapCache.size() )
    {
        d_data->pixmapCache = QwtPainter::backingStore( this, r.size() );
        d_data->pixmapCache.fill( Qt::transparent );

        QPainter p( &d_data->pixmapCache );
        p.setRenderHint( QPainter::Antialiasing, true );
        p.translate( -r.topLeft() );
            
        if ( d_data->mode != QwtDial::RotateScale )
            drawContents( &p );
pixhawk's avatar
pixhawk committed
344

Bryant's avatar
Bryant committed
345 346 347 348 349
        if ( lineWidth() > 0 )
            drawFrame( &p );

        if ( d_data->mode != QwtDial::RotateNeedle )
            drawNeedle( &p );
pixhawk's avatar
pixhawk committed
350
    }
Bryant's avatar
Bryant committed
351 352 353 354 355 356 357 358

    painter.drawPixmap( r.topLeft(), d_data->pixmapCache );

    if ( d_data->mode == QwtDial::RotateNeedle )
        drawNeedle( &painter );

    if ( hasFocus() )
        drawFocusIndicator( &painter );
pixhawk's avatar
pixhawk committed
359 360 361
}

/*!
Bryant's avatar
Bryant committed
362
  Draw the focus indicator
pixhawk's avatar
pixhawk committed
363 364
  \param painter Painter
*/
Bryant's avatar
Bryant committed
365
void QwtDial::drawFocusIndicator( QPainter *painter ) const
pixhawk's avatar
pixhawk committed
366
{
Bryant's avatar
Bryant committed
367
    QwtPainter::drawFocusRect( painter, this, boundingRect() );
pixhawk's avatar
pixhawk committed
368 369 370 371 372 373 374 375
}

/*!
  Draw the frame around the dial

  \param painter Painter
  \sa lineWidth(), frameShadow()
*/
Bryant's avatar
Bryant committed
376
void QwtDial::drawFrame( QPainter *painter )
pixhawk's avatar
pixhawk committed
377
{
Bryant's avatar
Bryant committed
378 379
    QwtPainter::drawRoundFrame( painter, boundingRect(),
        palette(), lineWidth(), d_data->frameShadow );
pixhawk's avatar
pixhawk committed
380 381 382 383
}

/*!
  \brief Draw the contents inside the frame
384

Bryant's avatar
Bryant committed
385 386 387
  QPalette::Window is the background color outside of the frame.
  QPalette::Base is the background color inside the frame.
  QPalette::WindowText is the background color inside the scale.
pixhawk's avatar
pixhawk committed
388 389

  \param painter Painter
Bryant's avatar
Bryant committed
390 391 392

  \sa boundingRect(), innerRect(),
    scaleInnerRect(), QWidget::setPalette()
pixhawk's avatar
pixhawk committed
393
*/
Bryant's avatar
Bryant committed
394
void QwtDial::drawContents( QPainter *painter ) const
pixhawk's avatar
pixhawk committed
395
{
Bryant's avatar
Bryant committed
396 397 398
    if ( testAttribute( Qt::WA_NoSystemBackground ) ||
        palette().brush( QPalette::Base ) !=
            palette().brush( QPalette::Window ) )
pixhawk's avatar
pixhawk committed
399
    {
Bryant's avatar
Bryant committed
400
        const QRectF br = boundingRect();
pixhawk's avatar
pixhawk committed
401 402

        painter->save();
Bryant's avatar
Bryant committed
403 404 405
        painter->setPen( Qt::NoPen );
        painter->setBrush( palette().brush( QPalette::Base ) );
        painter->drawEllipse( br );
pixhawk's avatar
pixhawk committed
406 407 408
        painter->restore();
    }

Bryant's avatar
Bryant committed
409 410 411
    const QRectF insideScaleRect = scaleInnerRect();
    if ( palette().brush( QPalette::WindowText ) !=
            palette().brush( QPalette::Base ) )
pixhawk's avatar
pixhawk committed
412 413
    {
        painter->save();
Bryant's avatar
Bryant committed
414 415 416
        painter->setPen( Qt::NoPen );
        painter->setBrush( palette().brush( QPalette::WindowText ) );
        painter->drawEllipse( insideScaleRect );
pixhawk's avatar
pixhawk committed
417 418 419
        painter->restore();
    }

Bryant's avatar
Bryant committed
420 421
    const QPointF center = insideScaleRect.center();
    const double radius = 0.5 * insideScaleRect.width();
pixhawk's avatar
pixhawk committed
422 423

    painter->save();
Bryant's avatar
Bryant committed
424
    drawScale( painter, center, radius );
pixhawk's avatar
pixhawk committed
425 426 427
    painter->restore();

    painter->save();
Bryant's avatar
Bryant committed
428
    drawScaleContents( painter, center, radius );
pixhawk's avatar
pixhawk committed
429 430 431 432 433 434 435 436 437 438
    painter->restore();
}

/*!
  Draw the needle

  \param painter Painter
  \param center Center of the dial
  \param radius Length for the needle
  \param direction Direction of the needle in degrees, counter clockwise
Bryant's avatar
Bryant committed
439
  \param colorGroup ColorGroup
pixhawk's avatar
pixhawk committed
440
*/
Bryant's avatar
Bryant committed
441 442
void QwtDial::drawNeedle( QPainter *painter, const QPointF &center,
    double radius, double direction, QPalette::ColorGroup colorGroup ) const
pixhawk's avatar
pixhawk committed
443
{
Bryant's avatar
Bryant committed
444 445
    if ( d_data->needle )
    {
pixhawk's avatar
pixhawk committed
446
        direction = 360.0 - direction; // counter clockwise
Bryant's avatar
Bryant committed
447
        d_data->needle->draw( painter, center, radius, direction, colorGroup );
pixhawk's avatar
pixhawk committed
448 449 450
    }
}

Bryant's avatar
Bryant committed
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
void QwtDial::drawNeedle( QPainter *painter ) const
{
    if ( !isValid() )
        return;

    QPalette::ColorGroup colorGroup;
    if ( isEnabled() )
        colorGroup = hasFocus() ? QPalette::Active : QPalette::Inactive;
    else
        colorGroup = QPalette::Disabled;

    const QRectF sr = scaleInnerRect();

    painter->save();
    painter->setRenderHint( QPainter::Antialiasing, true );
    drawNeedle( painter, sr.center(), 0.5 * sr.width(),
        transform( value() ) + 270.0, colorGroup );
    painter->restore();
}

pixhawk's avatar
pixhawk committed
471 472 473 474 475 476 477
/*!
  Draw the scale

  \param painter Painter
  \param center Center of the dial
  \param radius Radius of the scale
*/
Bryant's avatar
Bryant committed
478 479
void QwtDial::drawScale( QPainter *painter, 
    const QPointF &center, double radius ) const
pixhawk's avatar
pixhawk committed
480
{
Bryant's avatar
Bryant committed
481 482
    QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
    if ( sd == NULL )
pixhawk's avatar
pixhawk committed
483 484
        return;

Bryant's avatar
Bryant committed
485 486
    sd->setRadius( radius );
    sd->moveCenter( center );
487

pixhawk's avatar
pixhawk committed
488 489
    QPalette pal = palette();

Bryant's avatar
Bryant committed
490 491
    const QColor textColor = pal.color( QPalette::Text );
    pal.setColor( QPalette::WindowText, textColor ); // ticks, backbone
492

Bryant's avatar
Bryant committed
493 494
    painter->setFont( font() );
    painter->setPen( QPen( textColor, sd->penWidth() ) );
pixhawk's avatar
pixhawk committed
495

Bryant's avatar
Bryant committed
496 497
    painter->setBrush( Qt::red );
    sd->draw( painter, pal );
pixhawk's avatar
pixhawk committed
498 499
}

Bryant's avatar
Bryant committed
500 501 502 503 504 505 506 507 508 509 510
/*!
  Draw the contents inside the scale

  Paints nothing.

  \param painter Painter
  \param center Center of the contents circle
  \param radius Radius of the contents circle
*/
void QwtDial::drawScaleContents( QPainter *painter,
    const QPointF &center, double radius ) const
pixhawk's avatar
pixhawk committed
511
{
Bryant's avatar
Bryant committed
512 513 514
    Q_UNUSED(painter);
    Q_UNUSED(center);
    Q_UNUSED(radius);
pixhawk's avatar
pixhawk committed
515 516 517 518 519 520
}

/*!
  Set a needle for the dial

  \param needle Needle
Bryant's avatar
Bryant committed
521

pixhawk's avatar
pixhawk committed
522
  \warning The needle will be deleted, when a different needle is
Bryant's avatar
Bryant committed
523
           set or in ~QwtDial()
pixhawk's avatar
pixhawk committed
524
*/
Bryant's avatar
Bryant committed
525
void QwtDial::setNeedle( QwtDialNeedle *needle )
pixhawk's avatar
pixhawk committed
526
{
Bryant's avatar
Bryant committed
527 528
    if ( needle != d_data->needle )
    {
pixhawk's avatar
pixhawk committed
529 530 531 532 533 534 535 536
        if ( d_data->needle )
            delete d_data->needle;

        d_data->needle = needle;
        update();
    }
}

537
/*!
pixhawk's avatar
pixhawk committed
538 539 540
  \return needle
  \sa setNeedle()
*/
541 542 543
const QwtDialNeedle *QwtDial::needle() const
{
    return d_data->needle;
pixhawk's avatar
pixhawk committed
544 545
}

546
/*!
pixhawk's avatar
pixhawk committed
547 548 549
  \return needle
  \sa setNeedle()
*/
550 551 552
QwtDialNeedle *QwtDial::needle()
{
    return d_data->needle;
pixhawk's avatar
pixhawk committed
553 554
}

Bryant's avatar
Bryant committed
555 556
//! \return the scale draw
QwtRoundScaleDraw *QwtDial::scaleDraw()
pixhawk's avatar
pixhawk committed
557
{
Bryant's avatar
Bryant committed
558
    return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
pixhawk's avatar
pixhawk committed
559 560
}

Bryant's avatar
Bryant committed
561 562
//! \return the scale draw
const QwtRoundScaleDraw *QwtDial::scaleDraw() const
pixhawk's avatar
pixhawk committed
563
{
Bryant's avatar
Bryant committed
564
    return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
pixhawk's avatar
pixhawk committed
565 566 567 568 569
}

/*!
  Set an individual scale draw

Bryant's avatar
Bryant committed
570 571 572 573
  The motivation for setting a scale draw is often
  to overload QwtRoundScaleDraw::label() to return 
  individual tick labels.
  
pixhawk's avatar
pixhawk committed
574 575 576
  \param scaleDraw Scale draw
  \warning The previous scale draw is deleted
*/
Bryant's avatar
Bryant committed
577
void QwtDial::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
pixhawk's avatar
pixhawk committed
578
{
Bryant's avatar
Bryant committed
579 580
    setAbstractScaleDraw( scaleDraw );
    sliderChange();
pixhawk's avatar
pixhawk committed
581 582 583
}

/*!
Bryant's avatar
Bryant committed
584
  Change the arc of the scale
pixhawk's avatar
pixhawk committed
585

Bryant's avatar
Bryant committed
586 587
  \param minArc Lower limit
  \param maxArc Upper limit
pixhawk's avatar
pixhawk committed
588

Bryant's avatar
Bryant committed
589
  \sa minScaleArc(), maxScaleArc()
pixhawk's avatar
pixhawk committed
590
*/
Bryant's avatar
Bryant committed
591
void QwtDial::setScaleArc( double minArc, double maxArc )
pixhawk's avatar
pixhawk committed
592
{
Bryant's avatar
Bryant committed
593 594 595 596
    if ( minArc != 360.0 && minArc != -360.0 )
        minArc = ::fmod( minArc, 360.0 );
    if ( maxArc != 360.0 && maxArc != -360.0 )
        maxArc = ::fmod( maxArc, 360.0 );
pixhawk's avatar
pixhawk committed
597

Bryant's avatar
Bryant committed
598 599
    double minScaleArc = qMin( minArc, maxArc );
    double maxScaleArc = qMax( minArc, maxArc );
600

Bryant's avatar
Bryant committed
601 602
    if ( maxScaleArc - minScaleArc > 360.0 )
        maxScaleArc = minScaleArc + 360.0;
pixhawk's avatar
pixhawk committed
603

Bryant's avatar
Bryant committed
604 605 606 607 608
    if ( ( minScaleArc != d_data->minScaleArc ) || 
        ( maxScaleArc != d_data->maxScaleArc ) )
    {
        d_data->minScaleArc = minScaleArc;
        d_data->maxScaleArc = maxScaleArc;
pixhawk's avatar
pixhawk committed
609

Bryant's avatar
Bryant committed
610 611
        invalidateCache();
        sliderChange();
pixhawk's avatar
pixhawk committed
612 613 614
    }
}

Bryant's avatar
Bryant committed
615 616
/*! 
  Set the lower limit for the scale arc
pixhawk's avatar
pixhawk committed
617

Bryant's avatar
Bryant committed
618 619 620 621
  \param min Lower limit of the scale arc
  \sa setScaleArc(), setMaxScaleArc()
 */
void QwtDial::setMinScaleArc( double min )
pixhawk's avatar
pixhawk committed
622
{
Bryant's avatar
Bryant committed
623
    setScaleArc( min, d_data->maxScaleArc );
pixhawk's avatar
pixhawk committed
624 625
}

Bryant's avatar
Bryant committed
626 627 628 629
/*! 
  \return Lower limit of the scale arc
  \sa setScaleArc()
*/
630 631 632
double QwtDial::minScaleArc() const
{
    return d_data->minScaleArc;
pixhawk's avatar
pixhawk committed
633 634
}

Bryant's avatar
Bryant committed
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
/*! 
  Set the upper limit for the scale arc

  \param max Upper limit of the scale arc
  \sa setScaleArc(), setMinScaleArc()
 */
void QwtDial::setMaxScaleArc( double max )
{
    setScaleArc( d_data->minScaleArc, max );
}

/*! 
  \return Upper limit of the scale arc
  \sa setScaleArc()
*/
650 651 652
double QwtDial::maxScaleArc() const
{
    return d_data->maxScaleArc;
pixhawk's avatar
pixhawk committed
653 654 655
}

/*!
656 657
  \brief Change the origin

pixhawk's avatar
pixhawk committed
658 659 660 661 662
  The origin is the angle where scale and needle is relative to.

  \param origin New origin
  \sa origin()
*/
Bryant's avatar
Bryant committed
663
void QwtDial::setOrigin( double origin )
pixhawk's avatar
pixhawk committed
664
{
Bryant's avatar
Bryant committed
665 666
    invalidateCache();

pixhawk's avatar
pixhawk committed
667
    d_data->origin = origin;
Bryant's avatar
Bryant committed
668
    sliderChange();
pixhawk's avatar
pixhawk committed
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
}

/*!
  The origin is the angle where scale and needle is relative to.

  \return Origin of the dial
  \sa setOrigin()
*/
double QwtDial::origin() const
{
    return d_data->origin;
}

/*!
  \return Size hint
Bryant's avatar
Bryant committed
684
  \sa minimumSizeHint()
pixhawk's avatar
pixhawk committed
685 686 687 688
*/
QSize QwtDial::sizeHint() const
{
    int sh = 0;
Bryant's avatar
Bryant committed
689 690
    if ( scaleDraw() )
        sh = qCeil( scaleDraw()->extent( font() ) );
pixhawk's avatar
pixhawk committed
691 692

    const int d = 6 * sh + 2 * lineWidth();
693

Bryant's avatar
Bryant committed
694 695 696 697 698
    QSize hint( d, d ); 
    if ( !isReadOnly() )
        hint = hint.expandedTo( QApplication::globalStrut() );

    return hint;
pixhawk's avatar
pixhawk committed
699 700
}

701
/*!
Bryant's avatar
Bryant committed
702 703
  \return Minimum size hint
  \sa sizeHint()
704
*/
pixhawk's avatar
pixhawk committed
705
QSize QwtDial::minimumSizeHint() const
706
{
pixhawk's avatar
pixhawk committed
707
    int sh = 0;
Bryant's avatar
Bryant committed
708 709
    if ( scaleDraw() )
        sh = qCeil( scaleDraw()->extent( font() ) );
pixhawk's avatar
pixhawk committed
710 711

    const int d = 3 * sh + 2 * lineWidth();
712

pixhawk's avatar
pixhawk committed
713 714 715
    return QSize( d, d );
}

Bryant's avatar
Bryant committed
716 717 718 719 720 721 722 723 724
/*!
  \brief Determine what to do when the user presses a mouse button.

  \param pos Mouse position

  \retval True, when the inner circle contains pos 
  \sa scrolledTo()
*/
bool QwtDial::isScrollPosition( const QPoint &pos ) const
pixhawk's avatar
pixhawk committed
725
{
Bryant's avatar
Bryant committed
726 727 728 729 730 731 732 733 734 735 736 737 738 739
    const QRegion region( innerRect(), QRegion::Ellipse );
    if ( region.contains( pos ) && ( pos != innerRect().center() ) )
    {
        double angle = QLineF( rect().center(), pos ).angle();
        if ( d_data->mode == QwtDial::RotateScale )
            angle = 360.0 - angle;

        double valueAngle = 
            qwtNormalizeDegrees( 90.0 - transform( value() ) );

        d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
        d_data->arcOffset = scaleMap().p1();

        return true;
pixhawk's avatar
pixhawk committed
740
    }
Bryant's avatar
Bryant committed
741 742

    return false;
pixhawk's avatar
pixhawk committed
743 744 745
}

/*!
Bryant's avatar
Bryant committed
746 747 748 749
  \brief Determine the value for a new position of the
         slider handle.

  \param pos Mouse position
pixhawk's avatar
pixhawk committed
750

Bryant's avatar
Bryant committed
751 752
  \return Value for the mouse position
  \sa isScrollPosition()
pixhawk's avatar
pixhawk committed
753
*/
Bryant's avatar
Bryant committed
754
double QwtDial::scrolledTo( const QPoint &pos ) const
pixhawk's avatar
pixhawk committed
755
{
Bryant's avatar
Bryant committed
756 757 758 759 760 761
    double angle = QLineF( rect().center(), pos ).angle();
    if ( d_data->mode == QwtDial::RotateScale )
    {
        angle += scaleMap().p1() - d_data->arcOffset;
        angle = 360.0 - angle;
    }
pixhawk's avatar
pixhawk committed
762

Bryant's avatar
Bryant committed
763 764
    angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
    angle = qwtNormalizeDegrees( 90.0 - angle );
pixhawk's avatar
pixhawk committed
765

Bryant's avatar
Bryant committed
766 767 768 769 770 771 772 773 774 775 776 777 778 779
    if ( scaleMap().pDist() >= 360.0 )
    {
        if ( angle < scaleMap().p1() )
            angle += 360.0;

        if ( !wrapping() )
        {
            double boundedAngle = angle;

            const double arc = angle - transform( value() );
            if ( qAbs( arc ) > 180.0 )
            {
                boundedAngle = ( arc > 0 ) 
                    ? scaleMap().p1() : scaleMap().p2();
pixhawk's avatar
pixhawk committed
780
            }
Bryant's avatar
Bryant committed
781 782 783 784

            d_data->mouseOffset += ( boundedAngle - angle );

            angle = boundedAngle;
pixhawk's avatar
pixhawk committed
785
        }
Bryant's avatar
Bryant committed
786 787 788 789 790 791 792 793 794 795
    }
    else
    {
        const double boundedAngle =
            qwtBoundedAngle( scaleMap().p1(), angle, scaleMap().p2() );

        if ( !wrapping() )
            d_data->mouseOffset += ( boundedAngle - angle );

        angle = boundedAngle;
pixhawk's avatar
pixhawk committed
796 797
    }

Bryant's avatar
Bryant committed
798
    return invTransform( angle );
pixhawk's avatar
pixhawk committed
799 800 801
}

/*!
Bryant's avatar
Bryant committed
802 803 804 805
  Change Event handler
  \param event Change event

  Invalidates internal paint caches if necessary
pixhawk's avatar
pixhawk committed
806
*/
Bryant's avatar
Bryant committed
807
void QwtDial::changeEvent( QEvent *event )
pixhawk's avatar
pixhawk committed
808
{
Bryant's avatar
Bryant committed
809 810 811 812 813 814 815 816 817 818 819 820 821 822
    switch( event->type() )
    {
        case QEvent::EnabledChange:
        case QEvent::FontChange:
        case QEvent::StyleChange:
        case QEvent::PaletteChange:
        case QEvent::LanguageChange:
        case QEvent::LocaleChange:
        {
            invalidateCache();
            break;
        }
        default:
            break;
pixhawk's avatar
pixhawk committed
823
    }
Bryant's avatar
Bryant committed
824 825
    
    QwtAbstractSlider::changeEvent( event );
pixhawk's avatar
pixhawk committed
826 827
}

828
/*!
Bryant's avatar
Bryant committed
829 830
  Wheel Event handler
  \param event Wheel event
pixhawk's avatar
pixhawk committed
831
*/
Bryant's avatar
Bryant committed
832
void QwtDial::wheelEvent( QWheelEvent *event )
pixhawk's avatar
pixhawk committed
833
{
Bryant's avatar
Bryant committed
834 835 836 837
    const QRegion region( innerRect(), QRegion::Ellipse );
    if ( region.contains( event->pos() ) )
        QwtAbstractSlider::wheelEvent( event );
}
pixhawk's avatar
pixhawk committed
838

Bryant's avatar
Bryant committed
839 840 841 842 843 844 845
void QwtDial::setAngleRange( double angle, double span )
{
    QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
    if ( sd  )
    {
        angle = qwtNormalizeDegrees( angle - 270.0 );
        sd->setAngleRange( angle, angle + span );
pixhawk's avatar
pixhawk committed
846 847 848 849
    }
}

/*!
Bryant's avatar
Bryant committed
850 851 852 853 854 855 856 857
  Invalidate the internal caches and call 
  QwtAbstractSlider::scaleChange()
 */
void QwtDial::scaleChange()
{
    invalidateCache();
    QwtAbstractSlider::scaleChange();
}
pixhawk's avatar
pixhawk committed
858

Bryant's avatar
Bryant committed
859
void QwtDial::sliderChange()
pixhawk's avatar
pixhawk committed
860
{
Bryant's avatar
Bryant committed
861 862 863 864 865 866 867 868 869 870 871
    setAngleRange( d_data->origin + d_data->minScaleArc,
        d_data->maxScaleArc - d_data->minScaleArc );

    if ( mode() == RotateScale )
    {
        const double arc = transform( value() ) - scaleMap().p1();
        setAngleRange( d_data->origin - arc,
            d_data->maxScaleArc - d_data->minScaleArc );
    }

    QwtAbstractSlider::sliderChange();
pixhawk's avatar
pixhawk committed
872
}