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

« back to all changes in this revision

Viewing changes to qwt-5.1.2/src/qwt_knob.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 <qpainter.h>
 
11
#include <qpalette.h>
 
12
#include <qstyle.h>
 
13
#include <qevent.h>
 
14
#include "qwt_round_scale_draw.h"
 
15
#include "qwt_knob.h"
 
16
#include "qwt_math.h"
 
17
#include "qwt_painter.h"
 
18
#include "qwt_paint_buffer.h"
 
19
 
 
20
class QwtKnob::PrivateData
 
21
{
 
22
public:
 
23
    PrivateData()
 
24
    {
 
25
        angle = 0.0;
 
26
        nTurns = 0.0;
 
27
        borderWidth = 2;
 
28
        borderDist = 4;
 
29
        totalAngle = 270.0;
 
30
        scaleDist = 4;
 
31
        symbol = Line;
 
32
        maxScaleTicks = 11;
 
33
        knobWidth = 50;
 
34
        dotWidth = 8;
 
35
    }
 
36
 
 
37
    int borderWidth;
 
38
    int borderDist;
 
39
    int scaleDist;
 
40
    int maxScaleTicks;
 
41
    int knobWidth;
 
42
    int dotWidth;
 
43
 
 
44
    Symbol symbol;
 
45
    double angle;
 
46
    double totalAngle;
 
47
    double nTurns;
 
48
 
 
49
    QRect knobRect; // bounding rect of the knob without scale
 
50
};
 
51
 
 
52
/*!
 
53
  Constructor
 
54
  \param parent Parent widget
 
55
*/
 
56
QwtKnob::QwtKnob(QWidget* parent): 
 
57
    QwtAbstractSlider(Qt::Horizontal, parent)
 
58
{
 
59
    initKnob();
 
60
}
 
61
 
 
62
#if QT_VERSION < 0x040000
 
63
/*!
 
64
  Constructor
 
65
  \param parent Parent widget
 
66
  \param name Object name
 
67
*/
 
68
QwtKnob::QwtKnob(QWidget* parent, const char *name): 
 
69
    QwtAbstractSlider(Qt::Horizontal, parent)
 
70
{
 
71
    setName(name);
 
72
    initKnob();
 
73
}
 
74
#endif
 
75
 
 
76
void QwtKnob::initKnob()
 
77
{
 
78
#if QT_VERSION < 0x040000
 
79
    setWFlags(Qt::WNoAutoErase);
 
80
#endif
 
81
 
 
82
    d_data = new PrivateData;
 
83
 
 
84
    setScaleDraw(new QwtRoundScaleDraw());
 
85
 
 
86
    setUpdateTime(50);
 
87
    setTotalAngle( 270.0 );
 
88
    recalcAngle();
 
89
    setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
 
90
 
 
91
    setRange(0.0, 10.0, 1.0);
 
92
    setValue(0.0);
 
93
}
 
94
 
 
95
//! Destructor
 
96
QwtKnob::~QwtKnob()
 
97
{
 
98
    delete d_data;
 
99
}
 
100
 
 
101
/*!
 
102
  \brief Set the symbol of the knob
 
103
  \sa symbol()
 
104
*/
 
105
void QwtKnob::setSymbol(QwtKnob::Symbol s)
 
106
{
 
107
    if ( d_data->symbol != s )
 
108
    {
 
109
        d_data->symbol = s;
 
110
        update();
 
111
    }
 
112
}
 
113
 
 
114
/*! 
 
115
    \return symbol of the knob
 
116
    \sa setSymbol()
 
117
*/
 
118
QwtKnob::Symbol QwtKnob::symbol() const
 
119
{
 
120
    return d_data->symbol;
 
121
}
 
122
 
 
123
/*!
 
124
  \brief Set the total angle by which the knob can be turned
 
125
  \param angle Angle in degrees.
 
126
 
 
127
  The default angle is 270 degrees. It is possible to specify
 
128
  an angle of more than 360 degrees so that the knob can be
 
129
  turned several times around its axis.
 
130
*/
 
131
void QwtKnob::setTotalAngle (double angle)
 
132
{
 
133
    if (angle < 10.0)
 
134
       d_data->totalAngle = 10.0;
 
135
    else
 
136
       d_data->totalAngle = angle;
 
137
 
 
138
    scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle, 
 
139
        0.5 * d_data->totalAngle);
 
140
    layoutKnob();
 
141
}
 
142
 
 
143
//! Return the total angle
 
144
double QwtKnob::totalAngle() const 
 
145
{
 
146
    return d_data->totalAngle;
 
147
}
 
148
 
 
149
/*!
 
150
   Change the scale draw of the knob
 
151
 
 
152
   For changing the labels of the scales, it
 
153
   is necessary to derive from QwtRoundScaleDraw and
 
154
   overload QwtRoundScaleDraw::label(). 
 
155
 
 
156
   \sa scaleDraw()
 
157
*/
 
158
void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
 
159
{
 
160
    setAbstractScaleDraw(scaleDraw);
 
161
    setTotalAngle(d_data->totalAngle);
 
162
}
 
163
 
 
164
/*! 
 
165
   \return the scale draw of the knob
 
166
   \sa setScaleDraw()
 
167
*/
 
168
const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
 
169
{
 
170
    return (QwtRoundScaleDraw *)abstractScaleDraw();
 
171
}
 
172
 
 
173
/*! 
 
174
   \return the scale draw of the knob
 
175
   \sa setScaleDraw()
 
176
*/
 
177
QwtRoundScaleDraw *QwtKnob::scaleDraw()
 
178
{
 
179
    return (QwtRoundScaleDraw *)abstractScaleDraw();
 
180
}
 
181
 
 
182
/*!
 
183
  \brief Draw the knob
 
184
  \param painter painter
 
185
  \param r Bounding rectangle of the knob (without scale)
 
186
*/
 
187
void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
 
188
{
 
189
#if QT_VERSION < 0x040000
 
190
    const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
 
191
    const QColor buttonTextColor = colorGroup().buttonText();
 
192
    const QColor lightColor = colorGroup().light();
 
193
    const QColor darkColor = colorGroup().dark();
 
194
#else
 
195
    const QBrush buttonBrush = palette().brush(QPalette::Button);
 
196
    const QColor buttonTextColor = palette().color(QPalette::ButtonText);
 
197
    const QColor lightColor = palette().color(QPalette::Light);
 
198
    const QColor darkColor = palette().color(QPalette::Dark);
 
199
#endif
 
200
 
 
201
    const int bw2 = d_data->borderWidth / 2;
 
202
 
 
203
    const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
 
204
 
 
205
    const QRect aRect( 
 
206
        r.center().x() - radius, r.center().y() - radius,
 
207
        2 * radius, 2 * radius);
 
208
 
 
209
    //
 
210
    // draw button face
 
211
    //
 
212
    painter->setBrush(buttonBrush);
 
213
    painter->drawEllipse(aRect);
 
214
 
 
215
    //
 
216
    // draw button shades
 
217
    //
 
218
    QPen pn;
 
219
    pn.setWidth(d_data->borderWidth);
 
220
 
 
221
    pn.setColor(lightColor);
 
222
    painter->setPen(pn);
 
223
    painter->drawArc(aRect, 45*16, 180*16);
 
224
 
 
225
    pn.setColor(darkColor);
 
226
    painter->setPen(pn);
 
227
    painter->drawArc(aRect, 225*16, 180*16);
 
228
 
 
229
    //
 
230
    // draw marker
 
231
    //
 
232
    if ( isValid() )
 
233
        drawMarker(painter, d_data->angle, buttonTextColor);
 
234
}
 
235
 
 
236
/*!
 
237
  \brief Notify change of value
 
238
 
 
239
  Sets the knob's value to the nearest multiple
 
240
  of the step size.
 
241
*/
 
242
void QwtKnob::valueChange()
 
243
{
 
244
    recalcAngle();
 
245
    update();
 
246
    QwtAbstractSlider::valueChange();
 
247
}
 
248
 
 
249
/*!
 
250
  \brief Determine the value corresponding to a specified position
 
251
 
 
252
  Called by QwtAbstractSlider
 
253
  \param p point
 
254
*/
 
255
double QwtKnob::getValue(const QPoint &p)
 
256
{
 
257
    const double dx = double((rect().x() + rect().width() / 2) - p.x() );
 
258
    const double dy = double((rect().y() + rect().height() / 2) - p.y() );
 
259
 
 
260
    const double arc = atan2(-dx,dy) * 180.0 / M_PI;
 
261
 
 
262
    double newValue =  0.5 * (minValue() + maxValue())
 
263
       + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
 
264
      / d_data->totalAngle;
 
265
 
 
266
    const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
 
267
    const double eqValue = value() + mouseOffset();
 
268
 
 
269
    if (fabs(newValue - eqValue) > 0.5 * oneTurn)
 
270
    {
 
271
        if (newValue < eqValue)
 
272
           newValue += oneTurn;
 
273
        else
 
274
           newValue -= oneTurn;
 
275
    }
 
276
 
 
277
    return newValue;    
 
278
}
 
279
 
 
280
/*!
 
281
  \brief Set the scrolling mode and direction
 
282
 
 
283
  Called by QwtAbstractSlider
 
284
  \param p Point in question
 
285
*/
 
286
void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
 
287
{
 
288
    const int r = d_data->knobRect.width() / 2;
 
289
 
 
290
    const int dx = d_data->knobRect.x() + r - p.x();
 
291
    const int dy = d_data->knobRect.y() + r - p.y();
 
292
 
 
293
    if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
 
294
    {
 
295
        scrollMode = ScrMouse;
 
296
        direction = 0;
 
297
    }
 
298
    else                                // point lies outside
 
299
    {
 
300
        scrollMode = ScrTimer;
 
301
        double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
 
302
        if ( arc < d_data->angle)
 
303
           direction = -1;
 
304
        else if (arc > d_data->angle)
 
305
           direction = 1;
 
306
        else
 
307
           direction = 0;
 
308
    }
 
309
}
 
310
 
 
311
 
 
312
/*!
 
313
  \brief Notify a change of the range
 
314
 
 
315
  Called by QwtAbstractSlider
 
316
*/
 
317
void QwtKnob::rangeChange()
 
318
{
 
319
    if (autoScale())
 
320
        rescale(minValue(), maxValue());
 
321
 
 
322
    layoutKnob();
 
323
    recalcAngle();
 
324
}
 
325
 
 
326
/*!
 
327
  \brief Qt Resize Event
 
328
*/
 
329
void QwtKnob::resizeEvent(QResizeEvent *)
 
330
{
 
331
    layoutKnob( false );
 
332
}
 
333
 
 
334
//! Recalculate the knob's geometry and layout based on
 
335
//  the current rect and fonts.
 
336
//  \param update_geometry  notify the layout system and call update
 
337
//         to redraw the scale
 
338
void QwtKnob::layoutKnob( bool update_geometry )
 
339
{
 
340
    const QRect r = rect();
 
341
    const int radius = d_data->knobWidth / 2;
 
342
 
 
343
    d_data->knobRect.setWidth(2 * radius);
 
344
    d_data->knobRect.setHeight(2 * radius);
 
345
    d_data->knobRect.moveCenter(r.center());
 
346
 
 
347
    scaleDraw()->setRadius(radius + d_data->scaleDist);
 
348
    scaleDraw()->moveCenter(r.center());
 
349
 
 
350
    if ( update_geometry )
 
351
    {
 
352
        updateGeometry();
 
353
        update();
 
354
    }
 
355
}
 
356
 
 
357
/*!
 
358
  \brief Repaint the knob
 
359
*/
 
360
void QwtKnob::paintEvent(QPaintEvent *e)
 
361
{
 
362
    const QRect &ur = e->rect();
 
363
    if ( ur.isValid() ) 
 
364
    {
 
365
#if QT_VERSION < 0x040000
 
366
        QwtPaintBuffer paintBuffer(this, ur);
 
367
        draw(paintBuffer.painter(), ur);
 
368
#else
 
369
        QPainter painter(this);
 
370
        painter.setRenderHint(QPainter::Antialiasing);
 
371
        draw(&painter, ur);
 
372
#endif
 
373
    }
 
374
}
 
375
 
 
376
/*!
 
377
  \brief Repaint the knob
 
378
*/
 
379
void QwtKnob::draw(QPainter *painter, const QRect& ur)
 
380
{
 
381
    if ( !d_data->knobRect.contains( ur ) ) // event from valueChange()
 
382
    {
 
383
#if QT_VERSION < 0x040000
 
384
        scaleDraw()->draw( painter, colorGroup() );
 
385
#else
 
386
        scaleDraw()->draw( painter, palette() );
 
387
#endif
 
388
    }
 
389
 
 
390
    drawKnob( painter, d_data->knobRect );
 
391
 
 
392
    if ( hasFocus() )
 
393
        QwtPainter::drawFocusRect(painter, this);
 
394
}
 
395
 
 
396
/*!
 
397
  \brief Draw the marker at the knob's front
 
398
  \param p Painter
 
399
  \param arc Angle of the marker
 
400
  \param c Marker color
 
401
*/
 
402
void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
 
403
{
 
404
    const double rarc = arc * M_PI / 180.0;
 
405
    const double ca = cos(rarc);
 
406
    const double sa = - sin(rarc);
 
407
 
 
408
    int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
 
409
    if (radius < 3) 
 
410
        radius = 3; 
 
411
 
 
412
    const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
 
413
    const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
 
414
 
 
415
    switch (d_data->symbol)
 
416
    {
 
417
        case Dot:
 
418
        {
 
419
            p->setBrush(c);
 
420
            p->setPen(Qt::NoPen);
 
421
 
 
422
            const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
 
423
            p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
 
424
                   ym - qRound(ca * rb) - d_data->dotWidth / 2,
 
425
                   d_data->dotWidth, d_data->dotWidth);
 
426
            break;
 
427
        }
 
428
        case Line:
 
429
        {
 
430
            p->setPen(QPen(c, 2));
 
431
 
 
432
            const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
 
433
            const double re = qwtMax(double(radius - 4), 0.0);
 
434
            
 
435
            p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
 
436
                xm - qRound(sa * re), ym - qRound(ca * re));
 
437
            
 
438
            break;
 
439
        }
 
440
    }
 
441
}
 
442
 
 
443
/*!
 
444
  \brief Change the knob's width.
 
445
 
 
446
  The specified width must be >= 5, or it will be clipped.
 
447
  \param w New width
 
448
*/
 
449
void QwtKnob::setKnobWidth(int w)
 
450
{
 
451
    d_data->knobWidth = qwtMax(w,5);
 
452
    layoutKnob();
 
453
}
 
454
 
 
455
//! Return the width of the knob
 
456
int QwtKnob::knobWidth() const 
 
457
{
 
458
    return d_data->knobWidth;
 
459
}
 
460
 
 
461
/*!
 
462
  \brief Set the knob's border width
 
463
  \param bw new border width
 
464
*/
 
465
void QwtKnob::setBorderWidth(int bw)
 
466
{
 
467
    d_data->borderWidth = qwtMax(bw, 0);
 
468
    layoutKnob();
 
469
}
 
470
 
 
471
//! Return the border width
 
472
int QwtKnob::borderWidth() const 
 
473
{
 
474
    return d_data->borderWidth;
 
475
}
 
476
 
 
477
/*!
 
478
  \brief Recalculate the marker angle corresponding to the
 
479
    current value
 
480
*/
 
481
void QwtKnob::recalcAngle()
 
482
{
 
483
    //
 
484
    // calculate the angle corresponding to the value
 
485
    //
 
486
    if (maxValue() == minValue())
 
487
    {
 
488
        d_data->angle = 0;
 
489
        d_data->nTurns = 0;
 
490
    }
 
491
    else
 
492
    {
 
493
        d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
 
494
            / (maxValue() - minValue()) * d_data->totalAngle;
 
495
        d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
 
496
        d_data->angle = d_data->angle - d_data->nTurns * 360.0;
 
497
    }
 
498
}
 
499
 
 
500
 
 
501
/*!
 
502
    Recalculates the layout
 
503
    \sa layoutKnob()
 
504
*/
 
505
void QwtKnob::scaleChange()
 
506
{
 
507
    layoutKnob();
 
508
}
 
509
 
 
510
/*!
 
511
    Recalculates the layout
 
512
    \sa layoutKnob()
 
513
*/
 
514
void QwtKnob::fontChange(const QFont &f)
 
515
{
 
516
    QwtAbstractSlider::fontChange( f );
 
517
    layoutKnob();
 
518
}
 
519
 
 
520
/*!
 
521
  \return minimumSizeHint()
 
522
*/
 
523
QSize QwtKnob::sizeHint() const
 
524
{
 
525
    return minimumSizeHint();
 
526
}
 
527
 
 
528
/*!
 
529
  \brief Return a minimum size hint
 
530
  \warning The return value of QwtKnob::minimumSizeHint() depends on the 
 
531
           font and the scale.
 
532
*/
 
533
QSize QwtKnob::minimumSizeHint() const
 
534
{
 
535
    // Add the scale radial thickness to the knobWidth
 
536
    const int sh = scaleDraw()->extent( QPen(), font() );
 
537
    const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
 
538
 
 
539
    return QSize( d, d );
 
540
}