~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/widgets/qdial.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
Import upstream version 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the widgets module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qdial.h"
 
30
 
 
31
#ifndef QT_NO_DIAL
 
32
 
 
33
#include <qapplication.h>
 
34
#include <qbitmap.h>
 
35
#include <qcolor.h>
 
36
#include <qevent.h>
 
37
#include <qpainter.h>
 
38
#include <qpolygon.h>
 
39
#include <qregion.h>
 
40
#include <qstyle.h>
 
41
#include <qstylepainter.h>
 
42
#include <qstyleoption.h>
 
43
#include <qslider.h>
 
44
#include <private/qabstractslider_p.h>
 
45
#include <private/qmath_p.h>
 
46
#ifndef QT_NO_ACCESSIBILITY
 
47
#include "qaccessible.h"
 
48
#endif
 
49
 
 
50
class QDialPrivate : public QAbstractSliderPrivate
 
51
{
 
52
    Q_DECLARE_PUBLIC(QDial)
 
53
public:
 
54
    QDialPrivate()
 
55
    {
 
56
        wrapping = false;
 
57
        tracking = true;
 
58
        doNotEmit = false;
 
59
        target = 3.7;
 
60
    }
 
61
 
 
62
    qreal target;
 
63
    uint showNotches : 1;
 
64
    uint wrapping : 1;
 
65
    uint doNotEmit : 1;
 
66
 
 
67
    int valueFromPoint(const QPoint &) const;
 
68
    double angle(const QPoint &, const QPoint &) const;
 
69
    void init();
 
70
    QStyleOptionSlider getStyleOption() const;
 
71
};
 
72
 
 
73
void QDialPrivate::init()
 
74
{
 
75
    Q_Q(QDial);
 
76
    showNotches = false;
 
77
    q->setFocusPolicy(Qt::WheelFocus);
 
78
#ifdef QT3_SUPPORT
 
79
    QObject::connect(q, SIGNAL(sliderPressed()), q, SIGNAL(dialPressed()));
 
80
    QObject::connect(q, SIGNAL(sliderMoved(int)), q, SIGNAL(dialMoved(int)));
 
81
    QObject::connect(q, SIGNAL(sliderReleased()), q, SIGNAL(dialReleased()));
 
82
#endif
 
83
}
 
84
 
 
85
QStyleOptionSlider QDialPrivate::getStyleOption() const
 
86
{
 
87
    Q_Q(const QDial);
 
88
    QStyleOptionSlider opt;
 
89
    opt.init(q);
 
90
    opt.minimum = minimum;
 
91
    opt.maximum = maximum;
 
92
    opt.sliderPosition = position;
 
93
    opt.sliderValue = value;
 
94
    opt.singleStep = singleStep;
 
95
    opt.pageStep = pageStep;
 
96
    opt.upsideDown = !invertedAppearance;
 
97
    opt.notchTarget = target;
 
98
    opt.dialWrapping = wrapping;
 
99
    opt.subControls = QStyle::SC_All;
 
100
    opt.activeSubControls = QStyle::SC_None;
 
101
    if (!showNotches) {
 
102
        opt.subControls &= ~QStyle::SC_DialTickmarks;
 
103
        opt.tickPosition = QSlider::TicksAbove;
 
104
        opt.tickInterval = q->notchSize();
 
105
    } else {
 
106
        opt.tickPosition = QSlider::NoTicks;
 
107
        opt.tickInterval = 0;
 
108
    }
 
109
    return opt;
 
110
}
 
111
 
 
112
int QDialPrivate::valueFromPoint(const QPoint &p) const
 
113
{
 
114
    Q_Q(const QDial);
 
115
    double yy = (double)q->height()/2.0 - p.y();
 
116
    double xx = (double)p.x() - q->width()/2.0;
 
117
    double a = (xx || yy) ? atan2(yy, xx) : 0;
 
118
 
 
119
    if (a < Q_PI / -2)
 
120
        a = a + Q_PI * 2;
 
121
 
 
122
    int dist = 0;
 
123
    int minv = minimum, maxv = maximum;
 
124
 
 
125
    if (minimum < 0) {
 
126
        dist = -minimum;
 
127
        minv = 0;
 
128
        maxv = maximum + dist;
 
129
    }
 
130
 
 
131
    int r = maxv - minv;
 
132
    int v;
 
133
    if (wrapping)
 
134
        v =  (int)(0.5 + minv + r * (Q_PI * 3 / 2 - a) / (2 * Q_PI));
 
135
    else
 
136
        v =  (int)(0.5 + minv + r* (Q_PI * 4 / 3 - a) / (Q_PI * 10 / 6));
 
137
 
 
138
    if (dist > 0)
 
139
        v -= dist;
 
140
 
 
141
    return bound(v);
 
142
}
 
143
 
 
144
/*!
 
145
    \class QDial qdial.h
 
146
 
 
147
    \brief The QDial class provides a rounded range control (like a speedometer or potentiometer).
 
148
 
 
149
    \ingroup basic
 
150
    \mainclass
 
151
 
 
152
    QDial is used when the user needs to control a value within a
 
153
    program-definable range, and the range either wraps around
 
154
    (typically, 0..359 degrees) or the dialog layout needs a square
 
155
    widget.
 
156
 
 
157
    Both API- and UI-wise, the dial is very similar to a \link QSlider
 
158
    slider. \endlink Indeed, when wrapping() is false (the default)
 
159
    there is no real difference between a slider and a dial. They
 
160
    have the same signals, slots and member functions, all of which do
 
161
    the same things. Which one you use depends only on your taste
 
162
    and on the application.
 
163
 
 
164
    The dial initially emits valueChanged() signals continuously while
 
165
    the slider is being moved; you can make it emit the signal less
 
166
    often by calling setTracking(false). dialMoved() is emitted
 
167
    continuously even when tracking() is false.
 
168
 
 
169
    The slider also emits dialPressed() and dialReleased() signals
 
170
    when the mouse button is pressed and released. But note that the
 
171
    dial's value can change without these signals being emitted; the
 
172
    keyboard and wheel can be used to change the value.
 
173
 
 
174
    Unlike the slider, QDial attempts to draw a "nice" number of
 
175
    notches rather than one per lineStep(). If possible, the number
 
176
    of notches drawn is one per lineStep(), but if there aren't enough
 
177
    pixels to draw every one, QDial will draw every second, third
 
178
    etc., notch. notchSize() returns the number of units per notch,
 
179
    hopefully a multiple of lineStep(); setNotchTarget() sets the
 
180
    target distance between neighbouring notches in pixels. The
 
181
    default is 3.75 pixels.
 
182
 
 
183
    Like the slider, the dial makes the QAbstractSlider functions
 
184
    setValue(), addLine(), subtractLine(), addPage() and
 
185
    subtractPage() available as slots.
 
186
 
 
187
    The dial's keyboard interface is fairly simple: The left/up and
 
188
    right/down arrow keys move by lineStep(), page up and page down by
 
189
    pageStep() and Home and End to minValue() and maxValue().
 
190
 
 
191
    \inlineimage qdial-m.png Screenshot in Motif style
 
192
    \inlineimage qdial-w.png Screenshot in Windows style
 
193
 
 
194
    \sa QScrollBar, QSpinBox, {fowler}{GUI Design Handbook: Slider}
 
195
*/
 
196
 
 
197
/*!
 
198
    Constructs a dial.
 
199
 
 
200
    The \a parent argument is sent to the QAbstractSlider constructor.
 
201
*/
 
202
QDial::QDial(QWidget *parent)
 
203
    : QAbstractSlider(*new QDialPrivate, parent)
 
204
{
 
205
    Q_D(QDial);
 
206
    d->init();
 
207
}
 
208
 
 
209
#ifdef QT3_SUPPORT
 
210
/*!
 
211
    Use one of the constructors that doesn't take the \a name
 
212
    argument and then use setObjectName() instead.
 
213
*/
 
214
QDial::QDial(QWidget *parent, const char *name)
 
215
    : QAbstractSlider(*new QDialPrivate, parent)
 
216
{
 
217
    Q_D(QDial);
 
218
    setObjectName(name);
 
219
    d->init();
 
220
}
 
221
 
 
222
/*!
 
223
    Use one of the constructors that doesn't take the \a name
 
224
    argument and then use setObjectName() instead.
 
225
*/
 
226
QDial::QDial(int minValue, int maxValue, int pageStep, int value,
 
227
              QWidget *parent, const char *name)
 
228
    : QAbstractSlider(*new QDialPrivate, parent)
 
229
{
 
230
    Q_D(QDial);
 
231
    setObjectName(name);
 
232
    d->minimum = minValue;
 
233
    d->maximum = maxValue;
 
234
    d->pageStep = pageStep;
 
235
    d->position = d->value = value;
 
236
    d->init();
 
237
}
 
238
#endif
 
239
/*!
 
240
    Destroys the dial.
 
241
*/
 
242
QDial::~QDial()
 
243
{
 
244
}
 
245
 
 
246
/*! \reimp */
 
247
void QDial::resizeEvent(QResizeEvent *e)
 
248
{
 
249
    QWidget::resizeEvent(e);
 
250
}
 
251
 
 
252
/*!
 
253
  \reimp
 
254
*/
 
255
 
 
256
void QDial::paintEvent(QPaintEvent *)
 
257
{
 
258
    Q_D(QDial);
 
259
    QStylePainter p(this);
 
260
    p.drawComplexControl(QStyle::CC_Dial, d->getStyleOption());
 
261
}
 
262
 
 
263
/*!
 
264
  \reimp
 
265
*/
 
266
 
 
267
void QDial::mousePressEvent(QMouseEvent *e)
 
268
{
 
269
    Q_D(QDial);
 
270
    if (d->maximum == d->minimum ||
 
271
        (e->button() != Qt::LeftButton)  ||
 
272
        (e->buttons() ^ e->button())) {
 
273
        e->ignore();
 
274
        return;
 
275
    }
 
276
    e->accept();
 
277
    setSliderPosition(d->valueFromPoint(e->pos()));
 
278
    emit sliderPressed();
 
279
}
 
280
 
 
281
 
 
282
/*!
 
283
  \reimp
 
284
*/
 
285
 
 
286
void QDial::mouseReleaseEvent(QMouseEvent * e)
 
287
{
 
288
    Q_D(QDial);
 
289
    if (e->buttons() ^ e->button()) {
 
290
        e->ignore();
 
291
        return;
 
292
    }
 
293
    e->accept();
 
294
    setValue(d->valueFromPoint(e->pos()));
 
295
    emit sliderReleased();
 
296
}
 
297
 
 
298
 
 
299
/*!
 
300
  \reimp
 
301
*/
 
302
 
 
303
void QDial::mouseMoveEvent(QMouseEvent * e)
 
304
{
 
305
    Q_D(QDial);
 
306
    if (!d->tracking || !(e->buttons() & Qt::LeftButton)) {
 
307
        e->ignore();
 
308
        return;
 
309
    }
 
310
    e->accept();
 
311
    d->doNotEmit = true;
 
312
    setSliderPosition(d->valueFromPoint(e->pos()));
 
313
    emit sliderMoved(d->value);
 
314
    d->doNotEmit = false;
 
315
}
 
316
 
 
317
 
 
318
/*!
 
319
    \reimp
 
320
 
 
321
    Reimplemented to ensure the display is correct and to emit the
 
322
    valueChanged(int) signal when appropriate and to ensure
 
323
    tickmarks are consistent with the new range. The \a change
 
324
    parameter indicates what type of change that has taken place.
 
325
*/
 
326
 
 
327
void QDial::sliderChange(SliderChange change)
 
328
{
 
329
    Q_D(QDial);
 
330
    if (change == SliderRangeChange || change == SliderValueChange) {
 
331
        update();
 
332
        if (change == SliderValueChange && (d->tracking || !d->doNotEmit)) {
 
333
            emit valueChanged(d->value);
 
334
#ifndef QT_NO_ACCESSIBILITY
 
335
            QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged);
 
336
#endif
 
337
        }
 
338
    }
 
339
}
 
340
 
 
341
void QDial::setWrapping(bool enable)
 
342
{
 
343
    Q_D(QDial);
 
344
    if (d->wrapping == enable)
 
345
        return;
 
346
    d->wrapping = enable;
 
347
    update();
 
348
}
 
349
 
 
350
 
 
351
/*!
 
352
    \property QDial::wrapping
 
353
    \brief whether wrapping is enabled
 
354
 
 
355
    If true, wrapping is enabled. This means that the arrow can be
 
356
    turned around 360�. Otherwise there is some space at the bottom of
 
357
    the dial which is skipped by the arrow.
 
358
 
 
359
    This property's default is false.
 
360
*/
 
361
 
 
362
bool QDial::wrapping() const
 
363
{
 
364
    Q_D(const QDial);
 
365
    return d->wrapping;
 
366
}
 
367
 
 
368
 
 
369
/*!
 
370
    \property QDial::notchSize
 
371
    \brief the current notch size
 
372
 
 
373
    The notch size is in range control units, not pixels, and if
 
374
    possible it is a multiple of lineStep() that results in an
 
375
    on-screen notch size near notchTarget().
 
376
 
 
377
    \sa notchTarget() lineStep()
 
378
*/
 
379
 
 
380
int QDial::notchSize() const
 
381
{
 
382
    Q_D(const QDial);
 
383
    // radius of the arc
 
384
    int r = qMin(width(), height())/2;
 
385
    // length of the whole arc
 
386
    int l = (int)(r * (d->wrapping ? 6 : 5) * Q_PI / 6);
 
387
    // length of the arc from minValue() to minValue()+pageStep()
 
388
    if (d->maximum > d->minimum + d->pageStep)
 
389
        l = (int)(0.5 + l * d->pageStep / (d->maximum - d->minimum));
 
390
    // length of a singleStep arc
 
391
    l = l * d->singleStep / d->pageStep;
 
392
    if (l < 1)
 
393
        l = 1;
 
394
    // how many times singleStep can be draw in d->target pixels
 
395
    l = (int)(0.5 + d->target / l);
 
396
    // we want notchSize() to be a non-zero multiple of lineStep()
 
397
    if (!l)
 
398
        l = 1;
 
399
    return d->singleStep * l;
 
400
}
 
401
 
 
402
void QDial::setNotchTarget(double target)
 
403
{
 
404
    Q_D(QDial);
 
405
    d->target = target;
 
406
    update();
 
407
}
 
408
 
 
409
/*!
 
410
    \property QDial::notchTarget
 
411
    \brief the target number of pixels between notches
 
412
 
 
413
    The notch target is the number of pixels QDial attempts to put
 
414
    between each notch.
 
415
 
 
416
    The actual size may differ from the target size.
 
417
*/
 
418
qreal QDial::notchTarget() const
 
419
{
 
420
    Q_D(const QDial);
 
421
    return d->target;
 
422
}
 
423
 
 
424
 
 
425
void QDial::setNotchesVisible(bool visible)
 
426
{
 
427
    // d->showNotches = visible;
 
428
    // update();
 
429
    // ### fix after beta2
 
430
    Q_UNUSED(visible);
 
431
}
 
432
 
 
433
/*!
 
434
    \property QDial::notchesVisible
 
435
    \brief whether the notches are shown
 
436
 
 
437
    If true, the notches are shown. If false (the default) notches are
 
438
    not shown.
 
439
*/
 
440
bool QDial::notchesVisible() const
 
441
{
 
442
    Q_D(const QDial);
 
443
    return d->showNotches;
 
444
}
 
445
 
 
446
/*!
 
447
  \reimp
 
448
*/
 
449
 
 
450
QSize QDial::minimumSizeHint() const
 
451
{
 
452
    return QSize(50, 50);
 
453
}
 
454
 
 
455
/*!
 
456
  \reimp
 
457
*/
 
458
 
 
459
QSize QDial::sizeHint() const
 
460
{
 
461
    return QSize(100, 100).expandedTo(QApplication::globalStrut());
 
462
}
 
463
 
 
464
/*!
 
465
    \fn void QDial::dialPressed();
 
466
 
 
467
    Use QAbstractSlider::sliderPressed() instead.
 
468
*/
 
469
 
 
470
/*!
 
471
    \fn void QDial::dialMoved(int value);
 
472
 
 
473
    Use QAbstractSlider::sliderMoved() instead.
 
474
*/
 
475
 
 
476
/*!
 
477
    \fn void QDial::dialReleased();
 
478
 
 
479
    Use QAbstractSlider::sliderReleased() instead.
 
480
*/
 
481
 
 
482
 
 
483
#endif // QT_FEATURE_DIAL