~l3on/ubuntu/oneiric/qwt/fix-921430

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2007-10-05 15:20:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20071005152041-qmybqh4fj9jejyo2
Tags: 5.0.2-2
* Handle nostrip build option. (Closes: #437877)
* Build libqwt5-doc package in binary-indep target. (Closes: #443110)

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