1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
3
* Copyright (C) 1997 Josef Wilgen
4
* Copyright (C) 2002 Uwe Rathmann
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
*****************************************************************************/
14
#include <qdrawutil.h>
16
#include "qwt_painter.h"
17
#include "qwt_paint_buffer.h"
18
#include "qwt_scale_draw.h"
19
#include "qwt_scale_map.h"
20
#include "qwt_slider.h"
22
class QwtSlider::PrivateData
34
QwtSlider::ScalePos scalePos;
35
QwtSlider::BGSTYLE bgStyle;
38
Scale and values might have different maps. This is
39
confusing and I can't see strong arguments for such
42
QwtScaleMap map; // linear map
43
mutable QSize sizeHintCache;
48
\param parent parent widget
49
\param orientation Orientation of the slider. Can be Qt::Horizontal
50
or Qt::Vertical. Defaults to Qt::Horizontal.
51
\param scalePos Position of the scale.
52
Defaults to QwtSlider::NoScale.
53
\param bgStyle Background style. QwtSlider::BgTrough draws the
54
slider button in a trough, QwtSlider::BgSlot draws
55
a slot underneath the button. An or-combination of both
56
may also be used. The default is QwtSlider::BgTrough.
58
QwtSlider enforces valid combinations of its orientation and scale position.
59
If the combination is invalid, the scale position will be set to NoScale.
60
Valid combinations are:
61
- Qt::Horizonal with NoScale, TopScale, or BottomScale;
62
- Qt::Vertical with NoScale, LeftScale, or RightScale.
64
QwtSlider::QwtSlider(QWidget *parent,
65
Qt::Orientation orientation, ScalePos scalePos, BGSTYLE bgStyle):
66
QwtAbstractSlider(orientation, parent)
68
initSlider(orientation, scalePos, bgStyle);
71
#if QT_VERSION < 0x040000
75
Build a horizontal slider with no scale and BgTrough as
78
\param parent parent widget
79
\param name Object name
81
QwtSlider::QwtSlider(QWidget *parent, const char* name):
82
QwtAbstractSlider(Qt::Horizontal, parent)
85
initSlider(Qt::Horizontal, NoScale, BgTrough);
89
void QwtSlider::initSlider(Qt::Orientation orientation,
90
ScalePos scalePos, BGSTYLE bgStyle)
92
if (orientation == Qt::Vertical)
93
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
95
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
97
#if QT_VERSION >= 0x040000
98
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
100
clearWState( WState_OwnSizePolicy );
104
#if QT_VERSION < 0x040000
105
setWFlags(Qt::WNoAutoErase);
108
d_data = new QwtSlider::PrivateData;
110
d_data->borderWidth = 2;
111
d_data->scaleDist = 4;
112
d_data->scalePos = scalePos;
115
d_data->bgStyle = bgStyle;
117
if (bgStyle == BgSlot)
119
d_data->thumbLength = 16;
120
d_data->thumbWidth = 30;
124
d_data->thumbLength = 31;
125
d_data->thumbWidth = 16;
128
d_data->sliderRect.setRect(0,0,8,8);
130
QwtScaleDraw::Alignment align;
131
if ( orientation == Qt::Vertical )
133
// enforce a valid combination of scale position and orientation
134
if ((d_data->scalePos == BottomScale) || (d_data->scalePos == TopScale))
135
d_data->scalePos = NoScale;
136
// adopt the policy of layoutSlider (NoScale lays out like Left)
137
if (d_data->scalePos == RightScale)
138
align = QwtScaleDraw::RightScale;
140
align = QwtScaleDraw::LeftScale;
144
// enforce a valid combination of scale position and orientation
145
if ((d_data->scalePos == LeftScale) || (d_data->scalePos == RightScale))
146
d_data->scalePos = NoScale;
147
// adopt the policy of layoutSlider (NoScale lays out like Bottom)
148
if (d_data->scalePos == TopScale)
149
align = QwtScaleDraw::TopScale;
151
align = QwtScaleDraw::BottomScale;
154
scaleDraw()->setAlignment(align);
155
scaleDraw()->setLength(100);
157
setRange(0.0, 100.0, 1.0);
161
QwtSlider::~QwtSlider()
167
\brief Set the orientation.
168
\param o Orientation. Allowed values are Qt::Horizontal and Qt::Vertical.
170
If the new orientation and the old scale position are an invalid combination,
171
the scale position will be set to QwtSlider::NoScale.
172
\sa QwtAbstractSlider::orientation()
174
void QwtSlider::setOrientation(Qt::Orientation o)
176
if ( o == orientation() )
179
if (o == Qt::Horizontal)
181
if ((d_data->scalePos == LeftScale) || (d_data->scalePos == RightScale))
182
d_data->scalePos = NoScale;
184
else // if (o == Qt::Vertical)
186
if ((d_data->scalePos == BottomScale) || (d_data->scalePos == TopScale))
187
d_data->scalePos = NoScale;
190
#if QT_VERSION >= 0x040000
191
if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
193
if ( !testWState( WState_OwnSizePolicy ) )
196
QSizePolicy sp = sizePolicy();
200
#if QT_VERSION >= 0x040000
201
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
203
clearWState( WState_OwnSizePolicy );
207
QwtAbstractSlider::setOrientation(o);
212
\brief Change the scale position (and slider orientation).
214
\param s Position of the scale.
216
A valid combination of scale position and orientation is enforced:
217
- if the new scale position is Left or Right, the scale orientation will
219
- if the new scale position is Bottom or Top the scale orientation will
220
become Qt::Horizontal;
221
- if the new scale position is QwtSlider::NoScale, the scale
222
orientation will not change.
224
void QwtSlider::setScalePosition(ScalePos s)
226
if ( d_data->scalePos == s )
229
d_data->scalePos = s;
231
switch(d_data->scalePos)
235
setOrientation(Qt::Horizontal);
236
scaleDraw()->setAlignment(QwtScaleDraw::BottomScale);
241
setOrientation(Qt::Horizontal);
242
scaleDraw()->setAlignment(QwtScaleDraw::TopScale);
247
setOrientation(Qt::Vertical);
248
scaleDraw()->setAlignment(QwtScaleDraw::LeftScale);
253
setOrientation(Qt::Vertical);
254
scaleDraw()->setAlignment(QwtScaleDraw::RightScale);
266
//! Return the scale position.
267
QwtSlider::ScalePos QwtSlider::scalePosition() const
269
return d_data->scalePos;
273
\brief Change the slider's border width
274
\param bd border width
276
void QwtSlider::setBorderWidth(int bd)
281
if ( bd != d_data->borderWidth )
283
d_data->borderWidth = bd;
289
\brief Set the slider's thumb length
290
\param thumbLength new length
292
void QwtSlider::setThumbLength(int thumbLength)
294
if ( thumbLength < 8 )
297
if ( thumbLength != d_data->thumbLength )
299
d_data->thumbLength = thumbLength;
305
\brief Change the width of the thumb
308
void QwtSlider::setThumbWidth(int w)
313
if ( d_data->thumbWidth != w )
315
d_data->thumbWidth = w;
321
\brief Set a scale draw
323
For changing the labels of the scales, it
324
is necessary to derive from QwtScaleDraw and
325
overload QwtScaleDraw::label().
327
\param scaleDraw ScaleDraw object, that has to be created with
328
new and will be deleted in ~QwtSlider or the next
329
call of setScaleDraw().
331
void QwtSlider::setScaleDraw(QwtScaleDraw *scaleDraw)
333
const QwtScaleDraw *previousScaleDraw = this->scaleDraw();
334
if ( scaleDraw == NULL || scaleDraw == previousScaleDraw )
337
if ( previousScaleDraw )
338
scaleDraw->setAlignment(previousScaleDraw->alignment());
340
setAbstractScaleDraw(scaleDraw);
345
\return the scale draw of the slider
348
const QwtScaleDraw *QwtSlider::scaleDraw() const
350
return (QwtScaleDraw *)abstractScaleDraw();
354
\return the scale draw of the slider
357
QwtScaleDraw *QwtSlider::scaleDraw()
359
return (QwtScaleDraw *)abstractScaleDraw();
362
//! Notify changed scale
363
void QwtSlider::scaleChange()
369
//! Notify change in font
370
void QwtSlider::fontChange(const QFont &f)
372
QwtAbstractSlider::fontChange( f );
376
//! Draw the slider into the specified rectangle.
377
void QwtSlider::drawSlider(QPainter *p, const QRect &r)
381
if (d_data->bgStyle & BgTrough)
383
qDrawShadePanel(p, r.x(), r.y(),
384
r.width(), r.height(),
385
#if QT_VERSION < 0x040000
390
true, d_data->borderWidth,0);
392
cr.setRect(r.x() + d_data->borderWidth,
393
r.y() + d_data->borderWidth,
394
r.width() - 2 * d_data->borderWidth,
395
r.height() - 2 * d_data->borderWidth);
397
p->fillRect(cr.x(), cr.y(), cr.width(), cr.height(),
398
#if QT_VERSION < 0x040000
399
colorGroup().brush(QColorGroup::Mid)
401
palette().brush(QPalette::Mid)
406
if ( d_data->bgStyle & BgSlot)
409
int ds = d_data->thumbLength / 2 - 4;
414
if (orientation() == Qt::Horizontal)
416
if ( cr.height() & 1 )
418
rSlot = QRect(cr.x() + ds,
419
cr.y() + (cr.height() - ws) / 2,
420
cr.width() - 2 * ds, ws);
424
if ( cr.width() & 1 )
426
rSlot = QRect(cr.x() + (cr.width() - ws) / 2,
428
ws, cr.height() - 2 * ds);
430
p->fillRect(rSlot.x(), rSlot.y(), rSlot.width(), rSlot.height(),
431
#if QT_VERSION < 0x040000
432
colorGroup().brush(QColorGroup::Dark)
434
palette().brush(QPalette::Dark)
437
qDrawShadePanel(p, rSlot.x(), rSlot.y(),
438
rSlot.width(), rSlot.height(),
439
#if QT_VERSION < 0x040000
449
drawThumb(p, cr, xyPosition(value()));
452
//! Draw the thumb at a position
453
void QwtSlider::drawThumb(QPainter *p, const QRect &sliderRect, int pos)
455
pos++; // shade line points one pixel below
456
if (orientation() == Qt::Horizontal)
458
qDrawShadePanel(p, pos - d_data->thumbLength / 2,
459
sliderRect.y(), d_data->thumbLength, sliderRect.height(),
460
#if QT_VERSION < 0x040000
465
false, d_data->borderWidth,
466
#if QT_VERSION < 0x040000
467
&colorGroup().brush(QColorGroup::Button)
469
&palette().brush(QPalette::Button)
473
qDrawShadeLine(p, pos, sliderRect.y(),
474
pos, sliderRect.y() + sliderRect.height() - 2,
475
#if QT_VERSION < 0x040000
484
qDrawShadePanel(p,sliderRect.x(), pos - d_data->thumbLength / 2,
485
sliderRect.width(), d_data->thumbLength,
486
#if QT_VERSION < 0x040000
491
false, d_data->borderWidth,
492
#if QT_VERSION < 0x040000
493
&colorGroup().brush(QColorGroup::Button)
495
&palette().brush(QPalette::Button)
499
qDrawShadeLine(p, sliderRect.x(), pos,
500
sliderRect.x() + sliderRect.width() - 2, pos,
501
#if QT_VERSION < 0x040000
510
//! Find the x/y position for a given value v
511
int QwtSlider::xyPosition(double v) const
513
return d_data->map.transform(v);
516
//! Determine the value corresponding to a specified mouse location.
517
double QwtSlider::getValue(const QPoint &p)
519
return d_data->map.invTransform(
520
orientation() == Qt::Horizontal ? p.x() : p.y());
525
\brief Determine scrolling mode and direction
527
\param scrollMode Scrolling mode
528
\param direction Direction
530
void QwtSlider::getScrollMode(const QPoint &p,
531
int &scrollMode, int &direction )
533
if (!d_data->sliderRect.contains(p))
535
scrollMode = ScrNone;
540
const int pos = ( orientation() == Qt::Horizontal ) ? p.x() : p.y();
541
const int markerPos = xyPosition(value());
543
if ((pos > markerPos - d_data->thumbLength / 2)
544
&& (pos < markerPos + d_data->thumbLength / 2))
546
scrollMode = ScrMouse;
551
scrollMode = ScrPage;
552
direction = (pos > markerPos) ? 1 : -1;
554
if ( scaleDraw()->map().p1() > scaleDraw()->map().p2() )
555
direction = -direction;
559
void QwtSlider::paintEvent(QPaintEvent *e)
561
const QRect &ur = e->rect();
564
#if QT_VERSION < 0x040000
565
QwtPaintBuffer paintBuffer(this, ur);
566
draw(paintBuffer.painter(), ur);
568
QPainter painter(this);
574
//! Draw the QwtSlider
575
void QwtSlider::draw(QPainter *painter, const QRect&)
577
if (d_data->scalePos != NoScale)
579
#if QT_VERSION < 0x040000
580
scaleDraw()->draw(painter, colorGroup());
582
scaleDraw()->draw(painter, palette());
586
drawSlider(painter, d_data->sliderRect);
589
QwtPainter::drawFocusRect(painter, this, d_data->sliderRect);
593
void QwtSlider::resizeEvent(QResizeEvent *)
595
layoutSlider( false );
599
Recalculate the slider's geometry and layout based on
600
the current rect and fonts.
601
\param update_geometry notify the layout system and call update
604
void QwtSlider::layoutSlider( bool update_geometry )
606
int sliderWidth = d_data->thumbWidth;
607
int sld1 = d_data->thumbLength / 2 - 1;
608
int sld2 = d_data->thumbLength / 2 + d_data->thumbLength % 2;
609
if ( d_data->bgStyle & BgTrough )
611
sliderWidth += 2 * d_data->borderWidth;
612
sld1 += d_data->borderWidth;
613
sld2 += d_data->borderWidth;
617
if ( d_data->scalePos != NoScale )
620
scaleDraw()->getBorderDistHint(font(), d1, d2);
621
scd = qwtMax(d1, d2);
624
int slo = scd - sld1;
630
const QRect r = rect();
631
if (orientation() == Qt::Horizontal)
633
switch (d_data->scalePos)
637
d_data->sliderRect.setRect(
638
r.x() + d_data->xMargin + slo,
640
d_data->yMargin - sliderWidth,
641
r.width() - 2 * d_data->xMargin - 2 * slo,
644
x = d_data->sliderRect.x() + sld1;
645
y = d_data->sliderRect.y() - d_data->scaleDist;
652
d_data->sliderRect.setRect(
653
r.x() + d_data->xMargin + slo,
654
r.y() + d_data->yMargin,
655
r.width() - 2 * d_data->xMargin - 2 * slo,
658
x = d_data->sliderRect.x() + sld1;
659
y = d_data->sliderRect.y() + d_data->sliderRect.height()
665
case NoScale: // like Bottom, but no scale. See QwtSlider().
666
default: // inconsistent orientation and scale position
668
d_data->sliderRect.setRect(
669
r.x() + d_data->xMargin + slo,
670
r.y() + d_data->yMargin,
671
r.width() - 2 * d_data->xMargin - 2 * slo,
674
x = d_data->sliderRect.x() + sld1;
680
length = d_data->sliderRect.width() - (sld1 + sld2);
682
else // if (orientation() == Qt::Vertical
684
switch (d_data->scalePos)
687
d_data->sliderRect.setRect(
688
r.x() + d_data->xMargin,
689
r.y() + d_data->yMargin + slo,
691
r.height() - 2 * d_data->yMargin - 2 * slo);
693
x = d_data->sliderRect.x() + d_data->sliderRect.width()
695
y = d_data->sliderRect.y() + sld1;
700
d_data->sliderRect.setRect(
701
r.x() + r.width() - sliderWidth - d_data->xMargin,
702
r.y() + d_data->yMargin + slo,
704
r.height() - 2 * d_data->yMargin - 2 * slo);
706
x = d_data->sliderRect.x() - d_data->scaleDist;
707
y = d_data->sliderRect.y() + sld1;
711
case NoScale: // like Left, but no scale. See QwtSlider().
712
default: // inconsistent orientation and scale position
713
d_data->sliderRect.setRect(
714
r.x() + r.width() - sliderWidth - d_data->xMargin,
715
r.y() + d_data->yMargin + slo,
717
r.height() - 2 * d_data->yMargin - 2 * slo);
720
y = d_data->sliderRect.y() + sld1;
724
length = d_data->sliderRect.height() - (sld1 + sld2);
727
scaleDraw()->move(x, y);
728
scaleDraw()->setLength(length);
730
d_data->map.setPaintXInterval(scaleDraw()->map().p1(),
731
scaleDraw()->map().p2());
733
if ( update_geometry )
735
d_data->sizeHintCache = QSize(); // invalidate
741
//! Notify change of value
742
void QwtSlider::valueChange()
744
QwtAbstractSlider::valueChange();
749
//! Notify change of range
750
void QwtSlider::rangeChange()
752
d_data->map.setScaleInterval(minValue(), maxValue());
755
rescale(minValue(), maxValue());
757
QwtAbstractSlider::rangeChange();
762
\brief Set distances between the widget's border and internals.
763
\param xMargin Horizontal margin
764
\param yMargin Vertical margin
766
void QwtSlider::setMargins(int xMargin, int yMargin)
773
if ( xMargin != d_data->xMargin || yMargin != d_data->yMargin )
775
d_data->xMargin = xMargin;
776
d_data->yMargin = yMargin;
782
Set the background style.
784
void QwtSlider::setBgStyle(BGSTYLE st)
786
d_data->bgStyle = st;
791
\return the background style.
793
QwtSlider::BGSTYLE QwtSlider::bgStyle() const
795
return d_data->bgStyle;
799
\return the thumb length.
801
int QwtSlider::thumbLength() const
803
return d_data->thumbLength;
807
\return the thumb width.
809
int QwtSlider::thumbWidth() const
811
return d_data->thumbWidth;
815
\return the border width.
817
int QwtSlider::borderWidth() const
819
return d_data->borderWidth;
823
\return QwtSlider::minimumSizeHint()
825
QSize QwtSlider::sizeHint() const
827
return minimumSizeHint();
831
\brief Return a minimum size hint
832
\warning The return value of QwtSlider::minimumSizeHint() depends on
833
the font and the scale.
835
QSize QwtSlider::minimumSizeHint() const
837
if (!d_data->sizeHintCache.isEmpty())
838
return d_data->sizeHintCache;
840
int sliderWidth = d_data->thumbWidth;
841
if (d_data->bgStyle & BgTrough)
842
sliderWidth += 2 * d_data->borderWidth;
845
if (d_data->scalePos != NoScale)
848
scaleDraw()->getBorderDistHint(font(), d1, d2);
849
int msMbd = qwtMax(d1, d2);
851
int mbd = d_data->thumbLength / 2;
852
if (d_data->bgStyle & BgTrough)
853
mbd += d_data->borderWidth;
858
const int sdExtent = scaleDraw()->extent( QPen(), font() );
859
const int sdLength = scaleDraw()->minLength( QPen(), font() );
861
h = sliderWidth + sdExtent + d_data->scaleDist;
862
w = sdLength - 2 * msMbd + 2 * mbd;
870
if ( orientation() == Qt::Vertical )
873
w += 2 * d_data->xMargin;
874
h += 2 * d_data->yMargin;
876
d_data->sizeHintCache = QSize(w, h);
877
return d_data->sizeHintCache;