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 "qwt_slider.h"
|
---|
11 | #include "qwt_painter.h"
|
---|
12 | #include "qwt_scale_draw.h"
|
---|
13 | #include "qwt_scale_map.h"
|
---|
14 | #include <qevent.h>
|
---|
15 | #include <qdrawutil.h>
|
---|
16 | #include <qpainter.h>
|
---|
17 | #include <qalgorithms.h>
|
---|
18 | #include <qmath.h>
|
---|
19 | #include <qstyle.h>
|
---|
20 | #include <qstyleoption.h>
|
---|
21 | #include <qapplication.h>
|
---|
22 |
|
---|
23 | static QSize qwtHandleSize( const QSize &size,
|
---|
24 | Qt::Orientation orientation, bool hasTrough )
|
---|
25 | {
|
---|
26 | QSize handleSize = size;
|
---|
27 |
|
---|
28 | if ( handleSize.isEmpty() )
|
---|
29 | {
|
---|
30 | const int handleThickness = 16;
|
---|
31 | handleSize.setWidth( 2 * handleThickness );
|
---|
32 | handleSize.setHeight( handleThickness );
|
---|
33 |
|
---|
34 | if ( !hasTrough )
|
---|
35 | handleSize.transpose();
|
---|
36 |
|
---|
37 | if ( orientation == Qt::Vertical )
|
---|
38 | handleSize.transpose();
|
---|
39 | }
|
---|
40 |
|
---|
41 | return handleSize;
|
---|
42 | }
|
---|
43 |
|
---|
44 | static QwtScaleDraw::Alignment qwtScaleDrawAlignment(
|
---|
45 | Qt::Orientation orientation, QwtSlider::ScalePosition scalePos )
|
---|
46 | {
|
---|
47 | QwtScaleDraw::Alignment align;
|
---|
48 |
|
---|
49 | if ( orientation == Qt::Vertical )
|
---|
50 | {
|
---|
51 | // NoScale lays out like Left
|
---|
52 | if ( scalePos == QwtSlider::LeadingScale )
|
---|
53 | align = QwtScaleDraw::RightScale;
|
---|
54 | else
|
---|
55 | align = QwtScaleDraw::LeftScale;
|
---|
56 | }
|
---|
57 | else
|
---|
58 | {
|
---|
59 | // NoScale lays out like Bottom
|
---|
60 | if ( scalePos == QwtSlider::TrailingScale )
|
---|
61 | align = QwtScaleDraw::TopScale;
|
---|
62 | else
|
---|
63 | align = QwtScaleDraw::BottomScale;
|
---|
64 | }
|
---|
65 |
|
---|
66 | return align;
|
---|
67 | }
|
---|
68 |
|
---|
69 | class QwtSlider::PrivateData
|
---|
70 | {
|
---|
71 | public:
|
---|
72 | PrivateData():
|
---|
73 | repeatTimerId( 0 ),
|
---|
74 | updateInterval( 150 ),
|
---|
75 | stepsIncrement( 0 ),
|
---|
76 | pendingValueChange( false ),
|
---|
77 | borderWidth( 2 ),
|
---|
78 | spacing( 4 ),
|
---|
79 | scalePosition( QwtSlider::TrailingScale ),
|
---|
80 | hasTrough( true ),
|
---|
81 | hasGroove( false ),
|
---|
82 | mouseOffset( 0 )
|
---|
83 | {
|
---|
84 | }
|
---|
85 |
|
---|
86 | int repeatTimerId;
|
---|
87 | bool timerTick;
|
---|
88 | int updateInterval;
|
---|
89 | int stepsIncrement;
|
---|
90 | bool pendingValueChange;
|
---|
91 |
|
---|
92 | QRect sliderRect;
|
---|
93 |
|
---|
94 | QSize handleSize;
|
---|
95 | int borderWidth;
|
---|
96 | int spacing;
|
---|
97 |
|
---|
98 | Qt::Orientation orientation;
|
---|
99 | QwtSlider::ScalePosition scalePosition;
|
---|
100 |
|
---|
101 | bool hasTrough;
|
---|
102 | bool hasGroove;
|
---|
103 |
|
---|
104 | int mouseOffset;
|
---|
105 |
|
---|
106 | mutable QSize sizeHintCache;
|
---|
107 | };
|
---|
108 | /*!
|
---|
109 | Construct vertical slider in QwtSlider::Trough style
|
---|
110 | with a scale to the left.
|
---|
111 |
|
---|
112 | The scale is initialized to [0.0, 100.0] and the value set to 0.0.
|
---|
113 |
|
---|
114 | \param parent Parent widget
|
---|
115 |
|
---|
116 | \sa setOrientation(), setScalePosition(), setBackgroundStyle()
|
---|
117 | */
|
---|
118 | QwtSlider::QwtSlider( QWidget *parent ):
|
---|
119 | QwtAbstractSlider( parent )
|
---|
120 | {
|
---|
121 | initSlider( Qt::Vertical );
|
---|
122 | }
|
---|
123 |
|
---|
124 | /*!
|
---|
125 | Construct a slider in QwtSlider::Trough style
|
---|
126 |
|
---|
127 | When orientation is Qt::Vertical the scale will be aligned to
|
---|
128 | the left - otherwise at the the top of the slider.
|
---|
129 |
|
---|
130 | The scale is initialized to [0.0, 100.0] and the value set to 0.0.
|
---|
131 |
|
---|
132 | \param parent Parent widget
|
---|
133 | \param orientation Orientation of the slider.
|
---|
134 | */
|
---|
135 | QwtSlider::QwtSlider( Qt::Orientation orientation, QWidget *parent ):
|
---|
136 | QwtAbstractSlider( parent )
|
---|
137 | {
|
---|
138 | initSlider( orientation );
|
---|
139 | }
|
---|
140 |
|
---|
141 | //! Destructor
|
---|
142 | QwtSlider::~QwtSlider()
|
---|
143 | {
|
---|
144 | delete d_data;
|
---|
145 | }
|
---|
146 |
|
---|
147 | void QwtSlider::initSlider( Qt::Orientation orientation )
|
---|
148 | {
|
---|
149 | if ( orientation == Qt::Vertical )
|
---|
150 | setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
|
---|
151 | else
|
---|
152 | setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
|
---|
153 |
|
---|
154 | setAttribute( Qt::WA_WState_OwnSizePolicy, false );
|
---|
155 |
|
---|
156 | d_data = new QwtSlider::PrivateData;
|
---|
157 |
|
---|
158 | d_data->orientation = orientation;
|
---|
159 |
|
---|
160 | scaleDraw()->setAlignment(
|
---|
161 | qwtScaleDrawAlignment( orientation, d_data->scalePosition ) );
|
---|
162 | scaleDraw()->setLength( 100 );
|
---|
163 |
|
---|
164 | setScale( 0.0, 100.0 );
|
---|
165 | setValue( 0.0 );
|
---|
166 | }
|
---|
167 |
|
---|
168 | /*!
|
---|
169 | \brief Set the orientation.
|
---|
170 | \param orientation Allowed values are Qt::Horizontal and Qt::Vertical.
|
---|
171 |
|
---|
172 | \sa orientation(), scalePosition()
|
---|
173 | */
|
---|
174 | void QwtSlider::setOrientation( Qt::Orientation orientation )
|
---|
175 | {
|
---|
176 | if ( orientation == d_data->orientation )
|
---|
177 | return;
|
---|
178 |
|
---|
179 | d_data->orientation = orientation;
|
---|
180 |
|
---|
181 | scaleDraw()->setAlignment(
|
---|
182 | qwtScaleDrawAlignment( orientation, d_data->scalePosition ) );
|
---|
183 |
|
---|
184 | if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
|
---|
185 | {
|
---|
186 | QSizePolicy sp = sizePolicy();
|
---|
187 | sp.transpose();
|
---|
188 | setSizePolicy( sp );
|
---|
189 |
|
---|
190 | setAttribute( Qt::WA_WState_OwnSizePolicy, false );
|
---|
191 | }
|
---|
192 |
|
---|
193 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
194 | layoutSlider( true );
|
---|
195 | }
|
---|
196 |
|
---|
197 | /*!
|
---|
198 | \return Orientation
|
---|
199 | \sa setOrientation()
|
---|
200 | */
|
---|
201 | Qt::Orientation QwtSlider::orientation() const
|
---|
202 | {
|
---|
203 | return d_data->orientation;
|
---|
204 | }
|
---|
205 |
|
---|
206 | /*!
|
---|
207 | \brief Change the position of the scale
|
---|
208 | \param scalePosition Position of the scale.
|
---|
209 |
|
---|
210 | \sa ScalePosition, scalePosition()
|
---|
211 | */
|
---|
212 | void QwtSlider::setScalePosition( ScalePosition scalePosition )
|
---|
213 | {
|
---|
214 | if ( d_data->scalePosition == scalePosition )
|
---|
215 | return;
|
---|
216 |
|
---|
217 | d_data->scalePosition = scalePosition;
|
---|
218 | scaleDraw()->setAlignment(
|
---|
219 | qwtScaleDrawAlignment( d_data->orientation, scalePosition ) );
|
---|
220 |
|
---|
221 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
222 | layoutSlider( true );
|
---|
223 | }
|
---|
224 |
|
---|
225 | /*!
|
---|
226 | \return Position of the scale
|
---|
227 | \sa setScalePosition()
|
---|
228 | */
|
---|
229 | QwtSlider::ScalePosition QwtSlider::scalePosition() const
|
---|
230 | {
|
---|
231 | return d_data->scalePosition;
|
---|
232 | }
|
---|
233 |
|
---|
234 | /*!
|
---|
235 | \brief Change the slider's border width
|
---|
236 |
|
---|
237 | The border width is used for drawing the slider handle and the
|
---|
238 | trough.
|
---|
239 |
|
---|
240 | \param width Border width
|
---|
241 | \sa borderWidth()
|
---|
242 | */
|
---|
243 | void QwtSlider::setBorderWidth( int width )
|
---|
244 | {
|
---|
245 | if ( width < 0 )
|
---|
246 | width = 0;
|
---|
247 |
|
---|
248 | if ( width != d_data->borderWidth )
|
---|
249 | {
|
---|
250 | d_data->borderWidth = width;
|
---|
251 |
|
---|
252 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
253 | layoutSlider( true );
|
---|
254 | }
|
---|
255 | }
|
---|
256 |
|
---|
257 | /*!
|
---|
258 | \return the border width.
|
---|
259 | \sa setBorderWidth()
|
---|
260 | */
|
---|
261 | int QwtSlider::borderWidth() const
|
---|
262 | {
|
---|
263 | return d_data->borderWidth;
|
---|
264 | }
|
---|
265 |
|
---|
266 | /*!
|
---|
267 | \brief Change the spacing between trough and scale
|
---|
268 |
|
---|
269 | A spacing of 0 means, that the backbone of the scale is covered
|
---|
270 | by the trough.
|
---|
271 |
|
---|
272 | The default setting is 4 pixels.
|
---|
273 |
|
---|
274 | \param spacing Number of pixels
|
---|
275 | \sa spacing();
|
---|
276 | */
|
---|
277 | void QwtSlider::setSpacing( int spacing )
|
---|
278 | {
|
---|
279 | if ( spacing <= 0 )
|
---|
280 | spacing = 0;
|
---|
281 |
|
---|
282 | if ( spacing != d_data->spacing )
|
---|
283 | {
|
---|
284 | d_data->spacing = spacing;
|
---|
285 |
|
---|
286 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
287 | layoutSlider( true );
|
---|
288 | }
|
---|
289 | }
|
---|
290 |
|
---|
291 | /*!
|
---|
292 | \return Number of pixels between slider and scale
|
---|
293 | \sa setSpacing()
|
---|
294 | */
|
---|
295 | int QwtSlider::spacing() const
|
---|
296 | {
|
---|
297 | return d_data->spacing;
|
---|
298 | }
|
---|
299 |
|
---|
300 | /*!
|
---|
301 | \brief Set the slider's handle size
|
---|
302 |
|
---|
303 | When the size is empty the slider handle will be painted with a
|
---|
304 | default size depending on its orientation() and backgroundStyle().
|
---|
305 |
|
---|
306 | \param size New size
|
---|
307 |
|
---|
308 | \sa handleSize()
|
---|
309 | */
|
---|
310 | void QwtSlider::setHandleSize( const QSize &size )
|
---|
311 | {
|
---|
312 | if ( size != d_data->handleSize )
|
---|
313 | {
|
---|
314 | d_data->handleSize = size;
|
---|
315 |
|
---|
316 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
317 | layoutSlider( true );
|
---|
318 | }
|
---|
319 | }
|
---|
320 |
|
---|
321 | /*!
|
---|
322 | \return Size of the handle.
|
---|
323 | \sa setHandleSize()
|
---|
324 | */
|
---|
325 | QSize QwtSlider::handleSize() const
|
---|
326 | {
|
---|
327 | return d_data->handleSize;
|
---|
328 | }
|
---|
329 |
|
---|
330 | /*!
|
---|
331 | \brief Set a scale draw
|
---|
332 |
|
---|
333 | For changing the labels of the scales, it
|
---|
334 | is necessary to derive from QwtScaleDraw and
|
---|
335 | overload QwtScaleDraw::label().
|
---|
336 |
|
---|
337 | \param scaleDraw ScaleDraw object, that has to be created with
|
---|
338 | new and will be deleted in ~QwtSlider() or the next
|
---|
339 | call of setScaleDraw().
|
---|
340 |
|
---|
341 | \sa scaleDraw()
|
---|
342 | */
|
---|
343 | void QwtSlider::setScaleDraw( QwtScaleDraw *scaleDraw )
|
---|
344 | {
|
---|
345 | const QwtScaleDraw *previousScaleDraw = this->scaleDraw();
|
---|
346 | if ( scaleDraw == NULL || scaleDraw == previousScaleDraw )
|
---|
347 | return;
|
---|
348 |
|
---|
349 | if ( previousScaleDraw )
|
---|
350 | scaleDraw->setAlignment( previousScaleDraw->alignment() );
|
---|
351 |
|
---|
352 | setAbstractScaleDraw( scaleDraw );
|
---|
353 |
|
---|
354 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
355 | layoutSlider( true );
|
---|
356 | }
|
---|
357 |
|
---|
358 | /*!
|
---|
359 | \return the scale draw of the slider
|
---|
360 | \sa setScaleDraw()
|
---|
361 | */
|
---|
362 | const QwtScaleDraw *QwtSlider::scaleDraw() const
|
---|
363 | {
|
---|
364 | return static_cast<const QwtScaleDraw *>( abstractScaleDraw() );
|
---|
365 | }
|
---|
366 |
|
---|
367 | /*!
|
---|
368 | \return the scale draw of the slider
|
---|
369 | \sa setScaleDraw()
|
---|
370 | */
|
---|
371 | QwtScaleDraw *QwtSlider::scaleDraw()
|
---|
372 | {
|
---|
373 | return static_cast<QwtScaleDraw *>( abstractScaleDraw() );
|
---|
374 | }
|
---|
375 |
|
---|
376 | //! Notify changed scale
|
---|
377 | void QwtSlider::scaleChange()
|
---|
378 | {
|
---|
379 | QwtAbstractSlider::scaleChange();
|
---|
380 |
|
---|
381 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
382 | layoutSlider( true );
|
---|
383 | }
|
---|
384 |
|
---|
385 | /*!
|
---|
386 | \brief Specify the update interval for automatic scrolling
|
---|
387 |
|
---|
388 | The minimal accepted value is 50 ms.
|
---|
389 |
|
---|
390 | \param interval Update interval in milliseconds
|
---|
391 |
|
---|
392 | \sa setUpdateInterval()
|
---|
393 | */
|
---|
394 | void QwtSlider::setUpdateInterval( int interval )
|
---|
395 | {
|
---|
396 | d_data->updateInterval = qMax( interval, 50 );
|
---|
397 | }
|
---|
398 |
|
---|
399 | /*!
|
---|
400 | \return Update interval in milliseconds for automatic scrolling
|
---|
401 | \sa setUpdateInterval()
|
---|
402 | */
|
---|
403 | int QwtSlider::updateInterval() const
|
---|
404 | {
|
---|
405 | return d_data->updateInterval;
|
---|
406 | }
|
---|
407 |
|
---|
408 | /*!
|
---|
409 | Draw the slider into the specified rectangle.
|
---|
410 |
|
---|
411 | \param painter Painter
|
---|
412 | \param sliderRect Bounding rectangle of the slider
|
---|
413 | */
|
---|
414 | void QwtSlider::drawSlider(
|
---|
415 | QPainter *painter, const QRect &sliderRect ) const
|
---|
416 | {
|
---|
417 | QRect innerRect( sliderRect );
|
---|
418 |
|
---|
419 | if ( d_data->hasTrough )
|
---|
420 | {
|
---|
421 | const int bw = d_data->borderWidth;
|
---|
422 | innerRect = sliderRect.adjusted( bw, bw, -bw, -bw );
|
---|
423 |
|
---|
424 | painter->fillRect( innerRect, palette().brush( QPalette::Mid ) );
|
---|
425 | qDrawShadePanel( painter, sliderRect, palette(), true, bw, NULL );
|
---|
426 | }
|
---|
427 |
|
---|
428 | const QSize handleSize = qwtHandleSize( d_data->handleSize,
|
---|
429 | d_data->orientation, d_data->hasTrough );
|
---|
430 |
|
---|
431 | if ( d_data->hasGroove )
|
---|
432 | {
|
---|
433 | const int slotExtent = 4;
|
---|
434 | const int slotMargin = 4;
|
---|
435 |
|
---|
436 | QRect slotRect;
|
---|
437 | if ( orientation() == Qt::Horizontal )
|
---|
438 | {
|
---|
439 | int slotOffset = qMax( 1, handleSize.width() / 2 - slotMargin );
|
---|
440 | int slotHeight = slotExtent + ( innerRect.height() % 2 );
|
---|
441 |
|
---|
442 | slotRect.setWidth( innerRect.width() - 2 * slotOffset );
|
---|
443 | slotRect.setHeight( slotHeight );
|
---|
444 | }
|
---|
445 | else
|
---|
446 | {
|
---|
447 | int slotOffset = qMax( 1, handleSize.height() / 2 - slotMargin );
|
---|
448 | int slotWidth = slotExtent + ( innerRect.width() % 2 );
|
---|
449 |
|
---|
450 | slotRect.setWidth( slotWidth );
|
---|
451 | slotRect.setHeight( innerRect.height() - 2 * slotOffset );
|
---|
452 |
|
---|
453 | }
|
---|
454 |
|
---|
455 | slotRect.moveCenter( innerRect.center() );
|
---|
456 |
|
---|
457 | QBrush brush = palette().brush( QPalette::Dark );
|
---|
458 | qDrawShadePanel( painter, slotRect, palette(), true, 1 , &brush );
|
---|
459 | }
|
---|
460 |
|
---|
461 | if ( isValid() )
|
---|
462 | drawHandle( painter, handleRect(), transform( value() ) );
|
---|
463 | }
|
---|
464 |
|
---|
465 | /*!
|
---|
466 | Draw the thumb at a position
|
---|
467 |
|
---|
468 | \param painter Painter
|
---|
469 | \param handleRect Bounding rectangle of the handle
|
---|
470 | \param pos Position of the handle marker in widget coordinates
|
---|
471 | */
|
---|
472 | void QwtSlider::drawHandle( QPainter *painter,
|
---|
473 | const QRect &handleRect, int pos ) const
|
---|
474 | {
|
---|
475 | const int bw = d_data->borderWidth;
|
---|
476 |
|
---|
477 | qDrawShadePanel( painter,
|
---|
478 | handleRect, palette(), false, bw,
|
---|
479 | &palette().brush( QPalette::Button ) );
|
---|
480 |
|
---|
481 | pos++; // shade line points one pixel below
|
---|
482 | if ( orientation() == Qt::Horizontal )
|
---|
483 | {
|
---|
484 | qDrawShadeLine( painter, pos, handleRect.top() + bw,
|
---|
485 | pos, handleRect.bottom() - bw, palette(), true, 1 );
|
---|
486 | }
|
---|
487 | else // Vertical
|
---|
488 | {
|
---|
489 | qDrawShadeLine( painter, handleRect.left() + bw, pos,
|
---|
490 | handleRect.right() - bw, pos, palette(), true, 1 );
|
---|
491 | }
|
---|
492 | }
|
---|
493 |
|
---|
494 | /*!
|
---|
495 | \brief Determine what to do when the user presses a mouse button.
|
---|
496 |
|
---|
497 | \param pos Mouse position
|
---|
498 |
|
---|
499 | \retval True, when handleRect() contains pos
|
---|
500 | \sa scrolledTo()
|
---|
501 | */
|
---|
502 | bool QwtSlider::isScrollPosition( const QPoint &pos ) const
|
---|
503 | {
|
---|
504 | if ( handleRect().contains( pos ) )
|
---|
505 | {
|
---|
506 | const double v = ( orientation() == Qt::Horizontal )
|
---|
507 | ? pos.x() : pos.y();
|
---|
508 |
|
---|
509 | d_data->mouseOffset = v - transform( value() );
|
---|
510 | return true;
|
---|
511 | }
|
---|
512 |
|
---|
513 | return false;
|
---|
514 | }
|
---|
515 |
|
---|
516 | /*!
|
---|
517 | \brief Determine the value for a new position of the
|
---|
518 | slider handle.
|
---|
519 |
|
---|
520 | \param pos Mouse position
|
---|
521 |
|
---|
522 | \return Value for the mouse position
|
---|
523 | \sa isScrollPosition()
|
---|
524 | */
|
---|
525 | double QwtSlider::scrolledTo( const QPoint &pos ) const
|
---|
526 | {
|
---|
527 | int p = ( orientation() == Qt::Horizontal )
|
---|
528 | ? pos.x() : pos.y();
|
---|
529 |
|
---|
530 | p -= d_data->mouseOffset;
|
---|
531 |
|
---|
532 | int min = transform( lowerBound() );
|
---|
533 | int max = transform( upperBound() );
|
---|
534 | if ( min > max )
|
---|
535 | qSwap( min, max );
|
---|
536 |
|
---|
537 | p = qBound( min, p, max );
|
---|
538 |
|
---|
539 | return scaleMap().invTransform( p );
|
---|
540 | }
|
---|
541 |
|
---|
542 | /*!
|
---|
543 | Mouse press event handler
|
---|
544 | \param event Mouse event
|
---|
545 | */
|
---|
546 | void QwtSlider::mousePressEvent( QMouseEvent *event )
|
---|
547 | {
|
---|
548 | if ( isReadOnly() )
|
---|
549 | {
|
---|
550 | event->ignore();
|
---|
551 | return;
|
---|
552 | }
|
---|
553 |
|
---|
554 | const QPoint pos = event->pos();
|
---|
555 |
|
---|
556 | if ( isValid() && d_data->sliderRect.contains( pos ) )
|
---|
557 | {
|
---|
558 | if ( !handleRect().contains( pos ) )
|
---|
559 | {
|
---|
560 | const int markerPos = transform( value() );
|
---|
561 |
|
---|
562 | d_data->stepsIncrement = pageSteps();
|
---|
563 |
|
---|
564 | if ( d_data->orientation == Qt::Horizontal )
|
---|
565 | {
|
---|
566 | if ( pos.x() < markerPos )
|
---|
567 | d_data->stepsIncrement = -d_data->stepsIncrement;
|
---|
568 | }
|
---|
569 | else
|
---|
570 | {
|
---|
571 | if ( pos.y() < markerPos )
|
---|
572 | d_data->stepsIncrement = -d_data->stepsIncrement;
|
---|
573 | }
|
---|
574 |
|
---|
575 | if ( isInverted() )
|
---|
576 | d_data->stepsIncrement = -d_data->stepsIncrement;
|
---|
577 |
|
---|
578 | const double v = value();
|
---|
579 | incrementValue( d_data->stepsIncrement );
|
---|
580 |
|
---|
581 | if ( v != value() )
|
---|
582 | {
|
---|
583 | if ( isTracking() )
|
---|
584 | Q_EMIT valueChanged( value() );
|
---|
585 | else
|
---|
586 | d_data->pendingValueChange = true;
|
---|
587 |
|
---|
588 | Q_EMIT sliderMoved( value() );
|
---|
589 | }
|
---|
590 |
|
---|
591 | d_data->timerTick = false;
|
---|
592 | d_data->repeatTimerId = startTimer( qMax( 250, 2 * updateInterval() ) );
|
---|
593 |
|
---|
594 | return;
|
---|
595 | }
|
---|
596 | }
|
---|
597 |
|
---|
598 | QwtAbstractSlider::mousePressEvent( event );
|
---|
599 | }
|
---|
600 |
|
---|
601 | /*!
|
---|
602 | Mouse release event handler
|
---|
603 | \param event Mouse event
|
---|
604 | */
|
---|
605 | void QwtSlider::mouseReleaseEvent( QMouseEvent *event )
|
---|
606 | {
|
---|
607 | if ( d_data->repeatTimerId > 0 )
|
---|
608 | {
|
---|
609 | killTimer( d_data->repeatTimerId );
|
---|
610 | d_data->repeatTimerId = 0;
|
---|
611 | d_data->timerTick = false;
|
---|
612 | d_data->stepsIncrement = 0;
|
---|
613 | }
|
---|
614 |
|
---|
615 | if ( d_data->pendingValueChange )
|
---|
616 | {
|
---|
617 | d_data->pendingValueChange = false;
|
---|
618 | Q_EMIT valueChanged( value() );
|
---|
619 | }
|
---|
620 |
|
---|
621 | QwtAbstractSlider::mouseReleaseEvent( event );
|
---|
622 | }
|
---|
623 |
|
---|
624 | /*!
|
---|
625 | Timer event handler
|
---|
626 |
|
---|
627 | Handles the timer, when the mouse stays pressed
|
---|
628 | inside the sliderRect().
|
---|
629 |
|
---|
630 | \param event Mouse event
|
---|
631 | */
|
---|
632 | void QwtSlider::timerEvent( QTimerEvent *event )
|
---|
633 | {
|
---|
634 | if ( event->timerId() != d_data->repeatTimerId )
|
---|
635 | {
|
---|
636 | QwtAbstractSlider::timerEvent( event );
|
---|
637 | return;
|
---|
638 | }
|
---|
639 |
|
---|
640 | if ( !isValid() )
|
---|
641 | {
|
---|
642 | killTimer( d_data->repeatTimerId );
|
---|
643 | d_data->repeatTimerId = 0;
|
---|
644 | return;
|
---|
645 | }
|
---|
646 |
|
---|
647 | const double v = value();
|
---|
648 | incrementValue( d_data->stepsIncrement );
|
---|
649 |
|
---|
650 | if ( v != value() )
|
---|
651 | {
|
---|
652 | if ( isTracking() )
|
---|
653 | Q_EMIT valueChanged( value() );
|
---|
654 | else
|
---|
655 | d_data->pendingValueChange = true;
|
---|
656 |
|
---|
657 | Q_EMIT sliderMoved( value() );
|
---|
658 | }
|
---|
659 |
|
---|
660 | if ( !d_data->timerTick )
|
---|
661 | {
|
---|
662 | // restart the timer with a shorter interval
|
---|
663 | killTimer( d_data->repeatTimerId );
|
---|
664 | d_data->repeatTimerId = startTimer( updateInterval() );
|
---|
665 |
|
---|
666 | d_data->timerTick = true;
|
---|
667 | }
|
---|
668 | }
|
---|
669 |
|
---|
670 | /*!
|
---|
671 | Qt paint event handler
|
---|
672 | \param event Paint event
|
---|
673 | */
|
---|
674 | void QwtSlider::paintEvent( QPaintEvent *event )
|
---|
675 | {
|
---|
676 | QPainter painter( this );
|
---|
677 | painter.setClipRegion( event->region() );
|
---|
678 |
|
---|
679 | QStyleOption opt;
|
---|
680 | opt.init(this);
|
---|
681 | style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
---|
682 |
|
---|
683 | if ( d_data->scalePosition != QwtSlider::NoScale )
|
---|
684 | {
|
---|
685 | if ( !d_data->sliderRect.contains( event->rect() ) )
|
---|
686 | scaleDraw()->draw( &painter, palette() );
|
---|
687 | }
|
---|
688 |
|
---|
689 | drawSlider( &painter, d_data->sliderRect );
|
---|
690 |
|
---|
691 | if ( hasFocus() )
|
---|
692 | QwtPainter::drawFocusRect( &painter, this, d_data->sliderRect );
|
---|
693 | }
|
---|
694 |
|
---|
695 | /*!
|
---|
696 | Qt resize event handler
|
---|
697 | \param event Resize event
|
---|
698 | */
|
---|
699 | void QwtSlider::resizeEvent( QResizeEvent *event )
|
---|
700 | {
|
---|
701 | Q_UNUSED( event );
|
---|
702 |
|
---|
703 | layoutSlider( false );
|
---|
704 | }
|
---|
705 |
|
---|
706 | /*!
|
---|
707 | Handles QEvent::StyleChange and QEvent::FontChange events
|
---|
708 | \param event Change event
|
---|
709 | */
|
---|
710 | void QwtSlider::changeEvent( QEvent *event )
|
---|
711 | {
|
---|
712 | if ( event->type() == QEvent::StyleChange ||
|
---|
713 | event->type() == QEvent::FontChange )
|
---|
714 | {
|
---|
715 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
716 | layoutSlider( true );
|
---|
717 | }
|
---|
718 |
|
---|
719 | QwtAbstractSlider::changeEvent( event );
|
---|
720 | }
|
---|
721 |
|
---|
722 | /*!
|
---|
723 | Recalculate the slider's geometry and layout based on
|
---|
724 | the current geometry and fonts.
|
---|
725 |
|
---|
726 | \param update_geometry notify the layout system and call update
|
---|
727 | to redraw the scale
|
---|
728 | */
|
---|
729 | void QwtSlider::layoutSlider( bool update_geometry )
|
---|
730 | {
|
---|
731 | int bw = 0;
|
---|
732 | if ( d_data->hasTrough )
|
---|
733 | bw = d_data->borderWidth;
|
---|
734 |
|
---|
735 | const QSize handleSize = qwtHandleSize( d_data->handleSize,
|
---|
736 | d_data->orientation, d_data->hasTrough );
|
---|
737 |
|
---|
738 | QRect sliderRect = contentsRect();
|
---|
739 |
|
---|
740 | /*
|
---|
741 | The marker line of the handle needs to be aligned to
|
---|
742 | the scale. But the marker is in the center
|
---|
743 | and we need space enough to display the rest of the handle.
|
---|
744 |
|
---|
745 | But the scale itself usually needs margins for displaying
|
---|
746 | the tick labels, that also might needs space beyond the
|
---|
747 | backbone.
|
---|
748 |
|
---|
749 | Now it depends on what needs more margins. If it is the
|
---|
750 | slider the scale gets shrunk, otherwise the slider.
|
---|
751 | */
|
---|
752 |
|
---|
753 | int scaleMargin = 0;
|
---|
754 | if ( d_data->scalePosition != QwtSlider::NoScale )
|
---|
755 | {
|
---|
756 | int d1, d2;
|
---|
757 | scaleDraw()->getBorderDistHint( font(), d1, d2 );
|
---|
758 |
|
---|
759 | scaleMargin = qMax( d1, d2 ) - bw;
|
---|
760 | }
|
---|
761 |
|
---|
762 | int scaleX, scaleY, scaleLength;
|
---|
763 |
|
---|
764 | if ( d_data->orientation == Qt::Horizontal )
|
---|
765 | {
|
---|
766 | const int handleMargin = handleSize.width() / 2 - 1;
|
---|
767 | if ( scaleMargin > handleMargin )
|
---|
768 | {
|
---|
769 | int off = scaleMargin - handleMargin;
|
---|
770 | sliderRect.adjust( off, 0, -off, 0 );
|
---|
771 | }
|
---|
772 |
|
---|
773 | scaleX = sliderRect.left() + bw + handleSize.width() / 2 - 1;
|
---|
774 | scaleLength = sliderRect.width() - handleSize.width();
|
---|
775 | }
|
---|
776 | else
|
---|
777 | {
|
---|
778 | int handleMargin = handleSize.height() / 2 - 1;
|
---|
779 | if ( scaleMargin > handleMargin )
|
---|
780 | {
|
---|
781 | int off = scaleMargin - handleMargin;
|
---|
782 | sliderRect.adjust( 0, off, 0, -off );
|
---|
783 | }
|
---|
784 |
|
---|
785 | scaleY = sliderRect.top() + bw + handleSize.height() / 2 - 1;
|
---|
786 | scaleLength = sliderRect.height() - handleSize.height();
|
---|
787 | }
|
---|
788 |
|
---|
789 | scaleLength -= 2 * bw;
|
---|
790 |
|
---|
791 | // now align slider and scale according to the ScalePosition
|
---|
792 |
|
---|
793 | if ( d_data->orientation == Qt::Horizontal )
|
---|
794 | {
|
---|
795 | const int h = handleSize.height() + 2 * bw;
|
---|
796 |
|
---|
797 | if ( d_data->scalePosition == QwtSlider::TrailingScale )
|
---|
798 | {
|
---|
799 | sliderRect.setTop( sliderRect.bottom() + 1 - h );
|
---|
800 | scaleY = sliderRect.top() - d_data->spacing;
|
---|
801 | }
|
---|
802 | else
|
---|
803 | {
|
---|
804 | sliderRect.setHeight( h );
|
---|
805 | scaleY = sliderRect.bottom() + 1 + d_data->spacing;
|
---|
806 | }
|
---|
807 | }
|
---|
808 | else // Qt::Vertical
|
---|
809 | {
|
---|
810 | const int w = handleSize.width() + 2 * bw;
|
---|
811 |
|
---|
812 | if ( d_data->scalePosition == QwtSlider::LeadingScale )
|
---|
813 | {
|
---|
814 | sliderRect.setWidth( w );
|
---|
815 | scaleX = sliderRect.right() + 1 + d_data->spacing;
|
---|
816 | }
|
---|
817 | else
|
---|
818 | {
|
---|
819 | sliderRect.setLeft( sliderRect.right() + 1 - w );
|
---|
820 | scaleX = sliderRect.left() - d_data->spacing;
|
---|
821 | }
|
---|
822 | }
|
---|
823 |
|
---|
824 | d_data->sliderRect = sliderRect;
|
---|
825 |
|
---|
826 | scaleDraw()->move( scaleX, scaleY );
|
---|
827 | scaleDraw()->setLength( scaleLength );
|
---|
828 |
|
---|
829 | if ( update_geometry )
|
---|
830 | {
|
---|
831 | d_data->sizeHintCache = QSize(); // invalidate
|
---|
832 | updateGeometry();
|
---|
833 | update();
|
---|
834 | }
|
---|
835 | }
|
---|
836 |
|
---|
837 | /*!
|
---|
838 | En/Disable the trough
|
---|
839 |
|
---|
840 | The slider can be cutomized by showing a trough for the
|
---|
841 | handle.
|
---|
842 |
|
---|
843 | \param on When true, the groove is visible
|
---|
844 | \sa hasTrough(), setGroove()
|
---|
845 | */
|
---|
846 | void QwtSlider::setTrough( bool on )
|
---|
847 | {
|
---|
848 | if ( d_data->hasTrough != on )
|
---|
849 | {
|
---|
850 | d_data->hasTrough = on;
|
---|
851 |
|
---|
852 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
853 | layoutSlider( true );
|
---|
854 | }
|
---|
855 | }
|
---|
856 |
|
---|
857 | /*!
|
---|
858 | \return True, when the trough is visisble
|
---|
859 | \sa setTrough(), hasGroove()
|
---|
860 | */
|
---|
861 | bool QwtSlider::hasTrough() const
|
---|
862 | {
|
---|
863 | return d_data->hasTrough;
|
---|
864 | }
|
---|
865 |
|
---|
866 | /*!
|
---|
867 | En/Disable the groove
|
---|
868 |
|
---|
869 | The slider can be cutomized by showing a groove for the
|
---|
870 | handle.
|
---|
871 |
|
---|
872 | \param on When true, the groove is visible
|
---|
873 | \sa hasGroove(), setThrough()
|
---|
874 | */
|
---|
875 | void QwtSlider::setGroove( bool on )
|
---|
876 | {
|
---|
877 | if ( d_data->hasGroove != on )
|
---|
878 | {
|
---|
879 | d_data->hasGroove = on;
|
---|
880 |
|
---|
881 | if ( testAttribute( Qt::WA_WState_Polished ) )
|
---|
882 | layoutSlider( true );
|
---|
883 | }
|
---|
884 | }
|
---|
885 |
|
---|
886 | /*!
|
---|
887 | \return True, when the groove is visisble
|
---|
888 | \sa setGroove(), hasTrough()
|
---|
889 | */
|
---|
890 | bool QwtSlider::hasGroove() const
|
---|
891 | {
|
---|
892 | return d_data->hasGroove;
|
---|
893 | }
|
---|
894 |
|
---|
895 | /*!
|
---|
896 | \return minimumSizeHint()
|
---|
897 | */
|
---|
898 | QSize QwtSlider::sizeHint() const
|
---|
899 | {
|
---|
900 | const QSize hint = minimumSizeHint();
|
---|
901 | return hint.expandedTo( QApplication::globalStrut() );
|
---|
902 | }
|
---|
903 |
|
---|
904 | /*!
|
---|
905 | \return Minimum size hint
|
---|
906 | \sa sizeHint()
|
---|
907 | */
|
---|
908 | QSize QwtSlider::minimumSizeHint() const
|
---|
909 | {
|
---|
910 | if ( !d_data->sizeHintCache.isEmpty() )
|
---|
911 | return d_data->sizeHintCache;
|
---|
912 |
|
---|
913 | const QSize handleSize = qwtHandleSize( d_data->handleSize,
|
---|
914 | d_data->orientation, d_data->hasTrough );
|
---|
915 |
|
---|
916 | int bw = 0;
|
---|
917 | if ( d_data->hasTrough )
|
---|
918 | bw = d_data->borderWidth;
|
---|
919 |
|
---|
920 | int sliderLength = 0;
|
---|
921 | int scaleExtent = 0;
|
---|
922 |
|
---|
923 | if ( d_data->scalePosition != QwtSlider::NoScale )
|
---|
924 | {
|
---|
925 | int d1, d2;
|
---|
926 | scaleDraw()->getBorderDistHint( font(), d1, d2 );
|
---|
927 |
|
---|
928 | const int scaleBorderDist = 2 * ( qMax( d1, d2 ) - bw );
|
---|
929 |
|
---|
930 | int handleBorderDist;
|
---|
931 | if ( d_data->orientation == Qt::Horizontal )
|
---|
932 | handleBorderDist = handleSize.width();
|
---|
933 | else
|
---|
934 | handleBorderDist = handleSize.height();
|
---|
935 |
|
---|
936 | sliderLength = scaleDraw()->minLength( font() );
|
---|
937 | if ( handleBorderDist > scaleBorderDist )
|
---|
938 | {
|
---|
939 | // We need additional space for the overlapping handle
|
---|
940 | sliderLength += handleBorderDist - scaleBorderDist;
|
---|
941 | }
|
---|
942 |
|
---|
943 | scaleExtent += d_data->spacing;
|
---|
944 | scaleExtent += qCeil( scaleDraw()->extent( font() ) );
|
---|
945 | }
|
---|
946 |
|
---|
947 | sliderLength = qMax( sliderLength, 84 ); // from QSlider
|
---|
948 |
|
---|
949 | int w = 0;
|
---|
950 | int h = 0;
|
---|
951 |
|
---|
952 | if ( d_data->orientation == Qt::Horizontal )
|
---|
953 | {
|
---|
954 | w = sliderLength;
|
---|
955 | h = handleSize.height() + 2 * bw + scaleExtent;
|
---|
956 | }
|
---|
957 | else
|
---|
958 | {
|
---|
959 | w = handleSize.width() + 2 * bw + scaleExtent;
|
---|
960 | h = sliderLength;
|
---|
961 | }
|
---|
962 |
|
---|
963 | // finally add margins
|
---|
964 | int left, right, top, bottom;
|
---|
965 | getContentsMargins( &left, &top, &right, &bottom );
|
---|
966 |
|
---|
967 | w += left + right;
|
---|
968 | h += top + bottom;
|
---|
969 |
|
---|
970 | d_data->sizeHintCache = QSize( w, h );
|
---|
971 | return d_data->sizeHintCache;
|
---|
972 | }
|
---|
973 |
|
---|
974 | /*!
|
---|
975 | \return Bounding rectangle of the slider handle
|
---|
976 | */
|
---|
977 | QRect QwtSlider::handleRect() const
|
---|
978 | {
|
---|
979 | if ( !isValid() )
|
---|
980 | return QRect();
|
---|
981 |
|
---|
982 | const int markerPos = transform( value() );
|
---|
983 |
|
---|
984 | QPoint center = d_data->sliderRect.center();
|
---|
985 | if ( d_data->orientation == Qt::Horizontal )
|
---|
986 | center.setX( markerPos );
|
---|
987 | else
|
---|
988 | center.setY( markerPos );
|
---|
989 |
|
---|
990 | QRect rect;
|
---|
991 | rect.setSize( qwtHandleSize( d_data->handleSize,
|
---|
992 | d_data->orientation, d_data->hasTrough ) );
|
---|
993 | rect.moveCenter( center );
|
---|
994 |
|
---|
995 | return rect;
|
---|
996 | }
|
---|
997 |
|
---|
998 | /*!
|
---|
999 | \return Bounding rectangle of the slider - without the scale
|
---|
1000 | */
|
---|
1001 | QRect QwtSlider::sliderRect() const
|
---|
1002 | {
|
---|
1003 | return d_data->sliderRect;
|
---|
1004 | }
|
---|