QSlider: fix qdoc warnings
[profile/ivi/qtbase.git] / src / widgets / widgets / qslider.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qslider.h"
43 #ifndef QT_NO_SLIDER
44 #ifndef QT_NO_ACCESSIBILITY
45 #include "qaccessible.h"
46 #endif
47 #include "qapplication.h"
48 #include "qevent.h"
49 #include "qpainter.h"
50 #include "qstyle.h"
51 #include "qstyleoption.h"
52 #include "private/qabstractslider_p.h"
53 #include "qdebug.h"
54
55 QT_BEGIN_NAMESPACE
56
57 class QSliderPrivate : public QAbstractSliderPrivate
58 {
59     Q_DECLARE_PUBLIC(QSlider)
60 public:
61     QStyle::SubControl pressedControl;
62     int tickInterval;
63     QSlider::TickPosition tickPosition;
64     int clickOffset;
65     void init();
66         void resetLayoutItemMargins();
67     int pixelPosToRangeValue(int pos) const;
68     inline int pick(const QPoint &pt) const;
69
70     QStyle::SubControl newHoverControl(const QPoint &pos);
71     bool updateHoverControl(const QPoint &pos);
72     QStyle::SubControl hoverControl;
73     QRect hoverRect;
74 };
75
76 void QSliderPrivate::init()
77 {
78     Q_Q(QSlider);
79     pressedControl = QStyle::SC_None;
80     tickInterval = 0;
81     tickPosition = QSlider::NoTicks;
82     hoverControl = QStyle::SC_None;
83     q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy)));
84     QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::Slider);
85     if (orientation == Qt::Vertical)
86         sp.transpose();
87     q->setSizePolicy(sp);
88     q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
89         resetLayoutItemMargins();
90 }
91
92 void QSliderPrivate::resetLayoutItemMargins()
93 {
94     Q_Q(QSlider);
95     QStyleOptionSlider opt;
96     q->initStyleOption(&opt);
97     setLayoutItemMargins(QStyle::SE_SliderLayoutItem, &opt);
98 }
99
100 int QSliderPrivate::pixelPosToRangeValue(int pos) const
101 {
102     Q_Q(const QSlider);
103     QStyleOptionSlider opt;
104     q->initStyleOption(&opt);
105     QRect gr = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, q);
106     QRect sr = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, q);
107     int sliderMin, sliderMax, sliderLength;
108
109     if (orientation == Qt::Horizontal) {
110         sliderLength = sr.width();
111         sliderMin = gr.x();
112         sliderMax = gr.right() - sliderLength + 1;
113     } else {
114         sliderLength = sr.height();
115         sliderMin = gr.y();
116         sliderMax = gr.bottom() - sliderLength + 1;
117     }
118     return QStyle::sliderValueFromPosition(minimum, maximum, pos - sliderMin,
119                                            sliderMax - sliderMin, opt.upsideDown);
120 }
121
122 inline int QSliderPrivate::pick(const QPoint &pt) const
123 {
124     return orientation == Qt::Horizontal ? pt.x() : pt.y();
125 }
126
127 /*!
128     Initialize \a option with the values from this QSlider. This method
129     is useful for subclasses when they need a QStyleOptionSlider, but don't want
130     to fill in all the information themselves.
131
132     \sa QStyleOption::initFrom()
133 */
134 void QSlider::initStyleOption(QStyleOptionSlider *option) const
135 {
136     if (!option)
137         return;
138
139     Q_D(const QSlider);
140     option->initFrom(this);
141     option->subControls = QStyle::SC_None;
142     option->activeSubControls = QStyle::SC_None;
143     option->orientation = d->orientation;
144     option->maximum = d->maximum;
145     option->minimum = d->minimum;
146     option->tickPosition = (QSlider::TickPosition)d->tickPosition;
147     option->tickInterval = d->tickInterval;
148     option->upsideDown = (d->orientation == Qt::Horizontal) ?
149                      (d->invertedAppearance != (option->direction == Qt::RightToLeft))
150                      : (!d->invertedAppearance);
151     option->direction = Qt::LeftToRight; // we use the upsideDown option instead
152     option->sliderPosition = d->position;
153     option->sliderValue = d->value;
154     option->singleStep = d->singleStep;
155     option->pageStep = d->pageStep;
156     if (d->orientation == Qt::Horizontal)
157         option->state |= QStyle::State_Horizontal;
158 }
159
160 bool QSliderPrivate::updateHoverControl(const QPoint &pos)
161 {
162     Q_Q(QSlider);
163     QRect lastHoverRect = hoverRect;
164     QStyle::SubControl lastHoverControl = hoverControl;
165     bool doesHover = q->testAttribute(Qt::WA_Hover);
166     if (lastHoverControl != newHoverControl(pos) && doesHover) {
167         q->update(lastHoverRect);
168         q->update(hoverRect);
169         return true;
170     }
171     return !doesHover;
172 }
173
174 QStyle::SubControl QSliderPrivate::newHoverControl(const QPoint &pos)
175 {
176     Q_Q(QSlider);
177     QStyleOptionSlider opt;
178     q->initStyleOption(&opt);
179     opt.subControls = QStyle::SC_All;
180     QRect handleRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, q);
181     QRect grooveRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, q);
182     QRect tickmarksRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderTickmarks, q);
183
184     if (handleRect.contains(pos)) {
185         hoverRect = handleRect;
186         hoverControl = QStyle::SC_SliderHandle;
187     } else if (grooveRect.contains(pos)) {
188         hoverRect = grooveRect;
189         hoverControl = QStyle::SC_SliderGroove;
190     } else if (tickmarksRect.contains(pos)) {
191         hoverRect = tickmarksRect;
192         hoverControl = QStyle::SC_SliderTickmarks;
193     } else {
194         hoverRect = QRect();
195         hoverControl = QStyle::SC_None;
196     }
197
198     return hoverControl;
199 }
200
201 /*!
202     \class QSlider
203     \brief The QSlider widget provides a vertical or horizontal slider.
204
205     \ingroup basicwidgets
206     \inmodule QtWidgets
207
208     The slider is the classic widget for controlling a bounded value.
209     It lets the user move a slider handle along a horizontal or vertical
210     groove and translates the handle's position into an integer value
211     within the legal range.
212
213     QSlider has very few of its own functions; most of the functionality is in
214     QAbstractSlider. The most useful functions are setValue() to set
215     the slider directly to some value; triggerAction() to simulate
216     the effects of clicking (useful for shortcut keys);
217     setSingleStep(), setPageStep() to set the steps; and setMinimum()
218     and setMaximum() to define the range of the scroll bar.
219
220     QSlider provides methods for controlling tickmarks.  You can use
221     setTickPosition() to indicate where you want the tickmarks to be,
222     setTickInterval() to indicate how many of them you want. the
223     currently set tick position and interval can be queried using the
224     tickPosition() and tickInterval() functions, respectively.
225
226     QSlider inherits a comprehensive set of signals:
227     \table
228     \header \li Signal \li Description
229     \row \li \l valueChanged()
230     \li Emitted when the slider's value has changed. The tracking()
231        determines whether this signal is emitted during user
232        interaction.
233     \row \li \l sliderPressed()
234     \li Emitted when the user starts to drag the slider.
235     \row \li \l sliderMoved()
236     \li Emitted when the user drags the slider.
237     \row \li \l sliderReleased()
238     \li Emitted when the user releases the slider.
239     \endtable
240
241     QSlider only provides integer ranges. Note that although
242     QSlider handles very large numbers, it becomes difficult for users
243     to use a slider accurately for very large ranges.
244
245     A slider accepts focus on Tab and provides both a mouse wheel and a
246     keyboard interface. The keyboard interface is the following:
247
248     \list
249         \li Left/Right move a horizontal slider by one single step.
250         \li Up/Down move a vertical slider by one single step.
251         \li PageUp moves up one page.
252         \li PageDown moves down one page.
253         \li Home moves to the start (mininum).
254         \li End moves to the end (maximum).
255     \endlist
256
257     \table 100%
258     \row \li \inlineimage macintosh-slider.png Screenshot of a Macintosh slider
259          \li A slider shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
260     \row \li \inlineimage windows-slider.png Screenshot of a Windows XP slider
261          \li A slider shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
262     \row \li \inlineimage plastique-slider.png Screenshot of a Plastique slider
263          \li A slider shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
264     \endtable
265
266     \sa QScrollBar, QSpinBox, QDial, {fowler}{GUI Design Handbook: Slider}, {Sliders Example}
267 */
268
269
270 /*!
271     \enum QSlider::TickPosition
272
273     This enum specifies where the tick marks are to be drawn relative
274     to the slider's groove and the handle the user moves.
275
276     \value NoTicks Do not draw any tick marks.
277     \value TicksBothSides Draw tick marks on both sides of the groove.
278     \value TicksAbove Draw tick marks above the (horizontal) slider
279     \value TicksBelow Draw tick marks below the (horizontal) slider
280     \value TicksLeft Draw tick marks to the left of the (vertical) slider
281     \value TicksRight Draw tick marks to the right of the (vertical) slider
282 */
283
284
285 /*!
286     Constructs a vertical slider with the given \a parent.
287 */
288 QSlider::QSlider(QWidget *parent)
289     : QAbstractSlider(*new QSliderPrivate, parent)
290 {
291     d_func()->orientation = Qt::Vertical;
292     d_func()->init();
293 }
294
295 /*!
296     Constructs a slider with the given \a parent. The \a orientation
297     parameter determines whether the slider is horizontal or vertical;
298     the valid values are Qt::Vertical and Qt::Horizontal.
299 */
300
301 QSlider::QSlider(Qt::Orientation orientation, QWidget *parent)
302     : QAbstractSlider(*new QSliderPrivate, parent)
303 {
304     d_func()->orientation = orientation;
305     d_func()->init();
306 }
307
308
309 /*!
310     Destroys this slider.
311 */
312 QSlider::~QSlider()
313 {
314 }
315
316 /*!
317     \reimp
318 */
319 void QSlider::paintEvent(QPaintEvent *)
320 {
321     Q_D(QSlider);
322     QPainter p(this);
323     QStyleOptionSlider opt;
324     initStyleOption(&opt);
325
326     opt.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
327     if (d->tickPosition != NoTicks)
328         opt.subControls |= QStyle::SC_SliderTickmarks;
329     if (d->pressedControl) {
330         opt.activeSubControls = d->pressedControl;
331         opt.state |= QStyle::State_Sunken;
332     } else {
333         opt.activeSubControls = d->hoverControl;
334     }
335
336     style()->drawComplexControl(QStyle::CC_Slider, &opt, &p, this);
337 }
338
339 /*!
340     \reimp
341 */
342
343 bool QSlider::event(QEvent *event)
344 {
345     Q_D(QSlider);
346
347     switch(event->type()) {
348     case QEvent::HoverEnter:
349     case QEvent::HoverLeave:
350     case QEvent::HoverMove:
351         if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
352             d->updateHoverControl(he->pos());
353         break;
354     case QEvent::StyleChange:
355     case QEvent::MacSizeChange:
356         d->resetLayoutItemMargins();
357         break;
358     default:
359         break;
360     }
361     return QAbstractSlider::event(event);
362 }
363
364 /*!
365     \reimp
366 */
367 void QSlider::mousePressEvent(QMouseEvent *ev)
368 {
369     Q_D(QSlider);
370     if (d->maximum == d->minimum || (ev->buttons() ^ ev->button())) {
371         ev->ignore();
372         return;
373     }
374 #ifdef QT_KEYPAD_NAVIGATION
375     if (QApplication::keypadNavigationEnabled())
376         setEditFocus(true);
377 #endif
378     ev->accept();
379     if ((ev->button() & style()->styleHint(QStyle::SH_Slider_AbsoluteSetButtons)) == ev->button()) {
380         QStyleOptionSlider opt;
381         initStyleOption(&opt);
382         const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
383         const QPoint center = sliderRect.center() - sliderRect.topLeft();
384         // to take half of the slider off for the setSliderPosition call we use the center - topLeft
385
386         setSliderPosition(d->pixelPosToRangeValue(d->pick(ev->pos() - center)));
387         triggerAction(SliderMove);
388         setRepeatAction(SliderNoAction);
389         d->pressedControl = QStyle::SC_SliderHandle;
390         update();
391     } else if ((ev->button() & style()->styleHint(QStyle::SH_Slider_PageSetButtons)) == ev->button()) {
392         QStyleOptionSlider opt;
393         initStyleOption(&opt);
394         d->pressedControl = style()->hitTestComplexControl(QStyle::CC_Slider,
395                                                            &opt, ev->pos(), this);
396         SliderAction action = SliderNoAction;
397         if (d->pressedControl == QStyle::SC_SliderGroove) {
398             const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
399             int pressValue = d->pixelPosToRangeValue(d->pick(ev->pos() - sliderRect.center() + sliderRect.topLeft()));
400             d->pressValue = pressValue;
401             if (pressValue > d->value)
402                 action = SliderPageStepAdd;
403             else if (pressValue < d->value)
404                 action = SliderPageStepSub;
405             if (action) {
406                 triggerAction(action);
407                 setRepeatAction(action);
408             }
409         }
410     } else {
411         ev->ignore();
412         return;
413     }
414
415     if (d->pressedControl == QStyle::SC_SliderHandle) {
416         QStyleOptionSlider opt;
417         initStyleOption(&opt);
418         setRepeatAction(SliderNoAction);
419         QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
420         d->clickOffset = d->pick(ev->pos() - sr.topLeft());
421         update(sr);
422         setSliderDown(true);
423     }
424 }
425
426 /*!
427     \reimp
428 */
429 void QSlider::mouseMoveEvent(QMouseEvent *ev)
430 {
431     Q_D(QSlider);
432     if (d->pressedControl != QStyle::SC_SliderHandle) {
433         ev->ignore();
434         return;
435     }
436     ev->accept();
437     int newPosition = d->pixelPosToRangeValue(d->pick(ev->pos()) - d->clickOffset);
438     QStyleOptionSlider opt;
439     initStyleOption(&opt);
440     setSliderPosition(newPosition);
441 }
442
443
444 /*!
445     \reimp
446 */
447 void QSlider::mouseReleaseEvent(QMouseEvent *ev)
448 {
449     Q_D(QSlider);
450     if (d->pressedControl == QStyle::SC_None || ev->buttons()) {
451         ev->ignore();
452         return;
453     }
454     ev->accept();
455     QStyle::SubControl oldPressed = QStyle::SubControl(d->pressedControl);
456     d->pressedControl = QStyle::SC_None;
457     setRepeatAction(SliderNoAction);
458     if (oldPressed == QStyle::SC_SliderHandle)
459         setSliderDown(false);
460     QStyleOptionSlider opt;
461     initStyleOption(&opt);
462     opt.subControls = oldPressed;
463     update(style()->subControlRect(QStyle::CC_Slider, &opt, oldPressed, this));
464 }
465
466 /*!
467     \reimp
468 */
469 QSize QSlider::sizeHint() const
470 {
471     Q_D(const QSlider);
472     ensurePolished();
473     const int SliderLength = 84, TickSpace = 5;
474     QStyleOptionSlider opt;
475     initStyleOption(&opt);
476     int thick = style()->pixelMetric(QStyle::PM_SliderThickness, &opt, this);
477     if (d->tickPosition & TicksAbove)
478         thick += TickSpace;
479     if (d->tickPosition & TicksBelow)
480         thick += TickSpace;
481     int w = thick, h = SliderLength;
482     if (d->orientation == Qt::Horizontal) {
483         w = SliderLength;
484         h = thick;
485     }
486     return style()->sizeFromContents(QStyle::CT_Slider, &opt, QSize(w, h), this).expandedTo(QApplication::globalStrut());
487 }
488
489 /*!
490     \reimp
491 */
492 QSize QSlider::minimumSizeHint() const
493 {
494     Q_D(const QSlider);
495     QSize s = sizeHint();
496     QStyleOptionSlider opt;
497     initStyleOption(&opt);
498     int length = style()->pixelMetric(QStyle::PM_SliderLength, &opt, this);
499     if (d->orientation == Qt::Horizontal)
500         s.setWidth(length);
501     else
502         s.setHeight(length);
503     return s;
504 }
505
506 /*!
507     \property QSlider::tickPosition
508     \brief the tickmark position for this slider
509
510     The valid values are described by the QSlider::TickPosition enum.
511
512     The default value is \l QSlider::NoTicks.
513
514     \sa tickInterval
515 */
516
517 void QSlider::setTickPosition(TickPosition position)
518 {
519     Q_D(QSlider);
520     d->tickPosition = position;
521     d->resetLayoutItemMargins();
522     update();
523     updateGeometry();
524 }
525
526 QSlider::TickPosition QSlider::tickPosition() const
527 {
528     return d_func()->tickPosition;
529 }
530
531 /*!
532     \property QSlider::tickInterval
533     \brief the interval between tickmarks
534
535     This is a value interval, not a pixel interval. If it is 0, the
536     slider will choose between singleStep and pageStep.
537
538     The default value is 0.
539
540     \sa tickPosition, singleStep, pageStep
541 */
542
543 void QSlider::setTickInterval(int ts)
544 {
545     d_func()->tickInterval = qMax(0, ts);
546     update();
547 }
548
549 int QSlider::tickInterval() const
550 {
551     return d_func()->tickInterval;
552 }
553
554 Q_WIDGETS_EXPORT QStyleOptionSlider qt_qsliderStyleOption(QSlider *slider)
555 {
556     QStyleOptionSlider sliderOption;
557     slider->initStyleOption(&sliderOption);
558     return sliderOption;
559 }
560
561 #endif
562
563 QT_END_NAMESPACE