author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Tue, 06 Jul 2010 15:10:48 +0300 | |
changeset 30 | 5dc02b23752f |
parent 18 | 2f34d5167611 |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
18
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 4 |
** All rights reserved. |
5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 |
** |
|
7 |
** This file is part of the QtGui module of the Qt Toolkit. |
|
8 |
** |
|
9 |
** $QT_BEGIN_LICENSE:LGPL$ |
|
10 |
** No Commercial Usage |
|
11 |
** This file contains pre-release code and may not be distributed. |
|
12 |
** You may use this file in accordance with the terms and conditions |
|
13 |
** contained in the Technology Preview License Agreement accompanying |
|
14 |
** this package. |
|
15 |
** |
|
16 |
** GNU Lesser General Public License Usage |
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 |
** General Public License version 2.1 as published by the Free Software |
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 |
** packaging of this file. Please review the following information to |
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 |
** |
|
24 |
** In addition, as a special exception, Nokia gives you certain additional |
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 |
** |
|
28 |
** If you have questions regarding the use of this file, please contact |
|
29 |
** Nokia at qt-info@nokia.com. |
|
30 |
** |
|
31 |
** |
|
32 |
** |
|
33 |
** |
|
34 |
** |
|
35 |
** |
|
36 |
** |
|
37 |
** |
|
38 |
** $QT_END_LICENSE$ |
|
39 |
** |
|
40 |
****************************************************************************/ |
|
41 |
||
42 |
#include "qapplication.h" |
|
43 |
#include "qcursor.h" |
|
44 |
#include "qevent.h" |
|
45 |
#include "qpainter.h" |
|
46 |
#include "qscrollbar.h" |
|
47 |
#include "qstyle.h" |
|
48 |
#include "qstyleoption.h" |
|
49 |
#include "qmenu.h" |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
18
diff
changeset
|
50 |
#include <QtCore/qelapsedtimer.h> |
0 | 51 |
|
52 |
#ifndef QT_NO_SCROLLBAR |
|
53 |
||
54 |
#ifndef QT_NO_ACCESSIBILITY |
|
55 |
#include "qaccessible.h" |
|
56 |
#endif |
|
57 |
#include <limits.h> |
|
58 |
#include "qabstractslider_p.h" |
|
59 |
||
60 |
QT_BEGIN_NAMESPACE |
|
61 |
||
62 |
/*! |
|
63 |
\class QScrollBar |
|
64 |
\brief The QScrollBar widget provides a vertical or horizontal scroll bar. |
|
65 |
||
66 |
\ingroup basicwidgets |
|
67 |
||
68 |
A scroll bar is a control that enables the user to access parts of a |
|
69 |
document that is larger than the widget used to display it. It provides |
|
70 |
a visual indication of the user's current position within the document |
|
71 |
and the amount of the document that is visible. Scroll bars are usually |
|
72 |
equipped with other controls that enable more accurate navigation. |
|
73 |
Qt displays scroll bars in a way that is appropriate for each platform. |
|
74 |
||
75 |
If you need to provide a scrolling view onto another widget, it may be |
|
76 |
more convenient to use the QScrollArea class because this provides a |
|
77 |
viewport widget and scroll bars. QScrollBar is useful if you need to |
|
78 |
implement similar functionality for specialized widgets using QAbstractScrollArea; |
|
79 |
for example, if you decide to subclass QAbstractItemView. |
|
80 |
For most other situations where a slider control is used to obtain a value |
|
81 |
within a given range, the QSlider class may be more appropriate for your |
|
82 |
needs. |
|
83 |
||
84 |
\table |
|
85 |
\row \i \image qscrollbar-picture.png |
|
86 |
\i Scroll bars typically include four separate controls: a slider, |
|
87 |
scroll arrows, and a page control. |
|
88 |
||
89 |
\list |
|
90 |
\i a. The slider provides a way to quickly go to any part of the |
|
91 |
document, but does not support accurate navigation within large |
|
92 |
documents. |
|
93 |
\i b. The scroll arrows are push buttons which can be used to accurately |
|
94 |
navigate to a particular place in a document. For a vertical scroll bar |
|
95 |
connected to a text editor, these typically move the current position one |
|
96 |
"line" up or down, and adjust the position of the slider by a small |
|
97 |
amount. In editors and list boxes a "line" might mean one line of text; |
|
98 |
in an image viewer it might mean 20 pixels. |
|
99 |
\i c. The page control is the area over which the slider is dragged (the |
|
100 |
scroll bar's background). Clicking here moves the scroll bar towards |
|
101 |
the click by one "page". This value is usually the same as the length of |
|
102 |
the slider. |
|
103 |
\endlist |
|
104 |
\endtable |
|
105 |
||
106 |
Each scroll bar has a value that indicates how far the slider is from |
|
107 |
the start of the scroll bar; this is obtained with value() and set |
|
108 |
with setValue(). This value always lies within the range of values |
|
109 |
defined for the scroll bar, from \l{QAbstractSlider::minimum()}{minimum()} |
|
110 |
to \l{QAbstractSlider::minimum()}{maximum()} inclusive. The range of |
|
111 |
acceptable values can be set with setMinimum() and setMaximum(). |
|
112 |
At the minimum value, the top edge of the slider (for a vertical scroll |
|
113 |
bar) or left edge (for a horizontal scroll bar) will be at the top (or |
|
114 |
left) end of the scroll bar. At the maximum value, the bottom (or right) |
|
115 |
edge of the slider will be at the bottom (or right) end of the scroll bar. |
|
116 |
||
117 |
The length of the slider is usually related to the value of the page step, |
|
118 |
and typically represents the proportion of the document area shown in a |
|
119 |
scrolling view. The page step is the amount that the value changes by |
|
120 |
when the user presses the \key{Page Up} and \key{Page Down} keys, and is |
|
121 |
set with setPageStep(). Smaller changes to the value defined by the |
|
122 |
line step are made using the cursor keys, and this quantity is set with |
|
123 |
\l{QAbstractSlider::}{setSingleStep()}. |
|
124 |
||
125 |
Note that the range of values used is independent of the actual size |
|
126 |
of the scroll bar widget. You do not need to take this into account when |
|
127 |
you choose values for the range and the page step. |
|
128 |
||
129 |
The range of values specified for the scroll bar are often determined |
|
130 |
differently to those for a QSlider because the length of the slider |
|
131 |
needs to be taken into account. If we have a document with 100 lines, |
|
132 |
and we can only show 20 lines in a widget, we may wish to construct a |
|
133 |
scroll bar with a page step of 20, a minimum value of 0, and a maximum |
|
134 |
value of 80. This would give us a scroll bar with five "pages". |
|
135 |
||
136 |
\table |
|
137 |
\row \i \inlineimage qscrollbar-values.png |
|
138 |
\i The relationship between a document length, the range of values used |
|
139 |
in a scroll bar, and the page step is simple in many common situations. |
|
140 |
The scroll bar's range of values is determined by subtracting a |
|
141 |
chosen page step from some value representing the length of the document. |
|
142 |
In such cases, the following equation is useful: |
|
143 |
||
144 |
\e{document length} = maximum() - minimum() + pageStep(). |
|
145 |
\endtable |
|
146 |
||
147 |
QScrollBar only provides integer ranges. Note that although |
|
148 |
QScrollBar handles very large numbers, scroll bars on current |
|
149 |
screens cannot usefully represent ranges above about 100,000 pixels. |
|
150 |
Beyond that, it becomes difficult for the user to control the |
|
151 |
slider using either the keyboard or the mouse, and the scroll |
|
152 |
arrows will have limited use. |
|
153 |
||
154 |
ScrollBar inherits a comprehensive set of signals from QAbstractSlider: |
|
155 |
\list |
|
156 |
\i \l{QAbstractSlider::valueChanged()}{valueChanged()} is emitted when the |
|
157 |
scroll bar's value has changed. The tracking() determines whether this |
|
158 |
signal is emitted during user interaction. |
|
159 |
\i \l{QAbstractSlider::rangeChanged()}{rangeChanged()} is emitted when the |
|
160 |
scroll bar's range of values has changed. |
|
161 |
\i \l{QAbstractSlider::sliderPressed()}{sliderPressed()} is emitted when |
|
162 |
the user starts to drag the slider. |
|
163 |
\i \l{QAbstractSlider::sliderMoved()}{sliderMoved()} is emitted when the user |
|
164 |
drags the slider. |
|
165 |
\i \l{QAbstractSlider::sliderReleased()}{sliderReleased()} is emitted when |
|
166 |
the user releases the slider. |
|
167 |
\i \l{QAbstractSlider::actionTriggered()}{actionTriggered()} is emitted |
|
168 |
when the scroll bar is changed by user interaction or via the |
|
169 |
\l{QAbstractSlider::triggerAction()}{triggerAction()} function. |
|
170 |
\endlist |
|
171 |
||
172 |
A scroll bar can be controlled by the keyboard, but it has a |
|
173 |
default focusPolicy() of Qt::NoFocus. Use setFocusPolicy() to |
|
174 |
enable keyboard interaction with the scroll bar: |
|
175 |
\list |
|
176 |
\i Left/Right move a horizontal scroll bar by one single step. |
|
177 |
\i Up/Down move a vertical scroll bar by one single step. |
|
178 |
\i PageUp moves up one page. |
|
179 |
\i PageDown moves down one page. |
|
180 |
\i Home moves to the start (mininum). |
|
181 |
\i End moves to the end (maximum). |
|
182 |
\endlist |
|
183 |
||
184 |
The slider itself can be controlled by using the |
|
185 |
\l{QAbstractSlider::triggerAction()}{triggerAction()} function to simulate |
|
186 |
user interaction with the scroll bar controls. This is useful if you have |
|
187 |
many different widgets that use a common range of values. |
|
188 |
||
189 |
Most GUI styles use the pageStep() value to calculate the size of the |
|
190 |
slider. |
|
191 |
||
192 |
\table 100% |
|
193 |
\row \o \inlineimage macintosh-horizontalscrollbar.png Screenshot of a Macintosh style scroll bar |
|
194 |
\o A scroll bar shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}. |
|
195 |
\row \o \inlineimage windowsxp-horizontalscrollbar.png Screenshot of a Windows XP style scroll bar |
|
196 |
\o A scroll bar shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}. |
|
197 |
\row \o \inlineimage plastique-horizontalscrollbar.png Screenshot of a Plastique style scroll bar |
|
198 |
\o A scroll bar shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}. |
|
199 |
\endtable |
|
200 |
||
201 |
\sa QScrollArea, QSlider, QDial, QSpinBox, {fowler}{GUI Design Handbook: Scroll Bar}, {Sliders Example} |
|
202 |
*/ |
|
203 |
||
204 |
class QScrollBarPrivate : public QAbstractSliderPrivate |
|
205 |
{ |
|
206 |
Q_DECLARE_PUBLIC(QScrollBar) |
|
207 |
public: |
|
208 |
QStyle::SubControl pressedControl; |
|
209 |
bool pointerOutsidePressedControl; |
|
210 |
||
211 |
int clickOffset, snapBackPosition; |
|
212 |
||
213 |
void activateControl(uint control, int threshold = 500); |
|
214 |
void stopRepeatAction(); |
|
215 |
int pixelPosToRangeValue(int pos) const; |
|
216 |
void init(); |
|
217 |
bool updateHoverControl(const QPoint &pos); |
|
218 |
QStyle::SubControl newHoverControl(const QPoint &pos); |
|
219 |
||
220 |
QStyle::SubControl hoverControl; |
|
221 |
QRect hoverRect; |
|
222 |
}; |
|
223 |
||
224 |
bool QScrollBarPrivate::updateHoverControl(const QPoint &pos) |
|
225 |
{ |
|
226 |
Q_Q(QScrollBar); |
|
227 |
QRect lastHoverRect = hoverRect; |
|
228 |
QStyle::SubControl lastHoverControl = hoverControl; |
|
229 |
bool doesHover = q->testAttribute(Qt::WA_Hover); |
|
230 |
if (lastHoverControl != newHoverControl(pos) && doesHover) { |
|
231 |
q->update(lastHoverRect); |
|
232 |
q->update(hoverRect); |
|
233 |
return true; |
|
234 |
} |
|
235 |
return !doesHover; |
|
236 |
} |
|
237 |
||
238 |
QStyle::SubControl QScrollBarPrivate::newHoverControl(const QPoint &pos) |
|
239 |
{ |
|
240 |
Q_Q(QScrollBar); |
|
241 |
QStyleOptionSlider opt; |
|
242 |
q->initStyleOption(&opt); |
|
243 |
opt.subControls = QStyle::SC_All; |
|
244 |
hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, pos, q); |
|
245 |
if (hoverControl == QStyle::SC_None) |
|
246 |
hoverRect = QRect(); |
|
247 |
else |
|
248 |
hoverRect = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, hoverControl, q); |
|
249 |
return hoverControl; |
|
250 |
} |
|
251 |
||
252 |
void QScrollBarPrivate::activateControl(uint control, int threshold) |
|
253 |
{ |
|
254 |
QAbstractSlider::SliderAction action = QAbstractSlider::SliderNoAction; |
|
255 |
switch (control) { |
|
256 |
case QStyle::SC_ScrollBarAddPage: |
|
257 |
action = QAbstractSlider::SliderPageStepAdd; |
|
258 |
break; |
|
259 |
case QStyle::SC_ScrollBarSubPage: |
|
260 |
action = QAbstractSlider::SliderPageStepSub; |
|
261 |
break; |
|
262 |
case QStyle::SC_ScrollBarAddLine: |
|
263 |
action = QAbstractSlider::SliderSingleStepAdd; |
|
264 |
break; |
|
265 |
case QStyle::SC_ScrollBarSubLine: |
|
266 |
action = QAbstractSlider::SliderSingleStepSub; |
|
267 |
break; |
|
268 |
case QStyle::SC_ScrollBarFirst: |
|
269 |
action = QAbstractSlider::SliderToMinimum; |
|
270 |
break; |
|
271 |
case QStyle::SC_ScrollBarLast: |
|
272 |
action = QAbstractSlider::SliderToMaximum; |
|
273 |
break; |
|
274 |
default: |
|
275 |
break; |
|
276 |
} |
|
277 |
||
278 |
if (action) { |
|
279 |
q_func()->setRepeatAction(action, threshold); |
|
280 |
q_func()->triggerAction(action); |
|
281 |
} |
|
282 |
} |
|
283 |
||
284 |
void QScrollBarPrivate::stopRepeatAction() |
|
285 |
{ |
|
286 |
Q_Q(QScrollBar); |
|
287 |
QStyle::SubControl tmp = pressedControl; |
|
288 |
q->setRepeatAction(QAbstractSlider::SliderNoAction); |
|
289 |
pressedControl = QStyle::SC_None; |
|
290 |
||
291 |
if (tmp == QStyle::SC_ScrollBarSlider) |
|
292 |
q->setSliderDown(false); |
|
293 |
||
294 |
QStyleOptionSlider opt; |
|
295 |
q->initStyleOption(&opt); |
|
296 |
q->repaint(q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, tmp, q)); |
|
297 |
} |
|
298 |
||
299 |
/*! |
|
300 |
Initialize \a option with the values from this QScrollBar. This method |
|
301 |
is useful for subclasses when they need a QStyleOptionSlider, but don't want |
|
302 |
to fill in all the information themselves. |
|
303 |
||
304 |
\sa QStyleOption::initFrom() |
|
305 |
*/ |
|
306 |
void QScrollBar::initStyleOption(QStyleOptionSlider *option) const |
|
307 |
{ |
|
308 |
if (!option) |
|
309 |
return; |
|
310 |
||
311 |
Q_D(const QScrollBar); |
|
312 |
option->initFrom(this); |
|
313 |
option->subControls = QStyle::SC_None; |
|
314 |
option->activeSubControls = QStyle::SC_None; |
|
315 |
option->orientation = d->orientation; |
|
316 |
option->minimum = d->minimum; |
|
317 |
option->maximum = d->maximum; |
|
318 |
option->sliderPosition = d->position; |
|
319 |
option->sliderValue = d->value; |
|
320 |
option->singleStep = d->singleStep; |
|
321 |
option->pageStep = d->pageStep; |
|
322 |
option->upsideDown = d->invertedAppearance; |
|
323 |
if (d->orientation == Qt::Horizontal) |
|
324 |
option->state |= QStyle::State_Horizontal; |
|
325 |
} |
|
326 |
||
327 |
||
328 |
#define HORIZONTAL (d_func()->orientation == Qt::Horizontal) |
|
329 |
#define VERTICAL !HORIZONTAL |
|
330 |
||
331 |
/*! |
|
332 |
Constructs a vertical scroll bar. |
|
333 |
||
334 |
The \a parent arguments is sent to the QWidget constructor. |
|
335 |
||
336 |
The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the |
|
337 |
\l {QAbstractSlider::maximum} {maximum} to 99, with a |
|
338 |
\l {QAbstractSlider::singleStep} {singleStep} size of 1 and a |
|
339 |
\l {QAbstractSlider::pageStep} {pageStep} size of 10, and an |
|
340 |
initial \l {QAbstractSlider::value} {value} of 0. |
|
341 |
*/ |
|
342 |
QScrollBar::QScrollBar(QWidget *parent) |
|
343 |
: QAbstractSlider(*new QScrollBarPrivate, parent) |
|
344 |
{ |
|
345 |
d_func()->orientation = Qt::Vertical; |
|
346 |
d_func()->init(); |
|
347 |
} |
|
348 |
||
349 |
/*! |
|
350 |
Constructs a scroll bar with the given \a orientation. |
|
351 |
||
352 |
The \a parent argument is passed to the QWidget constructor. |
|
353 |
||
354 |
The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the |
|
355 |
\l {QAbstractSlider::maximum} {maximum} to 99, with a |
|
356 |
\l {QAbstractSlider::singleStep} {singleStep} size of 1 and a |
|
357 |
\l {QAbstractSlider::pageStep} {pageStep} size of 10, and an |
|
358 |
initial \l {QAbstractSlider::value} {value} of 0. |
|
359 |
*/ |
|
360 |
QScrollBar::QScrollBar(Qt::Orientation orientation, QWidget *parent) |
|
361 |
: QAbstractSlider(*new QScrollBarPrivate, parent) |
|
362 |
{ |
|
363 |
d_func()->orientation = orientation; |
|
364 |
d_func()->init(); |
|
365 |
} |
|
366 |
||
367 |
||
368 |
#ifdef QT3_SUPPORT |
|
369 |
/*! |
|
370 |
Use one of the constructors that doesn't take the \a name |
|
371 |
argument and then use setObjectName() instead. |
|
372 |
*/ |
|
373 |
QScrollBar::QScrollBar(QWidget *parent, const char *name) |
|
374 |
: QAbstractSlider(*new QScrollBarPrivate, parent) |
|
375 |
{ |
|
376 |
setObjectName(QString::fromAscii(name)); |
|
377 |
d_func()->orientation = Qt::Vertical; |
|
378 |
d_func()->init(); |
|
379 |
} |
|
380 |
||
381 |
/*! |
|
382 |
Use one of the constructors that doesn't take the \a name |
|
383 |
argument and then use setObjectName() instead. |
|
384 |
*/ |
|
385 |
QScrollBar::QScrollBar(Qt::Orientation orientation, QWidget *parent, const char *name) |
|
386 |
: QAbstractSlider(*new QScrollBarPrivate, parent) |
|
387 |
{ |
|
388 |
setObjectName(QString::fromAscii(name)); |
|
389 |
d_func()->orientation = orientation; |
|
390 |
d_func()->init(); |
|
391 |
} |
|
392 |
||
393 |
/*! |
|
394 |
Use one of the constructors that doesn't take the \a name |
|
395 |
argument and then use setObjectName() instead. |
|
396 |
*/ |
|
397 |
QScrollBar::QScrollBar(int minimum, int maximum, int lineStep, int pageStep, |
|
398 |
int value, Qt::Orientation orientation, |
|
399 |
QWidget *parent, const char *name) |
|
400 |
: QAbstractSlider(*new QScrollBarPrivate, parent) |
|
401 |
{ |
|
402 |
Q_D(QScrollBar); |
|
403 |
setObjectName(QString::fromAscii(name)); |
|
404 |
d->minimum = minimum; |
|
405 |
d->maximum = maximum; |
|
406 |
d->singleStep = lineStep; |
|
407 |
d->pageStep = pageStep; |
|
408 |
d->value = value; |
|
409 |
d->orientation = orientation; |
|
410 |
d->init(); |
|
411 |
} |
|
412 |
#endif // QT3_SUPPORT |
|
413 |
||
414 |
/*! |
|
415 |
Destroys the scroll bar. |
|
416 |
*/ |
|
417 |
QScrollBar::~QScrollBar() |
|
418 |
{ |
|
419 |
} |
|
420 |
||
421 |
void QScrollBarPrivate::init() |
|
422 |
{ |
|
423 |
Q_Q(QScrollBar); |
|
424 |
invertedControls = true; |
|
425 |
pressedControl = hoverControl = QStyle::SC_None; |
|
426 |
pointerOutsidePressedControl = false; |
|
427 |
q->setFocusPolicy(Qt::NoFocus); |
|
428 |
QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::Slider); |
|
429 |
if (orientation == Qt::Vertical) |
|
430 |
sp.transpose(); |
|
431 |
q->setSizePolicy(sp); |
|
432 |
q->setAttribute(Qt::WA_WState_OwnSizePolicy, false); |
|
433 |
q->setAttribute(Qt::WA_OpaquePaintEvent); |
|
434 |
||
435 |
#if !defined(QT_NO_CONTEXTMENU) && defined(Q_WS_WINCE) |
|
436 |
if (!q->style()->styleHint(QStyle::SH_ScrollBar_ContextMenu, 0, q)) { |
|
437 |
q->setContextMenuPolicy(Qt::PreventContextMenu); |
|
438 |
} |
|
439 |
#endif |
|
440 |
} |
|
441 |
||
442 |
#ifndef QT_NO_CONTEXTMENU |
|
443 |
/*! \reimp */ |
|
444 |
void QScrollBar::contextMenuEvent(QContextMenuEvent *event) |
|
445 |
{ |
|
446 |
if (!style()->styleHint(QStyle::SH_ScrollBar_ContextMenu, 0, this)) { |
|
447 |
QAbstractSlider::contextMenuEvent(event); |
|
448 |
return ; |
|
449 |
} |
|
450 |
||
451 |
#ifndef QT_NO_MENU |
|
452 |
bool horiz = HORIZONTAL; |
|
453 |
QPointer<QMenu> menu = new QMenu(this); |
|
454 |
QAction *actScrollHere = menu->addAction(tr("Scroll here")); |
|
455 |
menu->addSeparator(); |
|
456 |
QAction *actScrollTop = menu->addAction(horiz ? tr("Left edge") : tr("Top")); |
|
457 |
QAction *actScrollBottom = menu->addAction(horiz ? tr("Right edge") : tr("Bottom")); |
|
458 |
menu->addSeparator(); |
|
459 |
QAction *actPageUp = menu->addAction(horiz ? tr("Page left") : tr("Page up")); |
|
460 |
QAction *actPageDn = menu->addAction(horiz ? tr("Page right") : tr("Page down")); |
|
461 |
menu->addSeparator(); |
|
462 |
QAction *actScrollUp = menu->addAction(horiz ? tr("Scroll left") : tr("Scroll up")); |
|
463 |
QAction *actScrollDn = menu->addAction(horiz ? tr("Scroll right") : tr("Scroll down")); |
|
464 |
QAction *actionSelected = menu->exec(event->globalPos()); |
|
465 |
delete menu; |
|
466 |
if (actionSelected == 0) |
|
467 |
/* do nothing */ ; |
|
468 |
else if (actionSelected == actScrollHere) |
|
469 |
setValue(d_func()->pixelPosToRangeValue(horiz ? event->pos().x() : event->pos().y())); |
|
470 |
else if (actionSelected == actScrollTop) |
|
471 |
triggerAction(QAbstractSlider::SliderToMinimum); |
|
472 |
else if (actionSelected == actScrollBottom) |
|
473 |
triggerAction(QAbstractSlider::SliderToMaximum); |
|
474 |
else if (actionSelected == actPageUp) |
|
475 |
triggerAction(QAbstractSlider::SliderPageStepSub); |
|
476 |
else if (actionSelected == actPageDn) |
|
477 |
triggerAction(QAbstractSlider::SliderPageStepAdd); |
|
478 |
else if (actionSelected == actScrollUp) |
|
479 |
triggerAction(QAbstractSlider::SliderSingleStepSub); |
|
480 |
else if (actionSelected == actScrollDn) |
|
481 |
triggerAction(QAbstractSlider::SliderSingleStepAdd); |
|
482 |
#endif // QT_NO_MENU |
|
483 |
} |
|
484 |
#endif // QT_NO_CONTEXTMENU |
|
485 |
||
486 |
||
487 |
/*! \reimp */ |
|
488 |
QSize QScrollBar::sizeHint() const |
|
489 |
{ |
|
490 |
ensurePolished(); |
|
491 |
QStyleOptionSlider opt; |
|
492 |
initStyleOption(&opt); |
|
493 |
||
494 |
int scrollBarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, this); |
|
495 |
int scrollBarSliderMin = style()->pixelMetric(QStyle::PM_ScrollBarSliderMin, &opt, this); |
|
496 |
QSize size; |
|
497 |
if (opt.orientation == Qt::Horizontal) |
|
498 |
size = QSize(scrollBarExtent * 2 + scrollBarSliderMin, scrollBarExtent); |
|
499 |
else |
|
500 |
size = QSize(scrollBarExtent, scrollBarExtent * 2 + scrollBarSliderMin); |
|
501 |
||
502 |
return style()->sizeFromContents(QStyle::CT_ScrollBar, &opt, size, this) |
|
503 |
.expandedTo(QApplication::globalStrut()); |
|
504 |
} |
|
505 |
||
506 |
/*!\reimp */ |
|
507 |
void QScrollBar::sliderChange(SliderChange change) |
|
508 |
{ |
|
509 |
QAbstractSlider::sliderChange(change); |
|
510 |
} |
|
511 |
||
512 |
/*! |
|
513 |
\reimp |
|
514 |
*/ |
|
515 |
bool QScrollBar::event(QEvent *event) |
|
516 |
{ |
|
517 |
switch(event->type()) { |
|
518 |
case QEvent::HoverEnter: |
|
519 |
case QEvent::HoverLeave: |
|
520 |
case QEvent::HoverMove: |
|
521 |
if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event)) |
|
522 |
d_func()->updateHoverControl(he->pos()); |
|
523 |
break; |
|
18
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
524 |
#ifndef QT_NO_WHEELEVENT |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
525 |
case QEvent::Wheel: { |
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
18
diff
changeset
|
526 |
event->ignore(); |
18
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
527 |
// override wheel event without adding virtual function override |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
528 |
QWheelEvent *ev = static_cast<QWheelEvent *>(event); |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
529 |
int delta = ev->delta(); |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
530 |
// scrollbar is a special case - in vertical mode it reaches minimum |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
531 |
// value in the upper position, however QSlider's minimum value is on |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
532 |
// the bottom. So we need to invert a value, but since the scrollbar is |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
533 |
// inverted by default, we need to inverse the delta value for the |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
534 |
// horizontal orientation. |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
535 |
if (ev->orientation() == Qt::Horizontal) |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
536 |
delta = -delta; |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
537 |
Q_D(QScrollBar); |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
538 |
if (d->scrollByDelta(ev->orientation(), ev->modifiers(), delta)) |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
539 |
event->accept(); |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
540 |
return true; |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
541 |
} |
2f34d5167611
Revision: 201011
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
542 |
#endif |
0 | 543 |
default: |
544 |
break; |
|
545 |
} |
|
546 |
return QAbstractSlider::event(event); |
|
547 |
} |
|
548 |
||
549 |
/*! |
|
550 |
\reimp |
|
551 |
*/ |
|
552 |
void QScrollBar::paintEvent(QPaintEvent *) |
|
553 |
{ |
|
554 |
Q_D(QScrollBar); |
|
555 |
QPainter p(this); |
|
556 |
QStyleOptionSlider opt; |
|
557 |
initStyleOption(&opt); |
|
558 |
opt.subControls = QStyle::SC_All; |
|
559 |
if (d->pressedControl) { |
|
560 |
opt.activeSubControls = (QStyle::SubControl)d->pressedControl; |
|
561 |
if (!d->pointerOutsidePressedControl) |
|
562 |
opt.state |= QStyle::State_Sunken; |
|
563 |
} else { |
|
564 |
opt.activeSubControls = (QStyle::SubControl)d->hoverControl; |
|
565 |
} |
|
566 |
style()->drawComplexControl(QStyle::CC_ScrollBar, &opt, &p, this); |
|
567 |
} |
|
568 |
||
569 |
/*! |
|
570 |
\reimp |
|
571 |
*/ |
|
572 |
void QScrollBar::mousePressEvent(QMouseEvent *e) |
|
573 |
{ |
|
574 |
Q_D(QScrollBar); |
|
575 |
||
576 |
if (d->repeatActionTimer.isActive()) |
|
577 |
d->stopRepeatAction(); |
|
578 |
||
579 |
bool midButtonAbsPos = style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition, |
|
580 |
0, this); |
|
581 |
QStyleOptionSlider opt; |
|
582 |
initStyleOption(&opt); |
|
583 |
||
584 |
if (d->maximum == d->minimum // no range |
|
585 |
|| (e->buttons() & (~e->button())) // another button was clicked before |
|
586 |
|| !(e->button() == Qt::LeftButton || (midButtonAbsPos && e->button() == Qt::MidButton))) |
|
587 |
return; |
|
588 |
||
589 |
d->pressedControl = style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, e->pos(), this); |
|
590 |
d->pointerOutsidePressedControl = false; |
|
591 |
||
592 |
QRect sr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, |
|
593 |
QStyle::SC_ScrollBarSlider, this); |
|
594 |
QPoint click = e->pos(); |
|
595 |
QPoint pressValue = click - sr.center() + sr.topLeft(); |
|
596 |
d->pressValue = d->orientation == Qt::Horizontal ? d->pixelPosToRangeValue(pressValue.x()) : |
|
597 |
d->pixelPosToRangeValue(pressValue.y()); |
|
598 |
if (d->pressedControl == QStyle::SC_ScrollBarSlider) { |
|
599 |
d->clickOffset = HORIZONTAL ? (click.x()-sr.x()) : (click.y()-sr.y()); |
|
600 |
d->snapBackPosition = d->position; |
|
601 |
} |
|
602 |
||
603 |
if ((d->pressedControl == QStyle::SC_ScrollBarAddPage |
|
604 |
|| d->pressedControl == QStyle::SC_ScrollBarSubPage) |
|
605 |
&& ((midButtonAbsPos && e->button() == Qt::MidButton) |
|
606 |
|| (style()->styleHint(QStyle::SH_ScrollBar_LeftClickAbsolutePosition, &opt, this) |
|
607 |
&& e->button() == Qt::LeftButton))) { |
|
608 |
int sliderLength = HORIZONTAL ? sr.width() : sr.height(); |
|
609 |
setSliderPosition(d->pixelPosToRangeValue((HORIZONTAL ? e->pos().x() |
|
610 |
: e->pos().y()) - sliderLength / 2)); |
|
611 |
d->pressedControl = QStyle::SC_ScrollBarSlider; |
|
612 |
d->clickOffset = sliderLength / 2; |
|
613 |
} |
|
614 |
const int initialDelay = 500; // default threshold |
|
615 |
d->activateControl(d->pressedControl, initialDelay); |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
18
diff
changeset
|
616 |
QElapsedTimer time; |
0 | 617 |
time.start(); |
618 |
repaint(style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this)); |
|
619 |
if (time.elapsed() >= initialDelay && d->repeatActionTimer.isActive()) { |
|
620 |
// It took more than 500ms (the initial timer delay) to process the repaint(), we |
|
621 |
// therefore need to restart the timer in case we have a pending mouse release event; |
|
622 |
// otherwise we'll get a timer event right before the release event, |
|
623 |
// causing the repeat action to be invoked twice on a single mouse click. |
|
624 |
// 50ms is the default repeat time (see activateControl/setRepeatAction). |
|
625 |
d->repeatActionTimer.start(50, this); |
|
626 |
} |
|
627 |
if (d->pressedControl == QStyle::SC_ScrollBarSlider) |
|
628 |
setSliderDown(true); |
|
629 |
} |
|
630 |
||
631 |
||
632 |
/*! |
|
633 |
\reimp |
|
634 |
*/ |
|
635 |
void QScrollBar::mouseReleaseEvent(QMouseEvent *e) |
|
636 |
{ |
|
637 |
Q_D(QScrollBar); |
|
638 |
if (!d->pressedControl) |
|
639 |
return; |
|
640 |
||
641 |
if (e->buttons() & (~e->button())) // some other button is still pressed |
|
642 |
return; |
|
643 |
||
644 |
d->stopRepeatAction(); |
|
645 |
} |
|
646 |
||
647 |
||
648 |
/*! |
|
649 |
\reimp |
|
650 |
*/ |
|
651 |
void QScrollBar::mouseMoveEvent(QMouseEvent *e) |
|
652 |
{ |
|
653 |
Q_D(QScrollBar); |
|
654 |
if (!d->pressedControl) |
|
655 |
return; |
|
656 |
||
657 |
QStyleOptionSlider opt; |
|
658 |
initStyleOption(&opt); |
|
659 |
if (!(e->buttons() & Qt::LeftButton |
|
660 |
|| ((e->buttons() & Qt::MidButton) |
|
661 |
&& style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition, &opt, this)))) |
|
662 |
return; |
|
663 |
||
664 |
if (d->pressedControl == QStyle::SC_ScrollBarSlider) { |
|
665 |
QPoint click = e->pos(); |
|
666 |
int newPosition = d->pixelPosToRangeValue((HORIZONTAL ? click.x() : click.y()) -d->clickOffset); |
|
667 |
int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this); |
|
668 |
if (m >= 0) { |
|
669 |
QRect r = rect(); |
|
670 |
r.adjust(-m, -m, m, m); |
|
671 |
if (! r.contains(e->pos())) |
|
672 |
newPosition = d->snapBackPosition; |
|
673 |
} |
|
674 |
setSliderPosition(newPosition); |
|
675 |
} else if (!style()->styleHint(QStyle::SH_ScrollBar_ScrollWhenPointerLeavesControl, &opt, this)) { |
|
676 |
||
677 |
if (style()->styleHint(QStyle::SH_ScrollBar_RollBetweenButtons, &opt, this) |
|
678 |
&& d->pressedControl & (QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine)) { |
|
679 |
QStyle::SubControl newSc = style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, e->pos(), this); |
|
680 |
if (newSc == d->pressedControl && !d->pointerOutsidePressedControl) |
|
681 |
return; // nothing to do |
|
682 |
if (newSc & (QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine)) { |
|
683 |
d->pointerOutsidePressedControl = false; |
|
684 |
QRect scRect = style()->subControlRect(QStyle::CC_ScrollBar, &opt, newSc, this); |
|
685 |
scRect |= style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this); |
|
686 |
d->pressedControl = newSc; |
|
687 |
d->activateControl(d->pressedControl, 0); |
|
688 |
update(scRect); |
|
689 |
return; |
|
690 |
} |
|
691 |
} |
|
692 |
||
693 |
// stop scrolling when the mouse pointer leaves a control |
|
694 |
// similar to push buttons |
|
695 |
QRect pr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this); |
|
696 |
if (pr.contains(e->pos()) == d->pointerOutsidePressedControl) { |
|
697 |
if ((d->pointerOutsidePressedControl = !d->pointerOutsidePressedControl)) { |
|
698 |
d->pointerOutsidePressedControl = true; |
|
699 |
setRepeatAction(SliderNoAction); |
|
700 |
repaint(pr); |
|
701 |
} else { |
|
702 |
d->activateControl(d->pressedControl); |
|
703 |
} |
|
704 |
} |
|
705 |
} |
|
706 |
} |
|
707 |
||
708 |
||
709 |
int QScrollBarPrivate::pixelPosToRangeValue(int pos) const |
|
710 |
{ |
|
711 |
Q_Q(const QScrollBar); |
|
712 |
QStyleOptionSlider opt; |
|
713 |
q->initStyleOption(&opt); |
|
714 |
QRect gr = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, |
|
715 |
QStyle::SC_ScrollBarGroove, q); |
|
716 |
QRect sr = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, |
|
717 |
QStyle::SC_ScrollBarSlider, q); |
|
718 |
int sliderMin, sliderMax, sliderLength; |
|
719 |
||
720 |
if (orientation == Qt::Horizontal) { |
|
721 |
sliderLength = sr.width(); |
|
722 |
sliderMin = gr.x(); |
|
723 |
sliderMax = gr.right() - sliderLength + 1; |
|
724 |
if (q->layoutDirection() == Qt::RightToLeft) |
|
725 |
opt.upsideDown = !opt.upsideDown; |
|
726 |
} else { |
|
727 |
sliderLength = sr.height(); |
|
728 |
sliderMin = gr.y(); |
|
729 |
sliderMax = gr.bottom() - sliderLength + 1; |
|
730 |
} |
|
731 |
||
732 |
return QStyle::sliderValueFromPosition(minimum, maximum, pos - sliderMin, |
|
733 |
sliderMax - sliderMin, opt.upsideDown); |
|
734 |
} |
|
735 |
||
736 |
/*! \reimp |
|
737 |
*/ |
|
738 |
void QScrollBar::hideEvent(QHideEvent *) |
|
739 |
{ |
|
740 |
Q_D(QScrollBar); |
|
741 |
if (d->pressedControl) { |
|
742 |
d->pressedControl = QStyle::SC_None; |
|
743 |
setRepeatAction(SliderNoAction); |
|
744 |
} |
|
745 |
} |
|
746 |
||
747 |
/*! |
|
748 |
\fn bool QScrollBar::draggingSlider() |
|
749 |
||
750 |
Use isSliderDown() instead. |
|
751 |
*/ |
|
752 |
||
753 |
/*! \internal |
|
754 |
Returns the style option for scroll bar. |
|
755 |
*/ |
|
756 |
Q_GUI_EXPORT QStyleOptionSlider qt_qscrollbarStyleOption(QScrollBar *scrollbar) |
|
757 |
{ |
|
758 |
QStyleOptionSlider opt; |
|
759 |
scrollbar->initStyleOption(&opt); |
|
760 |
return opt; |
|
761 |
} |
|
762 |
||
763 |
QT_END_NAMESPACE |
|
764 |
||
765 |
#endif // QT_NO_SCROLLBAR |