qwt_slider.cpp 23 KB
Newer Older
pixhawk's avatar
pixhawk committed
1
2
3
4
5
6
7
8
9
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

Bryant's avatar
Bryant committed
10
#include "qwt_slider.h"
pixhawk's avatar
pixhawk committed
11
12
13
#include "qwt_painter.h"
#include "qwt_scale_draw.h"
#include "qwt_scale_map.h"
Bryant's avatar
Bryant committed
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <qevent.h>
#include <qdrawutil.h>
#include <qpainter.h>
#include <qalgorithms.h>
#include <qmath.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qapplication.h>

static QSize qwtHandleSize( const QSize &size, 
    Qt::Orientation orientation, bool hasTrough )
{
    QSize handleSize = size;

    if ( handleSize.isEmpty() )
    {
        const int handleThickness = 16;
        handleSize.setWidth( 2 * handleThickness );
        handleSize.setHeight( handleThickness );

        if ( !hasTrough )
            handleSize.transpose();

        if ( orientation == Qt::Vertical )
            handleSize.transpose();
    }

    return handleSize;
}

static QwtScaleDraw::Alignment qwtScaleDrawAlignment( 
    Qt::Orientation orientation, QwtSlider::ScalePosition scalePos )
{
    QwtScaleDraw::Alignment align;

    if ( orientation == Qt::Vertical )
    {
        // NoScale lays out like Left
        if ( scalePos == QwtSlider::LeadingScale )
            align = QwtScaleDraw::RightScale;
        else
            align = QwtScaleDraw::LeftScale;
    }
    else
    {
        // NoScale lays out like Bottom
        if ( scalePos == QwtSlider::TrailingScale )
            align = QwtScaleDraw::TopScale;
        else
            align = QwtScaleDraw::BottomScale;
    }

    return align;
}
pixhawk's avatar
pixhawk committed
68
69
70
71

class QwtSlider::PrivateData
{
public:
Bryant's avatar
Bryant committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    PrivateData():
        repeatTimerId( 0 ),
        updateInterval( 150 ),
        stepsIncrement( 0 ),
        pendingValueChange( false ),
        borderWidth( 2 ),
        spacing( 4 ),
        scalePosition( QwtSlider::TrailingScale ),
        hasTrough( true ),
        hasGroove( false ),
        mouseOffset( 0 )
    {
    }

    int repeatTimerId;
    bool timerTick;
    int updateInterval;
    int stepsIncrement;
    bool pendingValueChange;

pixhawk's avatar
pixhawk committed
92
93
    QRect sliderRect;

Bryant's avatar
Bryant committed
94
    QSize handleSize;
pixhawk's avatar
pixhawk committed
95
    int borderWidth;
Bryant's avatar
Bryant committed
96
    int spacing;
pixhawk's avatar
pixhawk committed
97

Bryant's avatar
Bryant committed
98
99
100
101
102
103
104
    Qt::Orientation orientation;
    QwtSlider::ScalePosition scalePosition;

    bool hasTrough;
    bool hasGroove;

    int mouseOffset;
pixhawk's avatar
pixhawk committed
105
106
107
108

    mutable QSize sizeHintCache;
};
/*!
Bryant's avatar
Bryant committed
109
110
111
112
113
114
115
116
  Construct vertical slider in QwtSlider::Trough style
  with a scale to the left. 

  The scale is initialized to [0.0, 100.0] and the value set to 0.0.

  \param parent Parent widget

  \sa setOrientation(), setScalePosition(), setBackgroundStyle()
pixhawk's avatar
pixhawk committed
117
*/
Bryant's avatar
Bryant committed
118
119
QwtSlider::QwtSlider( QWidget *parent ):
    QwtAbstractSlider( parent )
pixhawk's avatar
pixhawk committed
120
{
Bryant's avatar
Bryant committed
121
    initSlider( Qt::Vertical );
pixhawk's avatar
pixhawk committed
122
123
124
}

/*!
Bryant's avatar
Bryant committed
125
126
127
128
  Construct a slider in QwtSlider::Trough style

  When orientation is Qt::Vertical the scale will be aligned to
  the left - otherwise at the the top of the slider.
pixhawk's avatar
pixhawk committed
129

Bryant's avatar
Bryant committed
130
  The scale is initialized to [0.0, 100.0] and the value set to 0.0.
pixhawk's avatar
pixhawk committed
131

Bryant's avatar
Bryant committed
132
133
  \param parent Parent widget
  \param orientation Orientation of the slider. 
pixhawk's avatar
pixhawk committed
134
*/
Bryant's avatar
Bryant committed
135
136
QwtSlider::QwtSlider( Qt::Orientation orientation, QWidget *parent ):
    QwtAbstractSlider( parent )
pixhawk's avatar
pixhawk committed
137
{
Bryant's avatar
Bryant committed
138
    initSlider( orientation );
pixhawk's avatar
pixhawk committed
139
140
}

Bryant's avatar
Bryant committed
141
142
//! Destructor
QwtSlider::~QwtSlider()
pixhawk's avatar
pixhawk committed
143
{
Bryant's avatar
Bryant committed
144
145
    delete d_data;
}
pixhawk's avatar
pixhawk committed
146

Bryant's avatar
Bryant committed
147
148
149
150
151
152
void QwtSlider::initSlider( Qt::Orientation orientation )
{
    if ( orientation == Qt::Vertical )
        setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
    else
        setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
pixhawk's avatar
pixhawk committed
153

Bryant's avatar
Bryant committed
154
    setAttribute( Qt::WA_WState_OwnSizePolicy, false );
pixhawk's avatar
pixhawk committed
155
156
157

    d_data = new QwtSlider::PrivateData;

Bryant's avatar
Bryant committed
158
    d_data->orientation = orientation;
pixhawk's avatar
pixhawk committed
159

Bryant's avatar
Bryant committed
160
161
162
    scaleDraw()->setAlignment( 
        qwtScaleDrawAlignment( orientation, d_data->scalePosition ) );
    scaleDraw()->setLength( 100 );
pixhawk's avatar
pixhawk committed
163

Bryant's avatar
Bryant committed
164
165
    setScale( 0.0, 100.0 );
    setValue( 0.0 );
pixhawk's avatar
pixhawk committed
166
167
168
169
}

/*!
  \brief Set the orientation.
Bryant's avatar
Bryant committed
170
  \param orientation Allowed values are Qt::Horizontal and Qt::Vertical.
171

Bryant's avatar
Bryant committed
172
  \sa orientation(), scalePosition()
pixhawk's avatar
pixhawk committed
173
*/
Bryant's avatar
Bryant committed
174
void QwtSlider::setOrientation( Qt::Orientation orientation )
pixhawk's avatar
pixhawk committed
175
{
Bryant's avatar
Bryant committed
176
    if ( orientation == d_data->orientation )
pixhawk's avatar
pixhawk committed
177
178
        return;

Bryant's avatar
Bryant committed
179
    d_data->orientation = orientation;
pixhawk's avatar
pixhawk committed
180

Bryant's avatar
Bryant committed
181
182
183
184
    scaleDraw()->setAlignment( 
        qwtScaleDrawAlignment( orientation, d_data->scalePosition ) );

    if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
pixhawk's avatar
pixhawk committed
185
186
187
    {
        QSizePolicy sp = sizePolicy();
        sp.transpose();
Bryant's avatar
Bryant committed
188
        setSizePolicy( sp );
pixhawk's avatar
pixhawk committed
189

Bryant's avatar
Bryant committed
190
        setAttribute( Qt::WA_WState_OwnSizePolicy, false );
pixhawk's avatar
pixhawk committed
191
192
    }

Bryant's avatar
Bryant committed
193
194
    if ( testAttribute( Qt::WA_WState_Polished ) )
        layoutSlider( true );
pixhawk's avatar
pixhawk committed
195
196
197
}

/*!
Bryant's avatar
Bryant committed
198
199
200
201
202
203
204
  \return Orientation
  \sa setOrientation()
*/
Qt::Orientation QwtSlider::orientation() const
{
    return d_data->orientation;
}
pixhawk's avatar
pixhawk committed
205

Bryant's avatar
Bryant committed
206
207
208
/*!
  \brief Change the position of the scale
  \param scalePosition Position of the scale.
pixhawk's avatar
pixhawk committed
209

Bryant's avatar
Bryant committed
210
  \sa ScalePosition, scalePosition()
pixhawk's avatar
pixhawk committed
211
*/
Bryant's avatar
Bryant committed
212
void QwtSlider::setScalePosition( ScalePosition scalePosition )
pixhawk's avatar
pixhawk committed
213
{
Bryant's avatar
Bryant committed
214
    if ( d_data->scalePosition == scalePosition )
pixhawk's avatar
pixhawk committed
215
216
        return;

Bryant's avatar
Bryant committed
217
218
219
    d_data->scalePosition = scalePosition;
    scaleDraw()->setAlignment( 
        qwtScaleDrawAlignment( d_data->orientation, scalePosition ) );
pixhawk's avatar
pixhawk committed
220

Bryant's avatar
Bryant committed
221
222
    if ( testAttribute( Qt::WA_WState_Polished ) )
        layoutSlider( true );
pixhawk's avatar
pixhawk committed
223
224
}

Bryant's avatar
Bryant committed
225
226
227
228
229
/*! 
  \return Position of the scale
  \sa setScalePosition()
 */
QwtSlider::ScalePosition QwtSlider::scalePosition() const
pixhawk's avatar
pixhawk committed
230
{
Bryant's avatar
Bryant committed
231
    return d_data->scalePosition;
pixhawk's avatar
pixhawk committed
232
233
234
235
}

/*!
  \brief Change the slider's border width
Bryant's avatar
Bryant committed
236
237
238
239
240
241

  The border width is used for drawing the slider handle and the
  trough.

  \param width Border width
  \sa borderWidth()
pixhawk's avatar
pixhawk committed
242
*/
Bryant's avatar
Bryant committed
243
void QwtSlider::setBorderWidth( int width )
pixhawk's avatar
pixhawk committed
244
{
Bryant's avatar
Bryant committed
245
246
247
248
249
250
    if ( width < 0 )
        width = 0;

    if ( width != d_data->borderWidth )
    {
        d_data->borderWidth = width;
pixhawk's avatar
pixhawk committed
251

Bryant's avatar
Bryant committed
252
253
        if ( testAttribute( Qt::WA_WState_Polished ) )
            layoutSlider( true );
pixhawk's avatar
pixhawk committed
254
255
256
257
    }
}

/*!
Bryant's avatar
Bryant committed
258
259
  \return the border width.
  \sa setBorderWidth()
pixhawk's avatar
pixhawk committed
260
*/
Bryant's avatar
Bryant committed
261
int QwtSlider::borderWidth() const
pixhawk's avatar
pixhawk committed
262
{
Bryant's avatar
Bryant committed
263
264
265
266
267
268
269
270
271
272
    return d_data->borderWidth;
}

/*!
  \brief Change the spacing between trough and scale

  A spacing of 0 means, that the backbone of the scale is covered
  by the trough.

  The default setting is 4 pixels.
pixhawk's avatar
pixhawk committed
273

Bryant's avatar
Bryant committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  \param spacing Number of pixels
  \sa spacing();
*/
void QwtSlider::setSpacing( int spacing )
{
    if ( spacing <= 0 )
        spacing = 0;

    if ( spacing != d_data->spacing  )
    {
        d_data->spacing = spacing;

        if ( testAttribute( Qt::WA_WState_Polished ) )
            layoutSlider( true );
pixhawk's avatar
pixhawk committed
288
289
290
291
    }
}

/*!
Bryant's avatar
Bryant committed
292
293
  \return Number of pixels between slider and scale
  \sa setSpacing()
pixhawk's avatar
pixhawk committed
294
*/
Bryant's avatar
Bryant committed
295
int QwtSlider::spacing() const
pixhawk's avatar
pixhawk committed
296
{
Bryant's avatar
Bryant committed
297
298
299
300
301
302
303
304
305
306
    return d_data->spacing;
}

/*!
  \brief Set the slider's handle size

  When the size is empty the slider handle will be painted with a
  default size depending on its orientation() and backgroundStyle().

  \param size New size
pixhawk's avatar
pixhawk committed
307

Bryant's avatar
Bryant committed
308
309
310
311
312
313
314
315
316
317
  \sa handleSize()
*/
void QwtSlider::setHandleSize( const QSize &size )
{
    if ( size != d_data->handleSize )
    {
        d_data->handleSize = size;

        if ( testAttribute( Qt::WA_WState_Polished ) )
            layoutSlider( true );
pixhawk's avatar
pixhawk committed
318
319
320
    }
}

Bryant's avatar
Bryant committed
321
322
323
324
325
326
327
328
329
/*!
  \return Size of the handle.
  \sa setHandleSize()
*/
QSize QwtSlider::handleSize() const
{
    return d_data->handleSize;
}

pixhawk's avatar
pixhawk committed
330
331
332
333
334
335
336
/*!
  \brief Set a scale draw

  For changing the labels of the scales, it
  is necessary to derive from QwtScaleDraw and
  overload QwtScaleDraw::label().

337
  \param scaleDraw ScaleDraw object, that has to be created with
Bryant's avatar
Bryant committed
338
                   new and will be deleted in ~QwtSlider() or the next
pixhawk's avatar
pixhawk committed
339
                   call of setScaleDraw().
Bryant's avatar
Bryant committed
340
341

  \sa scaleDraw()
pixhawk's avatar
pixhawk committed
342
*/
Bryant's avatar
Bryant committed
343
void QwtSlider::setScaleDraw( QwtScaleDraw *scaleDraw )
pixhawk's avatar
pixhawk committed
344
345
346
347
348
349
{
    const QwtScaleDraw *previousScaleDraw = this->scaleDraw();
    if ( scaleDraw == NULL || scaleDraw == previousScaleDraw )
        return;

    if ( previousScaleDraw )
Bryant's avatar
Bryant committed
350
351
352
        scaleDraw->setAlignment( previousScaleDraw->alignment() );

    setAbstractScaleDraw( scaleDraw );
pixhawk's avatar
pixhawk committed
353

Bryant's avatar
Bryant committed
354
355
    if ( testAttribute( Qt::WA_WState_Polished ) )
        layoutSlider( true );
pixhawk's avatar
pixhawk committed
356
357
358
359
360
361
362
363
}

/*!
  \return the scale draw of the slider
  \sa setScaleDraw()
*/
const QwtScaleDraw *QwtSlider::scaleDraw() const
{
Bryant's avatar
Bryant committed
364
    return static_cast<const QwtScaleDraw *>( abstractScaleDraw() );
pixhawk's avatar
pixhawk committed
365
366
367
368
369
370
371
372
}

/*!
  \return the scale draw of the slider
  \sa setScaleDraw()
*/
QwtScaleDraw *QwtSlider::scaleDraw()
{
Bryant's avatar
Bryant committed
373
    return static_cast<QwtScaleDraw *>( abstractScaleDraw() );
pixhawk's avatar
pixhawk committed
374
375
376
377
378
}

//! Notify changed scale
void QwtSlider::scaleChange()
{
Bryant's avatar
Bryant committed
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
    QwtAbstractSlider::scaleChange();

    if ( testAttribute( Qt::WA_WState_Polished ) )
        layoutSlider( true );
}

/*!
  \brief Specify the update interval for automatic scrolling

  The minimal accepted value is 50 ms.

  \param interval Update interval in milliseconds

  \sa setUpdateInterval()
*/
void QwtSlider::setUpdateInterval( int interval )
{
    d_data->updateInterval = qMax( interval, 50 );
}

/*!
  \return Update interval in milliseconds for automatic scrolling
  \sa setUpdateInterval()
 */
int QwtSlider::updateInterval() const
{
    return d_data->updateInterval;
}

/*!
   Draw the slider into the specified rectangle.

   \param painter Painter
   \param sliderRect Bounding rectangle of the slider
*/
void QwtSlider::drawSlider( 
    QPainter *painter, const QRect &sliderRect ) const
{
    QRect innerRect( sliderRect );

    if ( d_data->hasTrough )
    {
        const int bw = d_data->borderWidth;
        innerRect = sliderRect.adjusted( bw, bw, -bw, -bw );

        painter->fillRect( innerRect, palette().brush( QPalette::Mid ) );
        qDrawShadePanel( painter, sliderRect, palette(), true, bw, NULL );
    }

    const QSize handleSize = qwtHandleSize( d_data->handleSize,
        d_data->orientation, d_data->hasTrough );

    if ( d_data->hasGroove )
    {
        const int slotExtent = 4;
        const int slotMargin = 4;

        QRect slotRect; 
        if ( orientation() == Qt::Horizontal )
        {
            int slotOffset = qMax( 1, handleSize.width() / 2 - slotMargin );
            int slotHeight = slotExtent + ( innerRect.height() % 2 );

            slotRect.setWidth( innerRect.width() - 2 * slotOffset );
            slotRect.setHeight( slotHeight );
pixhawk's avatar
pixhawk committed
444
        }
Bryant's avatar
Bryant committed
445
446
447
448
449
450
451
        else
        {
            int slotOffset = qMax( 1, handleSize.height() / 2 - slotMargin );
            int slotWidth = slotExtent + ( innerRect.width() % 2 );

            slotRect.setWidth( slotWidth );
            slotRect.setHeight( innerRect.height() - 2 * slotOffset );
pixhawk's avatar
pixhawk committed
452

Bryant's avatar
Bryant committed
453
454
455
456
457
458
        }

        slotRect.moveCenter( innerRect.center() );

        QBrush brush = palette().brush( QPalette::Dark );
        qDrawShadePanel( painter, slotRect, palette(), true, 1 , &brush );
pixhawk's avatar
pixhawk committed
459
460
461
    }

    if ( isValid() )
Bryant's avatar
Bryant committed
462
        drawHandle( painter, handleRect(), transform( value() ) );
pixhawk's avatar
pixhawk committed
463
464
}

Bryant's avatar
Bryant committed
465
466
467
468
469
470
471
472
473
/*!
  Draw the thumb at a position

  \param painter Painter
  \param handleRect Bounding rectangle of the handle
  \param pos Position of the handle marker in widget coordinates
*/
void QwtSlider::drawHandle( QPainter *painter, 
    const QRect &handleRect, int pos ) const
pixhawk's avatar
pixhawk committed
474
{
Bryant's avatar
Bryant committed
475
476
477
478
479
480
    const int bw = d_data->borderWidth;

    qDrawShadePanel( painter, 
        handleRect, palette(), false, bw,
        &palette().brush( QPalette::Button ) );

pixhawk's avatar
pixhawk committed
481
    pos++; // shade line points one pixel below
Bryant's avatar
Bryant committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
    if ( orientation() == Qt::Horizontal )
    {
        qDrawShadeLine( painter, pos, handleRect.top() + bw,
            pos, handleRect.bottom() - bw, palette(), true, 1 );
    }
    else // Vertical
    {
        qDrawShadeLine( painter, handleRect.left() + bw, pos,
            handleRect.right() - bw, pos, palette(), true, 1 );
    }
}

/*!
  \brief Determine what to do when the user presses a mouse button.

  \param pos Mouse position

  \retval True, when handleRect() contains pos 
  \sa scrolledTo()
pixhawk's avatar
pixhawk committed
501
*/
Bryant's avatar
Bryant committed
502
bool QwtSlider::isScrollPosition( const QPoint &pos ) const
pixhawk's avatar
pixhawk committed
503
{
Bryant's avatar
Bryant committed
504
505
506
507
508
509
510
    if ( handleRect().contains( pos ) )
    {
        const double v = ( orientation() == Qt::Horizontal ) 
            ? pos.x() : pos.y();

        d_data->mouseOffset = v - transform( value() );
        return true;
pixhawk's avatar
pixhawk committed
511
512
    }

Bryant's avatar
Bryant committed
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
    return false;
}

/*!
  \brief Determine the value for a new position of the
         slider handle.

  \param pos Mouse position

  \return Value for the mouse position
  \sa isScrollPosition()
*/
double QwtSlider::scrolledTo( const QPoint &pos ) const
{
    int p = ( orientation() == Qt::Horizontal ) 
        ? pos.x() : pos.y();

    p -= d_data->mouseOffset;

    int min = transform( lowerBound() );
    int max = transform( upperBound() );
    if ( min > max )
        qSwap( min, max );
pixhawk's avatar
pixhawk committed
536

Bryant's avatar
Bryant committed
537
538
539
540
541
542
543
544
545
546
547
548
549
550
    p = qBound( min, p, max );

    return invTransform( p );
}

/*!
   Mouse press event handler
   \param event Mouse event
*/
void QwtSlider::mousePressEvent( QMouseEvent *event )
{
    if ( isReadOnly() )
    {
        event->ignore();
pixhawk's avatar
pixhawk committed
551
552
553
        return;
    }

Bryant's avatar
Bryant committed
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
    const QPoint pos = event->pos();

    if ( isValid() && d_data->sliderRect.contains( pos ) )
    {
        if ( !handleRect().contains( pos ) )
        {
            const int markerPos = transform( value() );

            d_data->stepsIncrement = pageSteps();

            if ( d_data->orientation == Qt::Horizontal )
            {
                if ( pos.x() < markerPos )
                    d_data->stepsIncrement = -d_data->stepsIncrement;
            }
            else
            {
                if ( pos.y() < markerPos )
                    d_data->stepsIncrement = -d_data->stepsIncrement;
            }

            if ( isInverted() )
                d_data->stepsIncrement = -d_data->stepsIncrement;

            d_data->timerTick = false;
            d_data->repeatTimerId = startTimer( qMax( 250, 2 * updateInterval() ) );

            return;
        }
    }

    QwtAbstractSlider::mousePressEvent( event );
}

/*!
   Mouse release event handler
   \param event Mouse event
*/
void QwtSlider::mouseReleaseEvent( QMouseEvent *event )
{
    if ( d_data->repeatTimerId > 0 )
    {
        killTimer( d_data->repeatTimerId );
        d_data->repeatTimerId = 0;
        d_data->timerTick = false;
        d_data->stepsIncrement = 0;
    }

    if ( d_data->pendingValueChange )
    {
        d_data->pendingValueChange = false;
        Q_EMIT valueChanged( value() );
    }
pixhawk's avatar
pixhawk committed
607

Bryant's avatar
Bryant committed
608
    QwtAbstractSlider::mouseReleaseEvent( event );
pixhawk's avatar
pixhawk committed
609
610
}

Bryant's avatar
Bryant committed
611
612
613
614
615
616
617
618
619
/*!
   Timer event handler

   Handles the timer, when the mouse stays pressed
   inside the sliderRect().

   \param event Mouse event
*/  
void QwtSlider::timerEvent( QTimerEvent *event )
pixhawk's avatar
pixhawk committed
620
{
Bryant's avatar
Bryant committed
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
    if ( event->timerId() != d_data->repeatTimerId )
    {
        QwtAbstractSlider::timerEvent( event );
        return;
    }

    if ( !isValid() )
    {
        killTimer( d_data->repeatTimerId );
        d_data->repeatTimerId = 0;
        return;
    }

    const double v = value();
    incrementValue( d_data->stepsIncrement );

    if ( v != value() )
    {
        if ( isTracking() )
            Q_EMIT valueChanged( value() );
        else
            d_data->pendingValueChange = true;

        Q_EMIT sliderMoved( value() );
pixhawk's avatar
pixhawk committed
645
    }
Bryant's avatar
Bryant committed
646
647
648
649
650
651
652
653
654

    if ( !d_data->timerTick )
    {
        // restart the timer with a shorter interval
        killTimer( d_data->repeatTimerId );
        d_data->repeatTimerId = startTimer( updateInterval() );
        
        d_data->timerTick = true;
    }   
pixhawk's avatar
pixhawk committed
655
656
}

Bryant's avatar
Bryant committed
657
658
659
660
661
/*!
   Qt paint event handler
   \param event Paint event
*/
void QwtSlider::paintEvent( QPaintEvent *event )
pixhawk's avatar
pixhawk committed
662
{
Bryant's avatar
Bryant committed
663
664
665
666
667
668
669
670
671
672
673
    QPainter painter( this );
    painter.setClipRegion( event->region() );

    QStyleOption opt;
    opt.init(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);

    if ( d_data->scalePosition != QwtSlider::NoScale )
    {
        if ( !d_data->sliderRect.contains( event->rect() ) )
            scaleDraw()->draw( &painter, palette() );
pixhawk's avatar
pixhawk committed
674
675
    }

Bryant's avatar
Bryant committed
676
    drawSlider( &painter, d_data->sliderRect );
pixhawk's avatar
pixhawk committed
677
678

    if ( hasFocus() )
Bryant's avatar
Bryant committed
679
        QwtPainter::drawFocusRect( &painter, this, d_data->sliderRect );
pixhawk's avatar
pixhawk committed
680
681
}

Bryant's avatar
Bryant committed
682
683
684
685
686
/*!
   Qt resize event handler
   \param event Resize event
*/
void QwtSlider::resizeEvent( QResizeEvent *event )
pixhawk's avatar
pixhawk committed
687
{
Bryant's avatar
Bryant committed
688
689
    Q_UNUSED( event );

pixhawk's avatar
pixhawk committed
690
691
692
    layoutSlider( false );
}

Bryant's avatar
Bryant committed
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
/*!
   Handles QEvent::StyleChange and QEvent::FontChange events
   \param event Change event
*/
void QwtSlider::changeEvent( QEvent *event )
{
    if ( event->type() == QEvent::StyleChange || 
        event->type() == QEvent::FontChange )
    {
        if ( testAttribute( Qt::WA_WState_Polished ) )
            layoutSlider( true );
    }

    QwtAbstractSlider::changeEvent( event );
}

pixhawk's avatar
pixhawk committed
709
710
/*!
  Recalculate the slider's geometry and layout based on
Bryant's avatar
Bryant committed
711
712
  the current geometry and fonts.

pixhawk's avatar
pixhawk committed
713
714
715
716
717
  \param update_geometry  notify the layout system and call update
         to redraw the scale
*/
void QwtSlider::layoutSlider( bool update_geometry )
{
Bryant's avatar
Bryant committed
718
719
720
    int bw = 0;
    if ( d_data->hasTrough )
        bw = d_data->borderWidth;
pixhawk's avatar
pixhawk committed
721

Bryant's avatar
Bryant committed
722
723
    const QSize handleSize = qwtHandleSize( d_data->handleSize,
        d_data->orientation, d_data->hasTrough );
pixhawk's avatar
pixhawk committed
724

Bryant's avatar
Bryant committed
725
    QRect sliderRect = contentsRect();
pixhawk's avatar
pixhawk committed
726

Bryant's avatar
Bryant committed
727
728
729
730
    /*
       The marker line of the handle needs to be aligned to
       the scale. But the marker is in the center 
       and we need space enough to display the rest of the handle.
pixhawk's avatar
pixhawk committed
731

Bryant's avatar
Bryant committed
732
733
734
       But the scale itself usually needs margins for displaying
       the tick labels, that also might needs space beyond the
       backbone.
735

Bryant's avatar
Bryant committed
736
737
738
       Now it depends on what needs more margins. If it is the
       slider the scale gets shrunk, otherwise the slider.
     */
739

Bryant's avatar
Bryant committed
740
741
742
743
744
745
746
747
    int scaleMargin = 0;
    if ( d_data->scalePosition != QwtSlider::NoScale )
    {
        int d1, d2;
        scaleDraw()->getBorderDistHint( font(), d1, d2 );

        scaleMargin = qMax( d1, d2 ) - bw;
    }
748

Bryant's avatar
Bryant committed
749
    int scaleX, scaleY, scaleLength;
750

Bryant's avatar
Bryant committed
751
752
753
754
755
756
757
758
    if ( d_data->orientation == Qt::Horizontal )
    {
        const int handleMargin = handleSize.width() / 2 - 1;
        if ( scaleMargin > handleMargin )
        {
            int off = scaleMargin - handleMargin;
            sliderRect.adjust( off, 0, -off, 0 );
        }
759

Bryant's avatar
Bryant committed
760
761
762
763
764
765
766
767
768
769
        scaleX = sliderRect.left() + bw + handleSize.width() / 2 - 1;
        scaleLength = sliderRect.width() - handleSize.width();
    }
    else
    {
        int handleMargin = handleSize.height() / 2 - 1;
        if ( scaleMargin > handleMargin )
        {
            int off = scaleMargin - handleMargin;
            sliderRect.adjust( 0, off, 0, -off );
770
771
        }

Bryant's avatar
Bryant committed
772
773
774
775
776
        scaleY = sliderRect.top() + bw + handleSize.height() / 2 - 1;
        scaleLength = sliderRect.height() - handleSize.height();
    }

    scaleLength -= 2 * bw;
777

Bryant's avatar
Bryant committed
778
    // now align slider and scale according to the ScalePosition
779

Bryant's avatar
Bryant committed
780
781
782
783
784
785
786
787
    if ( d_data->orientation == Qt::Horizontal )
    {
        const int h = handleSize.height() + 2 * bw;

        if ( d_data->scalePosition == QwtSlider::TrailingScale )
        {
            sliderRect.setTop( sliderRect.bottom() + 1 - h );
            scaleY = sliderRect.top() - d_data->spacing;
788
        }
Bryant's avatar
Bryant committed
789
790
791
792
        else
        {
            sliderRect.setHeight( h );
            scaleY = sliderRect.bottom() + 1 + d_data->spacing;
pixhawk's avatar
pixhawk committed
793
        }
Bryant's avatar
Bryant committed
794
795
796
797
798
799
800
801
802
803
804
805
806
807
    }
    else // Qt::Vertical
    {
        const int w = handleSize.width() + 2 * bw;

        if ( d_data->scalePosition == QwtSlider::LeadingScale )
        {
            sliderRect.setWidth( w );
            scaleX = sliderRect.right() + 1 + d_data->spacing;
        }
        else
        {
            sliderRect.setLeft( sliderRect.right() + 1 - w );
            scaleX = sliderRect.left() - d_data->spacing;
pixhawk's avatar
pixhawk committed
808
809
810
        }
    }

Bryant's avatar
Bryant committed
811
    d_data->sliderRect = sliderRect;
pixhawk's avatar
pixhawk committed
812

Bryant's avatar
Bryant committed
813
814
    scaleDraw()->move( scaleX, scaleY );
    scaleDraw()->setLength( scaleLength );
pixhawk's avatar
pixhawk committed
815

Bryant's avatar
Bryant committed
816
817
    if ( update_geometry )
    {
pixhawk's avatar
pixhawk committed
818
819
820
821
822
823
        d_data->sizeHintCache = QSize(); // invalidate
        updateGeometry();
        update();
    }
}

Bryant's avatar
Bryant committed
824
825
/*!
  En/Disable the trough
pixhawk's avatar
pixhawk committed
826

Bryant's avatar
Bryant committed
827
828
  The slider can be cutomized by showing a trough for the
  handle.
pixhawk's avatar
pixhawk committed
829

Bryant's avatar
Bryant committed
830
831
832
833
  \param on When true, the groove is visible
  \sa hasTrough(), setGroove()
 */
void QwtSlider::setTrough( bool on )
pixhawk's avatar
pixhawk committed
834
{
Bryant's avatar
Bryant committed
835
836
837
    if ( d_data->hasTrough != on )
    {
        d_data->hasTrough = on;
pixhawk's avatar
pixhawk committed
838

Bryant's avatar
Bryant committed
839
840
        if ( testAttribute( Qt::WA_WState_Polished ) )
            layoutSlider( true );
pixhawk's avatar
pixhawk committed
841
842
843
844
    }
}

/*!
Bryant's avatar
Bryant committed
845
846
847
848
  \return True, when the trough is visisble
  \sa setTrough(), hasGroove()
 */
bool QwtSlider::hasTrough() const
pixhawk's avatar
pixhawk committed
849
{
Bryant's avatar
Bryant committed
850
    return d_data->hasTrough;
pixhawk's avatar
pixhawk committed
851
852
853
}

/*!
Bryant's avatar
Bryant committed
854
  En/Disable the groove
pixhawk's avatar
pixhawk committed
855

Bryant's avatar
Bryant committed
856
857
  The slider can be cutomized by showing a groove for the
  handle.
pixhawk's avatar
pixhawk committed
858

Bryant's avatar
Bryant committed
859
860
861
862
  \param on When true, the groove is visible
  \sa hasGroove(), setThrough()
 */
void QwtSlider::setGroove( bool on )
pixhawk's avatar
pixhawk committed
863
{
Bryant's avatar
Bryant committed
864
865
866
867
868
869
870
    if ( d_data->hasGroove != on )
    {
        d_data->hasGroove = on;
        
        if ( testAttribute( Qt::WA_WState_Polished ) )
            layoutSlider( true );
    }
pixhawk's avatar
pixhawk committed
871
872
873
}

/*!
Bryant's avatar
Bryant committed
874
875
876
877
  \return True, when the groove is visisble
  \sa setGroove(), hasTrough()
 */
bool QwtSlider::hasGroove() const
pixhawk's avatar
pixhawk committed
878
{
Bryant's avatar
Bryant committed
879
880
    return d_data->hasGroove;
} 
pixhawk's avatar
pixhawk committed
881
882

/*!
Bryant's avatar
Bryant committed
883
  \return minimumSizeHint()
pixhawk's avatar
pixhawk committed
884
885
886
*/
QSize QwtSlider::sizeHint() const
{
Bryant's avatar
Bryant committed
887
888
    const QSize hint = minimumSizeHint();
    return hint.expandedTo( QApplication::globalStrut() );
pixhawk's avatar
pixhawk committed
889
890
891
}

/*!
Bryant's avatar
Bryant committed
892
893
  \return Minimum size hint
  \sa sizeHint()
pixhawk's avatar
pixhawk committed
894
895
896
*/
QSize QwtSlider::minimumSizeHint() const
{
Bryant's avatar
Bryant committed
897
    if ( !d_data->sizeHintCache.isEmpty() )
pixhawk's avatar
pixhawk committed
898
899
        return d_data->sizeHintCache;

Bryant's avatar
Bryant committed
900
901
902
903
904
905
906
907
908
    const QSize handleSize = qwtHandleSize( d_data->handleSize,
        d_data->orientation, d_data->hasTrough );

    int bw = 0;
    if ( d_data->hasTrough )
        bw = d_data->borderWidth;

    int sliderLength = 0; 
    int scaleExtent = 0;
pixhawk's avatar
pixhawk committed
909

Bryant's avatar
Bryant committed
910
911
    if ( d_data->scalePosition != QwtSlider::NoScale )
    {
pixhawk's avatar
pixhawk committed
912
        int d1, d2;
Bryant's avatar
Bryant committed
913
        scaleDraw()->getBorderDistHint( font(), d1, d2 );
pixhawk's avatar
pixhawk committed
914

Bryant's avatar
Bryant committed
915
        const int scaleBorderDist = 2 * ( qMax( d1, d2 ) - bw );
pixhawk's avatar
pixhawk committed
916

Bryant's avatar
Bryant committed
917
918
919
920
921
        int handleBorderDist;
        if ( d_data->orientation == Qt::Horizontal )
            handleBorderDist = handleSize.width();
        else
            handleBorderDist = handleSize.height();
pixhawk's avatar
pixhawk committed
922

Bryant's avatar
Bryant committed
923
924
925
926
927
928
        sliderLength = scaleDraw()->minLength( font() );
        if ( handleBorderDist > scaleBorderDist )
        {
            // We need additional space for the overlapping handle
            sliderLength += handleBorderDist - scaleBorderDist;
        }
pixhawk's avatar
pixhawk committed
929

Bryant's avatar
Bryant committed
930
931
        scaleExtent += d_data->spacing;
        scaleExtent += qCeil( scaleDraw()->extent( font() ) );
pixhawk's avatar
pixhawk committed
932
933
    }

Bryant's avatar
Bryant committed
934
    sliderLength = qMax( sliderLength, 84 ); // from QSlider
pixhawk's avatar
pixhawk committed
935

Bryant's avatar
Bryant committed
936
937
    int w = 0;
    int h = 0;
pixhawk's avatar
pixhawk committed
938

Bryant's avatar
Bryant committed
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
    if ( d_data->orientation == Qt::Horizontal )
    {
        w = sliderLength;
        h = handleSize.height() + 2 * bw + scaleExtent;
    }
    else
    {
        w = handleSize.width() + 2 * bw + scaleExtent;
        h = sliderLength;
    }

    // finally add margins
    int left, right, top, bottom;
    getContentsMargins( &left, &top, &right, &bottom );

    w += left + right;
    h += top + bottom;

    d_data->sizeHintCache = QSize( w, h );
pixhawk's avatar
pixhawk committed
958
959
    return d_data->sizeHintCache;
}
Bryant's avatar
Bryant committed
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991

/*!
   \return Bounding rectangle of the slider handle
 */
QRect QwtSlider::handleRect() const
{
    if ( !isValid() )
        return QRect();

    const int markerPos = transform( value() );

    QPoint center = d_data->sliderRect.center();
    if ( d_data->orientation == Qt::Horizontal )
        center.setX( markerPos );
    else
        center.setY( markerPos );

    QRect rect;
    rect.setSize( qwtHandleSize( d_data->handleSize,
        d_data->orientation, d_data->hasTrough ) );
    rect.moveCenter( center );

    return rect;
}

/*!
 \return Bounding rectangle of the slider - without the scale
 */
QRect QwtSlider::sliderRect() const
{
    return d_data->sliderRect;
}