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
}