~ubuntu-branches/ubuntu/oneiric/qwt/oneiric-proposed

« back to all changes in this revision

Viewing changes to qwt-5.1.2/src/qwt_dial.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2009-04-12 23:25:58 UTC
  • mfrom: (1.1.4 upstream) (2.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090412232558-3bl06x785yr8xm8u
Tags: 5.1.2-1
* New upstream release.
* Bump compat/debhelper to 7.
* Bump Standards-Version to 3.8.1. No changes needed.
* Invert Maintainers and Uploaders field.
* Fix lintian warnings:
  - dh_clean _k deprecated.
  - missing dependency on libc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 
2
 * Qwt Widget Library
 
3
 * Copyright (C) 1997   Josef Wilgen
 
4
 * Copyright (C) 2002   Uwe Rathmann
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the Qwt License, Version 1.0
 
8
 *****************************************************************************/
 
9
 
 
10
#include <math.h>
 
11
#include <qpainter.h>
 
12
#if QT_VERSION >= 0x040000
 
13
#include <qbitmap.h>
 
14
#include <qpalette.h>
 
15
#endif
 
16
#include <qpixmap.h>
 
17
#include <qevent.h>
 
18
#include "qwt_math.h"
 
19
#include "qwt_scale_engine.h"
 
20
#include "qwt_scale_map.h"
 
21
#include "qwt_paint_buffer.h"
 
22
#include "qwt_painter.h"
 
23
#include "qwt_dial_needle.h"
 
24
#include "qwt_dial.h"
 
25
 
 
26
class QwtDial::PrivateData
 
27
{
 
28
public:
 
29
    PrivateData():
 
30
        visibleBackground(true),
 
31
        frameShadow(Sunken),
 
32
        lineWidth(0),
 
33
        mode(RotateNeedle),
 
34
        origin(90.0),
 
35
        minScaleArc(0.0),
 
36
        maxScaleArc(0.0),
 
37
        scaleDraw(0),
 
38
        maxMajIntv(36),
 
39
        maxMinIntv(10),
 
40
        scaleStep(0.0),
 
41
        needle(0)
 
42
    {
 
43
    }
 
44
 
 
45
    ~PrivateData()
 
46
    {
 
47
        delete scaleDraw;
 
48
        delete needle;
 
49
    }
 
50
    bool visibleBackground;
 
51
    Shadow frameShadow;
 
52
    int lineWidth;
 
53
 
 
54
    QwtDial::Mode mode;
 
55
 
 
56
    double origin;
 
57
    double minScaleArc;
 
58
    double maxScaleArc;
 
59
 
 
60
    QwtDialScaleDraw *scaleDraw;
 
61
    int maxMajIntv;
 
62
    int maxMinIntv;
 
63
    double scaleStep;
 
64
 
 
65
    QwtDialNeedle *needle;
 
66
 
 
67
    static double previousDir;
 
68
};
 
69
 
 
70
double QwtDial::PrivateData::previousDir = -1.0;
 
71
 
 
72
/*!
 
73
  Constructor
 
74
 
 
75
  \param parent Parent dial widget
 
76
*/
 
77
QwtDialScaleDraw::QwtDialScaleDraw(QwtDial *parent):
 
78
    d_parent(parent),
 
79
    d_penWidth(1)
 
80
{
 
81
}
 
82
 
 
83
/*!
 
84
  Set the pen width used for painting the scale
 
85
 
 
86
  \param penWidth Pen width
 
87
  \sa penWidth(), QwtDial::drawScale()
 
88
*/
 
89
    
 
90
void QwtDialScaleDraw::setPenWidth(uint penWidth)
 
91
{
 
92
    d_penWidth = penWidth;
 
93
}
 
94
 
 
95
/*!
 
96
  \return Pen width used for painting the scale
 
97
  \sa setPenWidth, QwtDial::drawScale()
 
98
*/
 
99
uint QwtDialScaleDraw::penWidth() const
 
100
{
 
101
    return d_penWidth;
 
102
}
 
103
 
 
104
/*! 
 
105
  Call QwtDial::scaleLabel of the parent dial widget.
 
106
 
 
107
  \param value Value to display
 
108
    
 
109
  \sa QwtDial::scaleLabel
 
110
*/  
 
111
QwtText QwtDialScaleDraw::label(double value) const
 
112
{
 
113
    if ( d_parent == NULL )
 
114
        return QwtRoundScaleDraw::label(value);
 
115
 
 
116
    return d_parent->scaleLabel(value);
 
117
}
 
118
 
 
119
/*!
 
120
  \brief Constructor
 
121
  \param parent Parent widget
 
122
 
 
123
  Create a dial widget with no scale and no needle. 
 
124
  The default origin is 90.0 with no valid value. It accepts
 
125
  mouse and keyboard inputs and has no step size. The default mode
 
126
  is QwtDial::RotateNeedle.
 
127
*/  
 
128
 
 
129
QwtDial::QwtDial(QWidget* parent):
 
130
    QwtAbstractSlider(Qt::Horizontal, parent)
 
131
{
 
132
    initDial();
 
133
}
 
134
 
 
135
#if QT_VERSION < 0x040000
 
136
/*!
 
137
  \brief Constructor
 
138
  \param parent Parent widget
 
139
  \param name Object name
 
140
 
 
141
  Create a dial widget with no scale and no needle. 
 
142
  The default origin is 90.0 with no valid value. It accepts
 
143
  mouse and keyboard inputs and has no step size. The default mode
 
144
  is QwtDial::RotateNeedle.
 
145
*/  
 
146
QwtDial::QwtDial(QWidget* parent, const char *name):
 
147
    QwtAbstractSlider(Qt::Horizontal, parent)
 
148
{
 
149
    setName(name);
 
150
    initDial();
 
151
}
 
152
#endif
 
153
 
 
154
void QwtDial::initDial()
 
155
{
 
156
    d_data = new PrivateData;
 
157
 
 
158
#if QT_VERSION < 0x040000
 
159
    setWFlags(Qt::WNoAutoErase);
 
160
#endif 
 
161
 
 
162
#if QT_VERSION >= 0x040000
 
163
    using namespace Qt;
 
164
#endif
 
165
    setFocusPolicy(TabFocus);
 
166
 
 
167
    QPalette p = palette();
 
168
    for ( int i = 0; i < QPalette::NColorGroups; i++ )
 
169
    {
 
170
        const QPalette::ColorGroup cg = (QPalette::ColorGroup)i;
 
171
 
 
172
        // Base: background color of the circle inside the frame.
 
173
        // Foreground: background color of the circle inside the scale
 
174
 
 
175
#if QT_VERSION < 0x040000
 
176
        p.setColor(cg, QColorGroup::Foreground, 
 
177
            p.color(cg, QColorGroup::Base));
 
178
#else
 
179
        p.setColor(cg, QPalette::Foreground, 
 
180
            p.color(cg, QPalette::Base));
 
181
#endif
 
182
    }
 
183
    setPalette(p);
 
184
 
 
185
    d_data->scaleDraw = new QwtDialScaleDraw(this);
 
186
    d_data->scaleDraw->setRadius(0);
 
187
 
 
188
    setScaleArc(0.0, 360.0); // scale as a full circle
 
189
    setRange(0.0, 360.0, 1.0, 10); // degrees as deafult
 
190
}
 
191
 
 
192
//!  Destructor
 
193
QwtDial::~QwtDial() 
 
194
{
 
195
    delete d_data;
 
196
}
 
197
 
 
198
/*!
 
199
  Show/Hide the area outside of the frame
 
200
  \param show Show if true, hide if false
 
201
 
 
202
  \sa hasVisibleBackground(), setMask()
 
203
  \warning When QwtDial is a toplevel widget the window
 
204
           border might disappear too.
 
205
*/
 
206
void QwtDial::showBackground(bool show)
 
207
{
 
208
    if ( d_data->visibleBackground != show )
 
209
    {
 
210
        d_data->visibleBackground = show;
 
211
        updateMask();
 
212
    }
 
213
}
 
214
 
 
215
/*!
 
216
  true when the area outside of the frame is visible
 
217
 
 
218
  \sa showBackground(), setMask()
 
219
*/
 
220
bool QwtDial::hasVisibleBackground() const 
 
221
 
222
    return d_data->visibleBackground; 
 
223
}
 
224
 
 
225
/*!
 
226
  Sets the frame shadow value from the frame style.
 
227
  \param shadow Frame shadow
 
228
  \sa setLineWidth(), QFrame::setFrameShadow()
 
229
*/
 
230
void QwtDial::setFrameShadow(Shadow shadow)
 
231
{
 
232
    if ( shadow != d_data->frameShadow )
 
233
    {
 
234
        d_data->frameShadow = shadow;
 
235
        if ( lineWidth() > 0 )
 
236
            update();
 
237
    }
 
238
}
 
239
 
 
240
/*!
 
241
  \return Frame shadow
 
242
  /sa setFrameShadow(), lineWidth(), QFrame::frameShadow
 
243
*/
 
244
QwtDial::Shadow QwtDial::frameShadow() const 
 
245
 
246
    return d_data->frameShadow; 
 
247
}
 
248
 
 
249
/*!
 
250
  Sets the line width
 
251
 
 
252
  \param lineWidth Line width
 
253
  \sa setFrameShadow()
 
254
*/
 
255
void QwtDial::setLineWidth(int lineWidth)
 
256
{
 
257
    if ( lineWidth < 0 )
 
258
        lineWidth = 0;
 
259
 
 
260
    if ( d_data->lineWidth != lineWidth )
 
261
    {
 
262
        d_data->lineWidth = lineWidth;
 
263
        update();
 
264
    }
 
265
}
 
266
 
 
267
/*!
 
268
  \return Line width of the frame
 
269
  \sa setLineWidth(), frameShadow(), lineWidth()
 
270
*/
 
271
int QwtDial::lineWidth() const 
 
272
 
273
    return d_data->lineWidth; 
 
274
}
 
275
 
 
276
/*!
 
277
  \return bounding rect of the circle inside the frame
 
278
  \sa setLineWidth(), scaleContentsRect(), boundingRect()
 
279
*/
 
280
QRect QwtDial::contentsRect() const
 
281
{
 
282
    const int lw = lineWidth();
 
283
 
 
284
    QRect r = boundingRect();
 
285
    if ( lw > 0 )
 
286
    {
 
287
        r.setRect(r.x() + lw, r.y() + lw, 
 
288
            r.width() - 2 * lw, r.height() - 2 * lw);
 
289
    }
 
290
    return r;
 
291
}
 
292
 
 
293
/*!
 
294
  \return bounding rect of the dial including the frame
 
295
  \sa setLineWidth(), scaleContentsRect(), contentsRect()
 
296
*/
 
297
QRect QwtDial::boundingRect() const
 
298
{
 
299
    const int radius = qwtMin(width(), height()) / 2;
 
300
 
 
301
    QRect r(0, 0, 2 * radius, 2 * radius);
 
302
    r.moveCenter(rect().center());
 
303
    return r;
 
304
}
 
305
 
 
306
/*!
 
307
  \return rect inside the scale
 
308
  \sa setLineWidth(), boundingRect(), contentsRect()
 
309
*/
 
310
QRect QwtDial::scaleContentsRect() const
 
311
{
 
312
#if QT_VERSION < 0x040000
 
313
    const QPen scalePen(colorGroup().text(), 0, Qt::NoPen);
 
314
#else
 
315
    const QPen scalePen(palette().text(), 0, Qt::NoPen);
 
316
#endif
 
317
 
 
318
    int scaleDist = 0;
 
319
    if ( d_data->scaleDraw )
 
320
    {
 
321
        scaleDist = d_data->scaleDraw->extent(scalePen, font());
 
322
        scaleDist++; // margin
 
323
    }
 
324
 
 
325
    const QRect rect = contentsRect();
 
326
    return QRect(rect.x() + scaleDist, rect.y() + scaleDist,
 
327
        rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist);
 
328
}
 
329
 
 
330
/*!
 
331
  \brief Change the mode of the meter.
 
332
  \param mode New mode 
 
333
    
 
334
  The value of the meter is indicated by the difference
 
335
  between north of the scale and the direction of the needle.
 
336
  In case of QwtDial::RotateNeedle north is pointing
 
337
  to the origin() and the needle is rotating, in case of
 
338
  QwtDial::RotateScale, the needle points to origin()
 
339
  and the scale is rotating.
 
340
    
 
341
  The default mode is QwtDial::RotateNeedle.
 
342
 
 
343
  \sa mode(), setValue(), setOrigin()
 
344
*/  
 
345
void QwtDial::setMode(Mode mode)
 
346
{   
 
347
    if ( mode != d_data->mode )
 
348
    {
 
349
        d_data->mode = mode;
 
350
        update(); 
 
351
    }
 
352
}       
 
353
 
 
354
/*! 
 
355
  \return mode of the dial.
 
356
    
 
357
  The value of the dial is indicated by the difference
 
358
  between the origin and the direction of the needle.
 
359
  In case of QwtDial::RotateNeedle the scale arc is fixed
 
360
  to the origin() and the needle is rotating, in case of
 
361
  QwtDial::RotateScale, the needle points to origin()
 
362
  and the scale is rotating.
 
363
 
 
364
  The default mode is QwtDial::RotateNeedle.
 
365
 
 
366
  \sa setMode(), origin(), setScaleArc(), value()
 
367
*/
 
368
QwtDial::Mode QwtDial::mode() const
 
369
{
 
370
    return d_data->mode;
 
371
}
 
372
 
 
373
/*! 
 
374
    Sets whether it is possible to step the value from the highest value to 
 
375
    the lowest value and vice versa to on.
 
376
 
 
377
    \param wrapping en/disables wrapping
 
378
 
 
379
    \sa wrapping(), QwtDoubleRange::periodic()
 
380
    \note The meaning of wrapping is like the wrapping property of QSpinBox,
 
381
          but not like it is used in QDial. 
 
382
*/
 
383
void QwtDial::setWrapping(bool wrapping)
 
384
{
 
385
    setPeriodic(wrapping);
 
386
 
387
 
 
388
/*! 
 
389
    wrapping() holds whether it is possible to step the value from the 
 
390
    highest value to the lowest value and vice versa. 
 
391
 
 
392
    \sa setWrapping(), QwtDoubleRange::setPeriodic()
 
393
    \note The meaning of wrapping is like the wrapping property of QSpinBox,
 
394
          but not like it is used in QDial. 
 
395
*/ 
 
396
bool QwtDial::wrapping() const
 
397
{
 
398
    return periodic();
 
399
}
 
400
 
 
401
/*! 
 
402
   Resize the dial widget
 
403
   \param e Resize event
 
404
*/
 
405
void QwtDial::resizeEvent(QResizeEvent *e)
 
406
{
 
407
    QWidget::resizeEvent(e);
 
408
 
 
409
    if ( !hasVisibleBackground() )
 
410
        updateMask();
 
411
}
 
412
 
 
413
/*! 
 
414
   Paint the dial 
 
415
   \param e Paint event
 
416
*/
 
417
void QwtDial::paintEvent(QPaintEvent *e)
 
418
{
 
419
    const QRect &ur = e->rect();
 
420
    if ( ur.isValid() )
 
421
    {
 
422
#if QT_VERSION < 0x040000
 
423
        QwtPaintBuffer paintBuffer(this, ur);
 
424
        QPainter &painter = *paintBuffer.painter();
 
425
#else
 
426
        QPainter painter(this);
 
427
        painter.setRenderHint(QPainter::Antialiasing, true);
 
428
#endif
 
429
 
 
430
        painter.save();
 
431
        drawContents(&painter);
 
432
        painter.restore();
 
433
 
 
434
        painter.save();
 
435
        drawFrame(&painter);
 
436
        painter.restore();
 
437
 
 
438
        if ( hasFocus() )
 
439
            drawFocusIndicator(&painter);
 
440
    }
 
441
}
 
442
 
 
443
/*!
 
444
  Draw a dotted round circle, if !isReadOnly()
 
445
 
 
446
  \param painter Painter
 
447
*/
 
448
void QwtDial::drawFocusIndicator(QPainter *painter) const
 
449
{
 
450
    if ( !isReadOnly() )
 
451
    {
 
452
        QRect focusRect = contentsRect();
 
453
 
 
454
        const int margin = 2;
 
455
        focusRect.setRect( 
 
456
            focusRect.x() + margin,
 
457
            focusRect.y() + margin,
 
458
            focusRect.width() - 2 * margin,
 
459
            focusRect.height() - 2 * margin);
 
460
 
 
461
#if QT_VERSION < 0x040000
 
462
        QColor color = colorGroup().color(QColorGroup::Base);
 
463
#else
 
464
        QColor color = palette().color(QPalette::Base);
 
465
#endif
 
466
        if (color.isValid())
 
467
        {
 
468
            const QColor gray(Qt::gray);
 
469
 
 
470
            int h, s, v;
 
471
#if QT_VERSION < 0x040000
 
472
            color.hsv(&h, &s, &v);
 
473
#else
 
474
            color.getHsv(&h, &s, &v);
 
475
#endif
 
476
            color = (v > 128) ? gray.dark(120) : gray.light(120);
 
477
        }
 
478
        else
 
479
            color = Qt::darkGray;
 
480
 
 
481
        painter->save();
 
482
        painter->setBrush(Qt::NoBrush);
 
483
        painter->setPen(QPen(color, 0, Qt::DotLine));
 
484
        painter->drawEllipse(focusRect);
 
485
        painter->restore();
 
486
    }
 
487
}
 
488
 
 
489
/*!
 
490
  Draw the frame around the dial
 
491
 
 
492
  \param painter Painter
 
493
  \sa lineWidth(), frameShadow()
 
494
*/
 
495
void QwtDial::drawFrame(QPainter *painter)
 
496
{
 
497
    const int lw = lineWidth();
 
498
    const int off = (lw + 1) % 2;
 
499
 
 
500
    QRect r = boundingRect();
 
501
    r.setRect(r.x() + lw / 2 - off, r.y() + lw / 2 - off,
 
502
        r.width() - lw + off + 1, r.height() - lw + off + 1);
 
503
#if QT_VERSION >= 0x040000
 
504
#ifdef __GNUC__
 
505
#endif
 
506
    r.setX(r.x() + 1);
 
507
    r.setY(r.y() + 1);
 
508
    r.setWidth(r.width() - 2);
 
509
    r.setHeight(r.height() - 2);
 
510
#endif
 
511
 
 
512
    if ( lw > 0 )
 
513
    {
 
514
        switch(d_data->frameShadow)
 
515
        {
 
516
            case QwtDial::Raised:
 
517
#if QT_VERSION < 0x040000
 
518
                QwtPainter::drawRoundFrame(painter, r, 
 
519
                    lw, colorGroup(), false);
 
520
#else
 
521
                QwtPainter::drawRoundFrame(painter, r, 
 
522
                    lw, palette(), false);
 
523
#endif
 
524
                break;
 
525
            case QwtDial::Sunken:
 
526
#if QT_VERSION < 0x040000
 
527
                QwtPainter::drawRoundFrame(painter, r, 
 
528
                    lw, colorGroup(), true);
 
529
#else
 
530
                QwtPainter::drawRoundFrame(painter, r, 
 
531
                    lw, palette(), true);
 
532
#endif
 
533
                break;
 
534
            default: // Plain
 
535
            {
 
536
                painter->save();
 
537
                painter->setPen(QPen(Qt::black, lw));
 
538
                painter->setBrush(Qt::NoBrush);
 
539
                painter->drawEllipse(r);
 
540
                painter->restore();
 
541
            }
 
542
        }
 
543
    }
 
544
}
 
545
 
 
546
/*!
 
547
  \brief Draw the contents inside the frame
 
548
 
 
549
  QColorGroup::Background is the background color outside of the frame.
 
550
  QColorGroup::Base is the background color inside the frame.
 
551
  QColorGroup::Foreground is the background color inside the scale.
 
552
 
 
553
  \param painter Painter
 
554
  \sa boundingRect(), contentsRect(),
 
555
    scaleContentsRect(), QWidget::setPalette
 
556
*/
 
557
void QwtDial::drawContents(QPainter *painter) const
 
558
{
 
559
#if QT_VERSION < 0x040000
 
560
    if ( backgroundMode() == Qt::NoBackground || 
 
561
        colorGroup().brush(QColorGroup::Base) != 
 
562
            colorGroup().brush(QColorGroup::Background) )
 
563
#else
 
564
    if ( testAttribute(Qt::WA_NoSystemBackground) ||
 
565
        palette().brush(QPalette::Base) != 
 
566
            palette().brush(QPalette::Background) )
 
567
#endif
 
568
    {
 
569
 
 
570
        const QRect br = boundingRect();
 
571
 
 
572
        painter->save();
 
573
        painter->setPen(Qt::NoPen);
 
574
 
 
575
#if QT_VERSION < 0x040000
 
576
        painter->setBrush(colorGroup().brush(QColorGroup::Base));
 
577
#else
 
578
        painter->setBrush(palette().brush(QPalette::Base));
 
579
#endif
 
580
 
 
581
        painter->drawEllipse(br);
 
582
        painter->restore();
 
583
    }
 
584
 
 
585
 
 
586
    const QRect insideScaleRect = scaleContentsRect();
 
587
#if QT_VERSION < 0x040000
 
588
    if ( colorGroup().brush(QColorGroup::Foreground) !=
 
589
        colorGroup().brush(QColorGroup::Base) )
 
590
#else
 
591
    if ( palette().brush(QPalette::Foreground) !=
 
592
        palette().brush(QPalette::Base) )
 
593
#endif
 
594
    {
 
595
        painter->save();
 
596
        painter->setPen(Qt::NoPen);
 
597
 
 
598
#if QT_VERSION < 0x040000
 
599
        painter->setBrush(colorGroup().brush(QColorGroup::Foreground));
 
600
#else
 
601
        painter->setBrush(palette().brush(QPalette::Foreground));
 
602
#endif
 
603
 
 
604
        painter->drawEllipse(insideScaleRect.x() - 1, insideScaleRect.y() - 1,
 
605
            insideScaleRect.width(), insideScaleRect.height() );
 
606
 
 
607
        painter->restore();
 
608
    }
 
609
 
 
610
    const QPoint center = insideScaleRect.center();
 
611
    const int radius = insideScaleRect.width() / 2;
 
612
 
 
613
    painter->save();
 
614
    drawScaleContents(painter, center, radius);
 
615
    painter->restore();
 
616
 
 
617
    double direction = d_data->origin;
 
618
 
 
619
    if (isValid())
 
620
    {
 
621
        direction = d_data->origin + d_data->minScaleArc;
 
622
        if ( maxValue() > minValue() && d_data->maxScaleArc > d_data->minScaleArc )
 
623
        {
 
624
            const double ratio = 
 
625
                (value() - minValue()) / (maxValue() - minValue());
 
626
            direction += ratio * (d_data->maxScaleArc - d_data->minScaleArc);
 
627
        }
 
628
 
 
629
        if ( direction >= 360.0 )
 
630
            direction -= 360.0;
 
631
    }
 
632
 
 
633
    double origin = d_data->origin;
 
634
    if ( mode() == RotateScale )
 
635
    {
 
636
        origin -= direction - d_data->origin;
 
637
        direction = d_data->origin;
 
638
    }
 
639
 
 
640
    painter->save();
 
641
    drawScale(painter, center, radius, origin, d_data->minScaleArc, d_data->maxScaleArc);
 
642
    painter->restore();
 
643
 
 
644
    if ( isValid() )
 
645
    {
 
646
        QPalette::ColorGroup cg;
 
647
        if ( isEnabled() )
 
648
            cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
 
649
        else
 
650
            cg = QPalette::Disabled;
 
651
 
 
652
        painter->save();
 
653
        drawNeedle(painter, center, radius, direction, cg);
 
654
        painter->restore();
 
655
    }
 
656
}
 
657
 
 
658
/*!
 
659
  Draw the needle
 
660
 
 
661
  \param painter Painter
 
662
  \param center Center of the dial
 
663
  \param radius Length for the needle
 
664
  \param direction Direction of the needle in degrees, counter clockwise
 
665
  \param cg ColorGroup
 
666
*/
 
667
void QwtDial::drawNeedle(QPainter *painter, const QPoint &center, 
 
668
    int radius, double direction, QPalette::ColorGroup cg) const
 
669
{
 
670
    if ( d_data->needle )
 
671
    {
 
672
        direction = 360.0 - direction; // counter clockwise
 
673
        d_data->needle->draw(painter, center, radius, direction, cg);
 
674
    }
 
675
}
 
676
 
 
677
/*!
 
678
  Draw the scale
 
679
 
 
680
  \param painter Painter
 
681
  \param center Center of the dial
 
682
  \param radius Radius of the scale
 
683
  \param origin Origin of the scale
 
684
  \param minArc Minimum of the arc 
 
685
  \param maxArc Minimum of the arc 
 
686
  
 
687
  \sa QwtAbstractScaleDraw::setAngleRange
 
688
*/
 
689
void QwtDial::drawScale(QPainter *painter, const QPoint &center,
 
690
    int radius, double origin, double minArc, double maxArc) const
 
691
{
 
692
    if ( d_data->scaleDraw == NULL )
 
693
        return;
 
694
 
 
695
    origin -= 270.0; // hardcoded origin of QwtScaleDraw
 
696
 
 
697
    double angle = maxArc - minArc;
 
698
    if ( angle > 360.0 )
 
699
        angle = fmod(angle, 360.0);
 
700
 
 
701
    minArc += origin;
 
702
    if ( minArc < -360.0 )
 
703
        minArc = fmod(minArc, 360.0);
 
704
    
 
705
    maxArc = minArc + angle;
 
706
    if ( maxArc > 360.0 )
 
707
    {
 
708
        // QwtAbstractScaleDraw::setAngleRange accepts only values
 
709
        // in the range [-360.0..360.0]
 
710
        minArc -= 360.0;
 
711
        maxArc -= 360.0;
 
712
    }
 
713
    
 
714
    painter->setFont(font());
 
715
 
 
716
    d_data->scaleDraw->setAngleRange(minArc, maxArc);
 
717
    d_data->scaleDraw->setRadius(radius);
 
718
    d_data->scaleDraw->moveCenter(center);
 
719
 
 
720
#if QT_VERSION < 0x040000
 
721
    QColorGroup cg = colorGroup();
 
722
 
 
723
    const QColor textColor = cg.color(QColorGroup::Text);
 
724
    cg.setColor(QColorGroup::Foreground, textColor);
 
725
    painter->setPen(QPen(textColor, d_data->scaleDraw->penWidth()));
 
726
    
 
727
    d_data->scaleDraw->draw(painter, cg);
 
728
#else
 
729
    QPalette pal = palette();
 
730
 
 
731
    const QColor textColor = pal.color(QPalette::Text);
 
732
    pal.setColor(QPalette::Foreground, textColor); //ticks, backbone
 
733
    
 
734
    painter->setPen(QPen(textColor, d_data->scaleDraw->penWidth()));
 
735
 
 
736
    d_data->scaleDraw->draw(painter, pal);
 
737
#endif
 
738
}
 
739
 
 
740
void QwtDial::drawScaleContents(QPainter *, 
 
741
    const QPoint &, int) const
 
742
{
 
743
    // empty default implementation
 
744
}
 
745
 
 
746
/*!
 
747
  Set a needle for the dial
 
748
 
 
749
  Qwt is missing a set of good looking needles. 
 
750
  Contributions are very welcome.
 
751
 
 
752
  \param needle Needle
 
753
  \warning The needle will be deleted, when a different needle is
 
754
    set or in ~QwtDial()
 
755
*/
 
756
void QwtDial::setNeedle(QwtDialNeedle *needle)
 
757
{
 
758
    if ( needle != d_data->needle )
 
759
    {
 
760
        if ( d_data->needle )
 
761
            delete d_data->needle;
 
762
 
 
763
        d_data->needle = needle;
 
764
        update();
 
765
    }
 
766
}
 
767
 
 
768
/*! 
 
769
  \return needle
 
770
  \sa setNeedle()
 
771
*/
 
772
const QwtDialNeedle *QwtDial::needle() const 
 
773
 
774
    return d_data->needle; 
 
775
}
 
776
 
 
777
/*! 
 
778
  \return needle
 
779
  \sa setNeedle()
 
780
*/
 
781
QwtDialNeedle *QwtDial::needle() 
 
782
 
783
    return d_data->needle; 
 
784
}
 
785
 
 
786
//! QwtDoubleRange update hook
 
787
void QwtDial::rangeChange()
 
788
{
 
789
    updateScale();
 
790
}
 
791
 
 
792
/*! 
 
793
  Update the scale with the current attributes
 
794
  \sa setScale()
 
795
*/
 
796
void QwtDial::updateScale()
 
797
{
 
798
    if ( d_data->scaleDraw )
 
799
    {
 
800
        QwtLinearScaleEngine scaleEngine;
 
801
 
 
802
        const QwtScaleDiv scaleDiv = scaleEngine.divideScale(
 
803
            minValue(), maxValue(), 
 
804
            d_data->maxMajIntv, d_data->maxMinIntv, d_data->scaleStep);
 
805
 
 
806
        d_data->scaleDraw->setTransformation(scaleEngine.transformation());
 
807
        d_data->scaleDraw->setScaleDiv(scaleDiv);
 
808
    }
 
809
}
 
810
 
 
811
//! Return the scale draw
 
812
QwtDialScaleDraw *QwtDial::scaleDraw() 
 
813
 
814
    return d_data->scaleDraw; 
 
815
}
 
816
 
 
817
//! Return the scale draw
 
818
const QwtDialScaleDraw *QwtDial::scaleDraw() const 
 
819
 
820
    return d_data->scaleDraw; 
 
821
}
 
822
 
 
823
/*!
 
824
  Set an individual scale draw
 
825
 
 
826
  \param scaleDraw Scale draw
 
827
  \warning The previous scale draw is deleted
 
828
*/
 
829
void QwtDial::setScaleDraw(QwtDialScaleDraw *scaleDraw)
 
830
{
 
831
    if ( scaleDraw != d_data->scaleDraw )
 
832
    {
 
833
        if ( d_data->scaleDraw )
 
834
            delete d_data->scaleDraw;
 
835
    
 
836
        d_data->scaleDraw = scaleDraw;
 
837
        updateScale();
 
838
        update();
 
839
    }
 
840
}
 
841
 
 
842
/*!
 
843
  Change the intervals of the scale
 
844
  \sa QwtAbstractScaleDraw::setScale
 
845
*/
 
846
void QwtDial::setScale(int maxMajIntv, int maxMinIntv, double step)
 
847
{
 
848
    d_data->maxMajIntv = maxMajIntv;
 
849
    d_data->maxMinIntv = maxMinIntv;
 
850
    d_data->scaleStep = step;
 
851
 
 
852
    updateScale();
 
853
}
 
854
 
 
855
/*!
 
856
  A wrapper method for accessing the scale draw. 
 
857
 
 
858
  - options == 0\n
 
859
    No visible scale: setScaleDraw(NULL)
 
860
  - options & ScaleBackbone\n
 
861
    En/disable the backbone of the scale.
 
862
  - options & ScaleTicks\n
 
863
    En/disable the ticks of the scale.
 
864
  - options & ScaleLabel\n
 
865
    En/disable scale labels
 
866
    
 
867
  \sa QwtAbstractScaleDraw::enableComponent 
 
868
*/
 
869
void QwtDial::setScaleOptions(int options)
 
870
{
 
871
    if ( options == 0 )
 
872
        setScaleDraw(NULL);
 
873
 
 
874
    QwtDialScaleDraw *sd = d_data->scaleDraw;
 
875
    if ( sd == NULL )
 
876
        return;
 
877
 
 
878
    sd->enableComponent(QwtAbstractScaleDraw::Backbone, 
 
879
        options & ScaleBackbone);
 
880
 
 
881
    sd->enableComponent(QwtAbstractScaleDraw::Ticks, 
 
882
        options & ScaleTicks);
 
883
    
 
884
    sd->enableComponent(QwtAbstractScaleDraw::Labels, 
 
885
        options & ScaleLabel);
 
886
}
 
887
 
 
888
//! See: QwtAbstractScaleDraw::setTickLength, QwtDialScaleDraw::setPenWidth
 
889
void QwtDial::setScaleTicks(int minLen, int medLen, 
 
890
    int majLen, int penWidth)
 
891
{
 
892
    QwtDialScaleDraw *sd = d_data->scaleDraw;
 
893
    if ( sd )
 
894
    {
 
895
        sd->setTickLength(QwtScaleDiv::MinorTick, minLen);
 
896
        sd->setTickLength(QwtScaleDiv::MediumTick, medLen);
 
897
        sd->setTickLength(QwtScaleDiv::MajorTick, majLen);
 
898
        sd->setPenWidth(penWidth);
 
899
    }
 
900
}
 
901
 
 
902
/*!
 
903
   Find the label for a value
 
904
 
 
905
   \param value Value
 
906
   \return label 
 
907
*/
 
908
QwtText QwtDial::scaleLabel(double value) const
 
909
{
 
910
#if 1
 
911
    if ( value == -0 )
 
912
        value = 0;
 
913
#endif
 
914
 
 
915
    return QString::number(value);
 
916
}
 
917
 
 
918
//! \return Lower limit of the scale arc
 
919
double QwtDial::minScaleArc() const 
 
920
 
921
    return d_data->minScaleArc; 
 
922
}
 
923
 
 
924
//! \return Upper limit of the scale arc
 
925
double QwtDial::maxScaleArc() const 
 
926
 
927
    return d_data->maxScaleArc; 
 
928
}
 
929
 
 
930
/*!
 
931
  \brief Change the origin 
 
932
 
 
933
  The origin is the angle where scale and needle is relative to.
 
934
 
 
935
  \param origin New origin
 
936
  \sa origin()
 
937
*/
 
938
void QwtDial::setOrigin(double origin)
 
939
{
 
940
    d_data->origin = origin;
 
941
    update();
 
942
}
 
943
 
 
944
/*!
 
945
  The origin is the angle where scale and needle is relative to.
 
946
 
 
947
  \return Origin of the dial
 
948
  \sa setOrigin()
 
949
*/
 
950
double QwtDial::origin() const
 
951
{
 
952
    return d_data->origin;
 
953
}
 
954
 
 
955
/*!
 
956
  Change the arc of the scale
 
957
 
 
958
  \param minArc Lower limit
 
959
  \param maxArc Upper limit
 
960
*/
 
961
void QwtDial::setScaleArc(double minArc, double maxArc)
 
962
{
 
963
    if ( minArc != 360.0 && minArc != -360.0 )
 
964
        minArc = fmod(minArc, 360.0);
 
965
    if ( maxArc != 360.0 && maxArc != -360.0 )
 
966
        maxArc = fmod(maxArc, 360.0);
 
967
 
 
968
    d_data->minScaleArc = qwtMin(minArc, maxArc);
 
969
    d_data->maxScaleArc = qwtMax(minArc, maxArc);
 
970
    if ( d_data->maxScaleArc - d_data->minScaleArc > 360.0 )
 
971
        d_data->maxScaleArc = d_data->minScaleArc + 360.0;
 
972
    
 
973
    update();
 
974
}
 
975
 
 
976
//! QwtDoubleRange update hook
 
977
void QwtDial::valueChange()
 
978
{
 
979
    update();
 
980
    QwtAbstractSlider::valueChange();
 
981
}
 
982
 
 
983
/*!
 
984
  \return Size hint
 
985
*/
 
986
QSize QwtDial::sizeHint() const
 
987
{
 
988
    int sh = 0;
 
989
    if ( d_data->scaleDraw )
 
990
        sh = d_data->scaleDraw->extent( QPen(), font() );
 
991
 
 
992
    const int d = 6 * sh + 2 * lineWidth();
 
993
    
 
994
    return QSize( d, d );
 
995
}
 
996
 
 
997
/*! 
 
998
  \brief Return a minimum size hint
 
999
  \warning The return value of QwtDial::minimumSizeHint() depends on the
 
1000
           font and the scale.
 
1001
*/  
 
1002
QSize QwtDial::minimumSizeHint() const
 
1003
{   
 
1004
    int sh = 0;
 
1005
    if ( d_data->scaleDraw )
 
1006
        sh = d_data->scaleDraw->extent(QPen(), font() );
 
1007
 
 
1008
    const int d = 3 * sh + 2 * lineWidth();
 
1009
    
 
1010
    return QSize( d, d );
 
1011
}
 
1012
 
 
1013
static double line2Radians(const QPoint &p1, const QPoint &p2)
 
1014
{
 
1015
    const QPoint p = p2 - p1;
 
1016
 
 
1017
    double angle;
 
1018
    if ( p.x() == 0 )
 
1019
        angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
 
1020
    else
 
1021
    {
 
1022
        angle = atan(double(-p.y()) / double(p.x()));
 
1023
        if ( p.x() < 0 )
 
1024
            angle += M_PI;
 
1025
        if ( angle < 0.0 )
 
1026
            angle += 2 * M_PI;
 
1027
    }
 
1028
    return 360.0 - angle * 180.0 / M_PI;
 
1029
}
 
1030
 
 
1031
/*!
 
1032
  Find the value for a given position
 
1033
 
 
1034
  \param pos Position
 
1035
  \return Value
 
1036
*/
 
1037
double QwtDial::getValue(const QPoint &pos)
 
1038
{
 
1039
    if ( d_data->maxScaleArc == d_data->minScaleArc || maxValue() == minValue() )
 
1040
        return minValue();
 
1041
 
 
1042
    double dir = line2Radians(rect().center(), pos) - d_data->origin;
 
1043
    if ( dir < 0.0 )
 
1044
        dir += 360.0;
 
1045
 
 
1046
    if ( mode() == RotateScale )
 
1047
        dir = 360.0 - dir;
 
1048
 
 
1049
    // The position might be in the area that is outside the scale arc.
 
1050
    // We need the range of the scale if it was a complete circle.
 
1051
 
 
1052
    const double completeCircle = 360.0 / (d_data->maxScaleArc - d_data->minScaleArc) 
 
1053
        * (maxValue() - minValue());
 
1054
 
 
1055
    double posValue = minValue() + completeCircle * dir / 360.0;
 
1056
 
 
1057
    if ( scrollMode() == ScrMouse )
 
1058
    {
 
1059
        if ( d_data->previousDir >= 0.0 ) // valid direction
 
1060
        {
 
1061
            // We have to find out whether the mouse is moving
 
1062
            // clock or counter clockwise
 
1063
 
 
1064
            bool clockWise = false;
 
1065
 
 
1066
            const double angle = dir - d_data->previousDir;
 
1067
            if ( (angle >= 0.0 && angle <= 180.0) || angle < -180.0 )
 
1068
                clockWise = true;
 
1069
 
 
1070
            if ( clockWise )
 
1071
            {
 
1072
                if ( dir < d_data->previousDir && mouseOffset() > 0.0 )
 
1073
                {
 
1074
                    // We passed 360 -> 0
 
1075
                    setMouseOffset(mouseOffset() - completeCircle);
 
1076
                }
 
1077
 
 
1078
                if ( wrapping() )
 
1079
                {
 
1080
                    if ( posValue - mouseOffset() > maxValue() )
 
1081
                    {
 
1082
                        // We passed maxValue and the value will be set
 
1083
                        // to minValue. We have to adjust the mouseOffset.
 
1084
 
 
1085
                        setMouseOffset(posValue - minValue());
 
1086
                    }
 
1087
                }
 
1088
                else
 
1089
                {
 
1090
                    if ( posValue - mouseOffset() > maxValue() ||
 
1091
                        value() == maxValue() )
 
1092
                    {
 
1093
                        // We fix the value at maxValue by adjusting
 
1094
                        // the mouse offset.
 
1095
 
 
1096
                        setMouseOffset(posValue - maxValue());
 
1097
                    }
 
1098
                }
 
1099
            }
 
1100
            else
 
1101
            {
 
1102
                if ( dir > d_data->previousDir && mouseOffset() < 0.0 )
 
1103
                {
 
1104
                    // We passed 0 -> 360 
 
1105
                    setMouseOffset(mouseOffset() + completeCircle);    
 
1106
                }
 
1107
 
 
1108
                if ( wrapping() )
 
1109
                {
 
1110
                    if ( posValue - mouseOffset() < minValue() )
 
1111
                    {
 
1112
                        // We passed minValue and the value will be set
 
1113
                        // to maxValue. We have to adjust the mouseOffset.
 
1114
 
 
1115
                        setMouseOffset(posValue - maxValue());
 
1116
                    }
 
1117
                }
 
1118
                else
 
1119
                {
 
1120
                    if ( posValue - mouseOffset() < minValue() ||
 
1121
                        value() == minValue() )
 
1122
                    {
 
1123
                        // We fix the value at minValue by adjusting
 
1124
                        // the mouse offset.
 
1125
 
 
1126
                        setMouseOffset(posValue - minValue());
 
1127
                    }
 
1128
                }
 
1129
            }
 
1130
        }
 
1131
        d_data->previousDir = dir;
 
1132
    }
 
1133
 
 
1134
    return posValue;
 
1135
}
 
1136
 
 
1137
/*!
 
1138
  \sa QwtAbstractSlider::getScrollMode
 
1139
*/
 
1140
void QwtDial::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
 
1141
{
 
1142
    direction = 0;
 
1143
    scrollMode = ScrNone;
 
1144
 
 
1145
    const QRegion region(contentsRect(), QRegion::Ellipse);
 
1146
    if ( region.contains(p) && p != rect().center() )
 
1147
    {
 
1148
        scrollMode = ScrMouse;
 
1149
        d_data->previousDir = -1.0;
 
1150
    }
 
1151
}
 
1152
 
 
1153
/*! 
 
1154
  Handles key events
 
1155
 
 
1156
  - Key_Down, KeyLeft\n
 
1157
    Decrement by 1
 
1158
  - Key_Prior\n
 
1159
    Decrement by pageSize()
 
1160
  - Key_Home\n
 
1161
    Set the value to minValue()
 
1162
 
 
1163
  - Key_Up, KeyRight\n
 
1164
    Increment by 1
 
1165
  - Key_Next\n
 
1166
    Increment by pageSize()
 
1167
  - Key_End\n
 
1168
    Set the value to maxValue()
 
1169
 
 
1170
  \sa isReadOnly()
 
1171
*/
 
1172
void QwtDial::keyPressEvent(QKeyEvent *e)
 
1173
{
 
1174
    if ( isReadOnly() )
 
1175
    {
 
1176
        e->ignore();
 
1177
        return;
 
1178
    }
 
1179
 
 
1180
    if ( !isValid() )
 
1181
        return;
 
1182
 
 
1183
    double previous = prevValue();
 
1184
    switch ( e->key() )
 
1185
    {
 
1186
        case Qt::Key_Down:
 
1187
        case Qt::Key_Left:
 
1188
            QwtDoubleRange::incValue(-1);
 
1189
            break;
 
1190
#if QT_VERSION < 0x040000
 
1191
        case Qt::Key_Prior:
 
1192
#else
 
1193
        case Qt::Key_PageUp:
 
1194
#endif
 
1195
            QwtDoubleRange::incValue(-pageSize());
 
1196
            break;
 
1197
        case Qt::Key_Home:
 
1198
            setValue(minValue());
 
1199
            break;
 
1200
 
 
1201
        case Qt::Key_Up:
 
1202
        case Qt::Key_Right:
 
1203
            QwtDoubleRange::incValue(1);
 
1204
            break;
 
1205
#if QT_VERSION < 0x040000
 
1206
        case Qt::Key_Next:
 
1207
#else
 
1208
        case Qt::Key_PageDown:
 
1209
#endif
 
1210
            QwtDoubleRange::incValue(pageSize());
 
1211
            break;
 
1212
        case Qt::Key_End:
 
1213
            setValue(maxValue());
 
1214
            break;
 
1215
        default:;
 
1216
            e->ignore();
 
1217
    }
 
1218
 
 
1219
    if (value() != previous)
 
1220
        emit sliderMoved(value());
 
1221
}
 
1222
 
 
1223
/*!
 
1224
   \brief Update the mask of the dial
 
1225
 
 
1226
   In case of "hasVisibleBackground() == false", the backgound is
 
1227
   transparent by a mask.
 
1228
 
 
1229
   \sa showBackground(), hasVisibleBackground()
 
1230
*/
 
1231
void QwtDial::updateMask()
 
1232
{
 
1233
    if ( d_data->visibleBackground )
 
1234
        clearMask();
 
1235
    else
 
1236
        setMask(QRegion(boundingRect(), QRegion::Ellipse));
 
1237
}