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

« back to all changes in this revision

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