source: trunk/src/widgets/qdial.cpp@ 174

Last change on this file since 174 was 174, checked in by dmik, 18 years ago

Styles: Implemented the first version of the Warp4 style (contributed by Cornelis Bockemuehl).

  • Property svn:keywords set to Id
File size: 25.4 KB
Line 
1/****************************************************************************
2** $Id: qdial.cpp 174 2007-11-06 22:27:57Z dmik $
3**
4** Implementation of the dial widget
5**
6** Created : 979899
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qdial.h"
39
40#ifndef QT_NO_DIAL
41
42#include "qpainter.h"
43#include "qpointarray.h"
44#include "qcolor.h"
45#include "qapplication.h"
46#include "qregion.h"
47#include "qbitmap.h"
48#include "qstyle.h"
49#if defined(QT_ACCESSIBILITY_SUPPORT)
50#include "qaccessible.h"
51#endif
52
53#include <math.h> // sin(), cos(), atan()
54//### Forutsetter linking med math lib - Jfr kommentar i qpainter_x11.cpp!
55
56static const double m_pi = 3.14159265358979323846;
57static const double rad_factor = 180.0 / m_pi;
58
59
60class QDialPrivate
61{
62public:
63 QDialPrivate()
64 {
65 wrapping = FALSE;
66 tracking = TRUE;
67 doNotEmit = FALSE;
68 target = 3.7;
69 mousePressed = FALSE;
70 }
71
72 bool wrapping;
73 bool tracking;
74 bool doNotEmit;
75 double target;
76 QRect eraseArea;
77 bool eraseAreaValid;
78 bool showNotches;
79 bool onlyOutside;
80 bool mousePressed;
81
82 QPointArray lines;
83};
84
85
86/*!
87 \class QDial qdial.h
88
89 \brief The QDial class provides a rounded range control (like a speedometer or potentiometer).
90
91 \ingroup basic
92 \mainclass
93
94 QDial is used when the user needs to control a value within a
95 program-definable range, and the range either wraps around
96 (typically, 0..359 degrees) or the dialog layout needs a square
97 widget.
98
99 Both API- and UI-wise, the dial is very similar to a \link QSlider
100 slider. \endlink Indeed, when wrapping() is FALSE (the default)
101 there is no real difference between a slider and a dial. They
102 have the same signals, slots and member functions, all of which do
103 the same things. Which one you use depends only on your taste
104 and on the application.
105
106 The dial initially emits valueChanged() signals continuously while
107 the slider is being moved; you can make it emit the signal less
108 often by calling setTracking(FALSE). dialMoved() is emitted
109 continuously even when tracking() is FALSE.
110
111 The slider also emits dialPressed() and dialReleased() signals
112 when the mouse button is pressed and released. But note that the
113 dial's value can change without these signals being emitted; the
114 keyboard and wheel can be used to change the value.
115
116 Unlike the slider, QDial attempts to draw a "nice" number of
117 notches rather than one per lineStep(). If possible, the number
118 of notches drawn is one per lineStep(), but if there aren't enough
119 pixels to draw every one, QDial will draw every second, third
120 etc., notch. notchSize() returns the number of units per notch,
121 hopefully a multiple of lineStep(); setNotchTarget() sets the
122 target distance between neighbouring notches in pixels. The
123 default is 3.75 pixels.
124
125 Like the slider, the dial makes the QRangeControl functions
126 setValue(), addLine(), subtractLine(), addPage() and
127 subtractPage() available as slots.
128
129 The dial's keyboard interface is fairly simple: The left/up and
130 right/down arrow keys move by lineStep(), page up and page down by
131 pageStep() and Home and End to minValue() and maxValue().
132
133 <img src=qdial-m.png> <img src=qdial-w.png>
134
135 \sa QScrollBar QSpinBox
136 \link guibooks.html#fowler GUI Design Handbook: Slider\endlink
137*/
138
139
140
141
142/*!
143 Constructs a dial called \a name with parent \a parent. \a f is
144 propagated to the QWidget constructor. It has the default range of
145 a QRangeControl.
146*/
147
148QDial::QDial( QWidget *parent, const char *name, WFlags f )
149 : QWidget( parent, name, f | WNoAutoErase ), QRangeControl()
150{
151 d = new QDialPrivate;
152 d->eraseAreaValid = FALSE;
153 d->showNotches = FALSE;
154 d->onlyOutside = FALSE;
155 setFocusPolicy( QWidget::WheelFocus );
156}
157
158
159
160/*!
161 Constructs a dial called \a name with parent \a parent. The dial's
162 value can never be smaller than \a minValue or greater than \a
163 maxValue. Its page step size is \a pageStep, and its initial value
164 is \a value.
165
166 \a value is forced to be within the legal range.
167*/
168
169QDial::QDial( int minValue, int maxValue, int pageStep, int value,
170 QWidget *parent, const char *name )
171 : QWidget( parent, name, WNoAutoErase ),
172 QRangeControl( minValue, maxValue, 1, pageStep, value )
173{
174 d = new QDialPrivate;
175 d->eraseAreaValid = FALSE;
176 d->showNotches = FALSE;
177 d->onlyOutside = FALSE;
178 setFocusPolicy( QWidget::WheelFocus );
179}
180
181/*!
182 Destroys the dial.
183*/
184QDial::~QDial()
185{
186 delete d;
187}
188
189
190void QDial::setTracking( bool enable )
191{
192 d->tracking = enable;
193}
194
195
196/*!
197 \property QDial::tracking
198 \brief whether tracking is enabled
199
200 If TRUE (the default), tracking is enabled. This means that the
201 arrow can be moved using the mouse; otherwise the arrow cannot be
202 moved with the mouse.
203*/
204
205bool QDial::tracking() const
206{
207 return d ? d->tracking : TRUE;
208}
209
210void QDial::setValue( int newValue )
211{ // ### set doNotEmit? Matthias?
212 QRangeControl::setValue( newValue );
213}
214
215
216/*!
217 Increments the dial's value() by one lineStep().
218*/
219
220void QDial::addLine()
221{
222 QRangeControl::addLine();
223}
224
225
226/*!
227 Decrements the dial's value() by one lineStep().
228*/
229
230void QDial::subtractLine()
231{
232 QRangeControl::subtractLine();
233}
234
235
236/*! \reimp */
237
238void QDial::resizeEvent( QResizeEvent * e )
239{
240 d->lines.resize( 0 );
241 QWidget::resizeEvent( e );
242}
243
244
245/*!
246 \reimp
247*/
248
249void QDial::paintEvent( QPaintEvent * e )
250{
251 repaintScreen( &e->rect() );
252}
253
254/*!
255 Paints the dial using clip region \a cr.
256*/
257
258void QDial::repaintScreen( const QRect *cr )
259{
260 QPainter p;
261 p.begin( this );
262
263 // note: drawing dial controls is NOT AT ALL using the QStyle drawing
264 // concept, so we have to draw the Warp4 dial here explicitly in
265 // the widget code!
266 if ( style().styleHint( QStyle::SH_GUIStyle ) == QStyle::PMStyle ) {
267 QRect rr(rect());
268
269 // erase the background
270 QBrush br( paletteBackgroundColor() );
271 p.setPen( QPen::NoPen );
272 p.fillRect( rr, br );
273
274 // centered quadratic rectangle
275 if ( rr.width() > rr.height() ) {
276 rr.setWidth( rr.height() );
277 rr.moveBy( (width() - rr.width()) / 2, 0 );
278 } else {
279 rr.setHeight( rr.width() );
280 rr.moveBy( 0, (height() - rr.height()) / 2 );
281 }
282
283 // draw the ticks ("notches")
284 if ( d->showNotches ) {
285 calcLines();
286 p.setPen( colorGroup().foreground() );
287 p.drawLineSegments( d->lines );
288 }
289
290 // draw dial (circle with shadow)
291 int bigLineSize = calcBigLineSize();
292 int dist = 6;
293 rr.setLeft( rr.left() + bigLineSize + dist );
294 rr.setTop( rr.top() + bigLineSize + dist );
295 rr.setRight( rr.right() - bigLineSize - dist );
296 rr.setBottom( rr.bottom() - bigLineSize - dist );
297 p.setPen( QPen( colorGroup().shadow(), 2) );
298 p.drawEllipse( rr );
299 rr.setLeft( rr.left() + 2 );
300 rr.setTop( rr.top() + 2 );
301 rr.setRight( rr.right() - 2 );
302 rr.setBottom( rr.bottom() - 2 );
303 QPointArray pa;
304 pa.putPoints( 0, 3,
305 rr.left() - 2, rr.top() - 2,
306 rr.right() + 2, rr.top() - 2,
307 rr.left() - 2, rr.bottom() + 2 );
308 p.setClipRegion( QRegion( pa ) );
309 p.setPen( QPen( colorGroup().light(), 2 ) );
310 p.drawEllipse( rr );
311 pa.resize( 0 );
312 pa.putPoints( 0, 3,
313 rr.right() + 2, rr.top() - 2,
314 rr.right() + 2, rr.bottom() + 2,
315 rr.left() - 2, rr.bottom() + 2 );
316 p.setClipRegion( QRegion( pa ) );
317 p.setPen( QPen( colorGroup().dark(), 2 ) );
318 p.drawEllipse( rr );
319 p.setClipping( false );
320
321 // draw pointer (triangle)
322 double a;
323 calcArrow( a );
324 double s = sin( a ),
325 c = cos( a );
326 int r = rr.width() / 2 - 9;
327 double xtr = ((double)rr.left() + rr.right()) * .5 + r * c,
328 ytr = ((double)rr.top() + rr.bottom()) * .5 - r * s;
329 QPointArray ar;
330 ar.putPoints( 0, 3,
331 (int)(xtr + 3.5 * c), (int)(ytr - 3.5 * s),
332 (int)(xtr + 4 * cos(a - 2.0944)), (int)(ytr - 4 * sin(a - 2.0944)),
333 (int)(xtr + 4 * cos(a + 2.0944)), (int)(ytr - 4 * sin(a + 2.0944)) );
334 p.setBrush( colorGroup().foreground() );
335 p.setPen( QPen::NoPen );
336 p.drawPolygon( ar );
337
338 if( hasFocus() )
339 style().drawPrimitive( QStyle::PE_FocusRect, &p, rect(), colorGroup() );
340 }
341
342 // all non-PM styles
343 else
344 {
345 bool resetClipping = FALSE;
346
347 // calculate clip-region for erasing background
348 if ( cr ) {
349 p.setClipRect( *cr );
350 } else if ( !d->onlyOutside && d->eraseAreaValid ) {
351 QRegion reg = d->eraseArea;
352 double a;
353 reg = reg.subtract( calcArrow( a ) );
354 p.setClipRegion( reg );
355 resetClipping = TRUE;
356 }
357
358 QRect br( calcDial() );
359 p.setPen( NoPen );
360 // if ( style() == MotifStyle )
361 // p.setBrush( colorGroup().brush( QColorGroup::Mid ) );
362 // else {
363 QBrush b;
364 if ( colorGroup().brush( QColorGroup::Light ).pixmap() )
365 b = QBrush( colorGroup().brush( QColorGroup::Light ) );
366 else
367 b = QBrush( colorGroup().light(), Dense4Pattern );
368 p.setBrush( b );
369 p.setBackgroundMode( OpaqueMode );
370 // }
371
372 QRect te = br;
373 te.setWidth(te.width()+2);
374 te.setHeight(te.height()+2);
375 // erase background of dial
376 if ( !d->onlyOutside ) {
377 p.drawEllipse( te );
378 }
379
380 // erase remaining space around the dial
381 QRegion remaining( 0, 0, width(), height() );
382 remaining = remaining.subtract( QRegion( te, QRegion::Ellipse ) );
383 if ( p.hasClipping() )
384 remaining = remaining.intersect( p.clipRegion() );
385 erase(remaining);
386
387 if ( resetClipping ) {
388 if ( cr )
389 p.setClipRect( *cr );
390 else
391 p.setClipRect( QRect( 0, 0, width(), height() ) );
392 }
393
394 // draw notches
395 if ( d->showNotches ) {
396 calcLines();
397 p.setPen( colorGroup().foreground() );
398 p.drawLineSegments( d->lines );
399 }
400
401 // calculate and paint arrow
402 p.setPen( QPen( colorGroup().dark() ) );
403 p.drawArc( te, 60 * 16, 180 * 16 );
404 p.setPen( QPen( colorGroup().light() ) );
405 p.drawArc( te, 240 * 16, 180 * 16 );
406
407 double a;
408 QPointArray arrow( calcArrow( a ) );
409 QRect ea( arrow.boundingRect() );
410 d->eraseArea = ea;
411 d->eraseAreaValid = TRUE;
412
413 p.setPen( NoPen );
414 p.setBrush( colorGroup().brush( QColorGroup::Button ) );
415 if ( !d->onlyOutside )
416 p.drawPolygon( arrow );
417
418 a = angle( QPoint( width() / 2, height() / 2 ), arrow[ 0 ] );
419 p.setBrush( Qt::NoBrush );
420
421 // that's still a hack...
422 if ( a <= 0 || a > 200 ) {
423 p.setPen( colorGroup().light() );
424 p.drawLine( arrow[ 2 ], arrow[ 0 ] );
425 p.drawLine( arrow[ 1 ], arrow[ 2 ] );
426 p.setPen( colorGroup().dark() );
427 p.drawLine( arrow[ 0 ], arrow[ 1 ] );
428 } else if ( a > 0 && a < 45 ) {
429 p.setPen( colorGroup().light() );
430 p.drawLine( arrow[ 2 ], arrow[ 0 ] );
431 p.setPen( colorGroup().dark() );
432 p.drawLine( arrow[ 1 ], arrow[ 2 ] );
433 p.drawLine( arrow[ 0 ], arrow[ 1 ] );
434 } else if ( a >= 45 && a < 135 ) {
435 p.setPen( colorGroup().dark() );
436 p.drawLine( arrow[ 2 ], arrow[ 0 ] );
437 p.drawLine( arrow[ 1 ], arrow[ 2 ] );
438 p.setPen( colorGroup().light() );
439 p.drawLine( arrow[ 0 ], arrow[ 1 ] );
440 } else if ( a >= 135 && a < 200 ) {
441 p.setPen( colorGroup().dark() );
442 p.drawLine( arrow[ 2 ], arrow[ 0 ] );
443 p.setPen( colorGroup().light() );
444 p.drawLine( arrow[ 0 ], arrow[ 1 ] );
445 p.drawLine( arrow[ 1 ], arrow[ 2 ] );
446 }
447
448 // draw focus rect around the dial
449 if ( hasFocus() ) {
450 p.setClipping( FALSE );
451 br.setWidth( br.width() + 2 );
452 br.setHeight( br.height() + 2 );
453 if ( d->showNotches ) {
454 int r = QMIN( width(), height() ) / 2;
455 br.moveBy( -r / 6, - r / 6 );
456 br.setWidth( br.width() + r / 3 );
457 br.setHeight( br.height() + r / 3 );
458 }
459 // strange, but else we get redraw errors on Windows
460 p.end();
461 p.begin( this );
462 p.save();
463 p.setPen( QPen( colorGroup().background() ) );
464 p.setBrush( NoBrush );
465 p.drawRect( br );
466 p.restore();
467 style().drawPrimitive( QStyle::PE_FocusRect, &p, br, colorGroup());
468 }
469 }
470
471 p.end();
472}
473
474
475/*!
476 \reimp
477*/
478
479void QDial::keyPressEvent( QKeyEvent * e )
480{
481 switch ( e->key() ) {
482 case Key_Left: case Key_Down:
483 subtractLine();
484 break;
485 case Key_Right: case Key_Up:
486 addLine();
487 break;
488 case Key_Prior:
489 subtractPage();
490 break;
491 case Key_Next:
492 addPage();
493 break;
494 case Key_Home:
495 setValue( minValue() );
496 break;
497 case Key_End:
498 setValue( maxValue() );
499 break;
500 default:
501 e->ignore();
502 break;
503 }
504}
505
506
507/*!
508 \reimp
509*/
510
511void QDial::mousePressEvent( QMouseEvent * e )
512{
513 d->mousePressed = TRUE;
514 setValue( valueFromPoint( e->pos() ) );
515 emit dialPressed();
516}
517
518
519/*!
520 \reimp
521*/
522
523void QDial::mouseReleaseEvent( QMouseEvent * e )
524{
525 d->mousePressed = FALSE;
526 setValue( valueFromPoint( e->pos() ) );
527 emit dialReleased();
528}
529
530
531/*!
532 \reimp
533*/
534
535void QDial::mouseMoveEvent( QMouseEvent * e )
536{
537 if ( !d->mousePressed )
538 return;
539 if ( !d->tracking || (e->state() & LeftButton) == 0 )
540 return;
541 d->doNotEmit = TRUE;
542 setValue( valueFromPoint( e->pos() ) );
543 emit dialMoved( value() );
544 d->doNotEmit = FALSE;
545}
546
547
548/*!
549 \reimp
550*/
551#ifndef QT_NO_WHEELEVENT
552void QDial::wheelEvent( QWheelEvent *e )
553{
554 setValue( value() - e->delta() / 120 );
555}
556#endif
557
558/*!
559 \reimp
560*/
561
562void QDial::focusInEvent( QFocusEvent * )
563{
564 d->onlyOutside = TRUE;
565 repaintScreen();
566 d->onlyOutside = FALSE;
567}
568
569
570/*!
571 \reimp
572*/
573
574void QDial::focusOutEvent( QFocusEvent * )
575{
576 d->onlyOutside = TRUE;
577 repaintScreen();
578 d->onlyOutside = FALSE;
579}
580
581/*!
582 Reimplemented to ensure the display is correct and to emit the
583 valueChanged(int) signal when appropriate.
584*/
585
586void QDial::valueChange()
587{
588 d->lines.resize( 0 );
589 repaintScreen();
590 if ( d->tracking || !d->doNotEmit ) {
591 emit valueChanged( value() );
592#if defined(QT_ACCESSIBILITY_SUPPORT)
593 QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
594#endif
595 }
596}
597
598
599/*!
600 Reimplemented to ensure tick-marks are consistent with the new range.
601*/
602
603void QDial::rangeChange()
604{
605 d->lines.resize( 0 );
606 repaintScreen();
607}
608
609
610/*!
611 \internal
612*/
613
614int QDial::valueFromPoint( const QPoint & p ) const
615{
616 double a = atan2( (double)height()/2.0 - p.y(),
617 (double)p.x() - width()/2.0 );
618 if ( a < m_pi/-2 )
619 a = a + m_pi*2;
620
621 int dist = 0;
622 int minv = minValue(), maxv = maxValue();
623
624 if ( minValue() < 0 ) {
625 dist = -minValue();
626 minv = 0;
627 maxv = maxValue() + dist;
628 }
629
630 int r = maxv - minv;
631 int v;
632 if ( d->wrapping )
633 v = (int)(0.5 + minv + r*(m_pi*3/2-a)/(2*m_pi));
634 else
635 v = (int)(0.5 + minv + r*(m_pi*4/3-a)/(m_pi*10/6));
636
637 if ( dist > 0 )
638 v -= dist;
639
640 return bound( v );
641}
642
643
644/*!
645 \internal
646*/
647
648double QDial::angle( const QPoint &p1, const QPoint &p2 ) const
649{
650 double _angle = 0.0;
651
652 if ( p1.x() == p2.x() ) {
653 if ( p1.y() < p2.y() )
654 _angle = 270.0;
655 else
656 _angle = 90.0;
657 } else {
658 double x1, x2, y1, y2;
659
660 if ( p1.x() <= p2.x() ) {
661 x1 = p1.x(); y1 = p1.y();
662 x2 = p2.x(); y2 = p2.y();
663 } else {
664 x2 = p1.x(); y2 = p1.y();
665 x1 = p2.x(); y1 = p2.y();
666 }
667
668 double m = -( y2 - y1 ) / ( x2 - x1 );
669 _angle = atan( m ) * rad_factor;
670
671 if ( p1.x() < p2.x() )
672 _angle = 180.0 - _angle;
673 else
674 _angle = -_angle;
675 }
676
677 return _angle;
678}
679
680void QDial::setWrapping( bool enable )
681{
682 if ( d->wrapping == enable )
683 return;
684 d->lines.resize( 0 );
685 d->wrapping = enable;
686 d->eraseAreaValid = FALSE;
687 repaintScreen();
688}
689
690
691/*!
692 \property QDial::wrapping
693 \brief whether wrapping is enabled
694
695 If TRUE, wrapping is enabled. This means that the arrow can be
696 turned around 360°. Otherwise there is some space at the bottom of
697 the dial which is skipped by the arrow.
698
699 This property's default is FALSE.
700*/
701
702bool QDial::wrapping() const
703{
704 return d->wrapping;
705}
706
707
708/*!
709 \property QDial::notchSize
710 \brief the current notch size
711
712 The notch size is in range control units, not pixels, and if
713 possible it is a multiple of lineStep() that results in an
714 on-screen notch size near notchTarget().
715
716 \sa notchTarget() lineStep()
717*/
718
719int QDial::notchSize() const
720{
721 // radius of the arc
722 int r = QMIN( width(), height() )/2;
723 // length of the whole arc
724 int l = (int)(r*(d->wrapping ? 6 : 5)*m_pi/6);
725 // length of the arc from minValue() to minValue()+pageStep()
726 if ( maxValue() > minValue()+pageStep() )
727 l = (int)(0.5 + l * pageStep() / (maxValue()-minValue()));
728 // length of a lineStep() arc
729 l = l * lineStep() / pageStep();
730 if ( l < 1 )
731 l = 1;
732 // how many times lineStep can be draw in d->target pixels
733 l = (int)(0.5 + d->target / l);
734 // we want notchSize() to be a non-zero multiple of lineStep()
735 if ( !l )
736 l = 1;
737 return lineStep() * l;
738}
739
740void QDial::setNotchTarget( double target )
741{
742 d->lines.resize( 0 );
743 d->target = target;
744 d->eraseAreaValid = FALSE;
745 d->onlyOutside = TRUE;
746 repaintScreen();
747 d->onlyOutside = FALSE;
748}
749
750
751/*!
752 \property QDial::notchTarget
753 \brief the target number of pixels between notches
754
755 The notch target is the number of pixels QDial attempts to put
756 between each notch.
757
758 The actual size may differ from the target size.
759*/
760
761double QDial::notchTarget() const
762{
763 return d->target;
764}
765
766
767/*!
768 Increments the dial's value() by one pageStep() of steps.
769*/
770
771void QDial::addPage()
772{
773 QRangeControl::addPage();
774}
775
776
777/*!
778 Decrements the dial's value() by one pageStep() of steps.
779*/
780
781void QDial::subtractPage()
782{
783 QRangeControl::subtractPage();
784}
785
786
787/*!
788 \fn void QDial::valueChanged( int value )
789
790 This signal is emitted whenever the dial's \a value changes. The
791 frequency of this signal is influenced by setTracking().
792*/
793
794/*!
795 \fn void QDial::dialPressed()
796
797 This signal is emitted when the user begins mouse interaction with
798 the dial.
799
800 \sa dialReleased()
801*/
802
803/*!
804 \fn void QDial::dialMoved( int value )
805
806 This signal is emitted whenever the dial \a value changes. The
807 frequency of this signal is \e not influenced by setTracking().
808
809 \sa valueChanged()
810*/
811
812/*!
813 \fn void QDial::dialReleased()
814
815 This signal is emitted when the user ends mouse interaction with
816 the dial.
817
818 \sa dialPressed()
819*/
820
821void QDial::setNotchesVisible( bool b )
822{
823 d->showNotches = b;
824 d->eraseAreaValid = FALSE;
825 d->onlyOutside = TRUE;
826 repaintScreen();
827 d->onlyOutside = FALSE;
828}
829
830/*!
831 \property QDial::notchesVisible
832 \brief whether the notches are shown
833
834 If TRUE, the notches are shown. If FALSE (the default) notches are
835 not shown.
836*/
837bool QDial::notchesVisible() const
838{
839 return d->showNotches;
840}
841
842/*!
843 \reimp
844*/
845
846QSize QDial::minimumSizeHint() const
847{
848 return QSize( 50, 50 );
849}
850
851/*!
852 \reimp
853*/
854
855QSize QDial::sizeHint() const
856{
857 return QSize( 100, 100 ).expandedTo( QApplication::globalStrut() );
858}
859
860
861
862/*!
863 \internal
864*/
865
866QPointArray QDial::calcArrow( double &a ) const
867{
868 int r = QMIN( width(), height() ) / 2;
869 if ( maxValue() == minValue() )
870 a = m_pi / 2;
871 else if ( d->wrapping )
872 a = m_pi * 3 / 2 - ( value() - minValue() ) * 2 * m_pi / ( maxValue() - minValue() );
873 else
874 a = ( m_pi * 8 - ( value() - minValue() ) * 10 * m_pi / ( maxValue() - minValue() ) ) / 6;
875
876 int xc = width() / 2;
877 int yc = height() / 2;
878
879 int len = r - calcBigLineSize() - 5;
880 if ( len < 5 )
881 len = 5;
882 int back = len / 4;
883 if ( back < 1 )
884 back = 1;
885
886 QPointArray arrow( 3 );
887 arrow[0] = QPoint( (int)( 0.5 + xc + len * cos(a) ),
888 (int)( 0.5 + yc -len * sin( a ) ) );
889 arrow[1] = QPoint( (int)( 0.5 + xc + back * cos( a + m_pi * 5 / 6 ) ),
890 (int)( 0.5 + yc - back * sin( a + m_pi * 5 / 6 ) ) );
891 arrow[2] = QPoint( (int)( 0.5 + xc + back * cos( a - m_pi * 5 / 6 ) ),
892 (int)( 0.5 + yc - back * sin( a - m_pi * 5 / 6 ) ) );
893 return arrow;
894}
895
896/*!
897 \internal
898*/
899
900QRect QDial::calcDial() const
901{
902 double r = QMIN( width(), height() ) / 2.0;
903 double d_ = r / 6.0;
904 double dx = d_ + ( width() - 2 * r ) / 2.0 + 1;
905 double dy = d_ + ( height() - 2 * r ) / 2.0 + 1;
906 return QRect( int(dx), int(dy),
907 int(r * 2 - 2 * d_ - 2), int(r * 2 - 2 * d_ - 2) );
908}
909
910/*!
911 \internal
912*/
913
914int QDial::calcBigLineSize() const
915{
916 int r = QMIN( width(), height() ) / 2;
917 int bigLineSize = r / 6;
918 if ( bigLineSize < 4 )
919 bigLineSize = 4;
920 if ( bigLineSize > r / 2 )
921 bigLineSize = r / 2;
922 return bigLineSize;
923}
924
925/*!
926 \internal
927*/
928
929void QDial::calcLines()
930{
931 if ( !d->lines.size() ) {
932 double r = QMIN( width(), height() ) / 2.0;
933 int bigLineSize = calcBigLineSize();
934 double xc = width() / 2.0;
935 double yc = height() / 2.0;
936 int ns = notchSize();
937 int notches = ( maxValue() + ns - 1 - minValue() ) / ns;
938 d->lines.resize( 2 + 2 * notches );
939 int smallLineSize = bigLineSize / 2;
940 int i;
941 for( i = 0; i <= notches; i++ ) {
942 double angle = d->wrapping
943 ? m_pi * 3 / 2 - i * 2 * m_pi / notches
944 : (m_pi * 8 - i * 10 * m_pi / notches) / 6;
945
946 double s = sin( angle ); // sin/cos aren't defined as const...
947 double c = cos( angle );
948 if ( i == 0 || ( ((ns * i ) % pageStep() ) == 0 ) ) {
949 d->lines[2*i] = QPoint( (int)( xc + ( r - bigLineSize ) * c ),
950 (int)( yc - ( r - bigLineSize ) * s ) );
951 d->lines[2*i+1] = QPoint( (int)( xc + r * c ),
952 (int)( yc - r * s ) );
953 } else {
954 d->lines[2*i] = QPoint( (int)( xc + ( r - 1 - smallLineSize ) * c ),
955 (int)( yc - ( r - 1 - smallLineSize ) * s ) );
956 d->lines[2*i+1] = QPoint( (int)( xc + ( r - 1 ) * c ),
957 (int)( yc -( r - 1 ) * s ) );
958 }
959 }
960 }
961}
962
963/*!
964 \property QDial::minValue
965 \brief the current minimum value
966
967 When setting this property, the \l QDial::maxValue is adjusted if
968 necessary to ensure that the range remains valid.
969
970 \sa setRange()
971*/
972int QDial::minValue() const
973{
974 return QRangeControl::minValue();
975}
976
977/*!
978 \property QDial::maxValue
979 \brief the current maximum value
980
981 When setting this property, the \l QDial::minValue is adjusted if
982 necessary to ensure that the range remains valid.
983
984 \sa setRange()
985*/
986int QDial::maxValue() const
987{
988 return QRangeControl::maxValue();
989}
990
991void QDial::setMinValue( int minVal )
992{
993 QRangeControl::setMinValue( minVal );
994}
995
996void QDial::setMaxValue( int maxVal )
997{
998 QRangeControl::setMaxValue( maxVal );
999}
1000
1001/*!
1002 \property QDial::lineStep
1003 \brief the current line step
1004
1005 setLineStep() calls the virtual stepChange() function if the new
1006 line step is different from the previous setting.
1007
1008 \sa QRangeControl::setSteps() pageStep setRange()
1009*/
1010
1011int QDial::lineStep() const
1012{
1013 return QRangeControl::lineStep();
1014}
1015
1016/*!
1017 \property QDial::pageStep
1018 \brief the current page step
1019
1020 setPageStep() calls the virtual stepChange() function if the new
1021 page step is different from the previous setting.
1022
1023 \sa stepChange()
1024*/
1025int QDial::pageStep() const
1026{
1027 return QRangeControl::pageStep();
1028}
1029
1030void QDial::setLineStep( int i )
1031{
1032 setSteps( i, pageStep() );
1033}
1034
1035void QDial::setPageStep( int i )
1036{
1037 setSteps( lineStep(), i );
1038}
1039
1040/*!
1041 \property QDial::value
1042 \brief the current dial value
1043
1044 This is guaranteed to be within the range
1045 \l{QDial::minValue}..\l{QDial::maxValue}.
1046
1047 \sa minValue maxValue
1048*/
1049
1050int QDial::value() const
1051{
1052 return QRangeControl::value();
1053}
1054
1055#endif // QT_FEATURE_DIAL
Note: See TracBrowser for help on using the repository browser.