source: trunk/src/gui/widgets/qabstractscrollarea.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 45.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qabstractscrollarea.h"
43
44#ifndef QT_NO_SCROLLAREA
45
46#include "qscrollbar.h"
47#include "qapplication.h"
48#include "qstyle.h"
49#include "qstyleoption.h"
50#include "qevent.h"
51#include "qdebug.h"
52#include "qboxlayout.h"
53#include "qpainter.h"
54#include "qmargins.h"
55
56#include "qabstractscrollarea_p.h"
57#include <qwidget.h>
58
59#include <private/qapplication_p.h>
60
61#ifdef Q_WS_MAC
62#include <private/qt_mac_p.h>
63#include <private/qt_cocoa_helpers_mac_p.h>
64#endif
65
66QT_BEGIN_NAMESPACE
67
68/*!
69 \class QAbstractScrollArea
70 \brief The QAbstractScrollArea widget provides a scrolling area with
71 on-demand scroll bars.
72
73 \ingroup abstractwidgets
74
75 QAbstractScrollArea is a low-level abstraction of a scrolling
76 area. The area provides a central widget called the viewport, in
77 which the contents of the area is to be scrolled (i.e, the
78 visible parts of the contents are rendered in the viewport).
79
80 Next to the viewport is a vertical scroll bar, and below is a
81 horizontal scroll bar. When all of the area contents fits in the
82 viewport, each scroll bar can be either visible or hidden
83 depending on the scroll bar's Qt::ScrollBarPolicy. When a scroll
84 bar is hidden, the viewport expands in order to cover all
85 available space. When a scroll bar becomes visible again, the
86 viewport shrinks in order to make room for the scroll bar.
87
88 It is possible to reserve a margin area around the viewport, see
89 setViewportMargins(). The feature is mostly used to place a
90 QHeaderView widget above or beside the scrolling area. Subclasses
91 of QAbstractScrollArea should implement margins.
92
93 When inheriting QAbstractScrollArea, you need to do the
94 following:
95
96 \list
97 \o Control the scroll bars by setting their
98 range, value, page step, and tracking their
99 movements.
100 \o Draw the contents of the area in the viewport according
101 to the values of the scroll bars.
102 \o Handle events received by the viewport in
103 viewportEvent() - notably resize events.
104 \o Use \c{viewport->update()} to update the contents of the
105 viewport instead of \l{QWidget::update()}{update()}
106 as all painting operations take place on the viewport.
107 \endlist
108
109 With a scroll bar policy of Qt::ScrollBarAsNeeded (the default),
110 QAbstractScrollArea shows scroll bars when they provide a non-zero
111 scrolling range, and hides them otherwise.
112
113 The scroll bars and viewport should be updated whenever the viewport
114 receives a resize event or the size of the contents changes.
115 The viewport also needs to be updated when the scroll bars
116 values change. The initial values of the scroll bars are often
117 set when the area receives new contents.
118
119 We give a simple example, in which we have implemented a scroll area
120 that can scroll any QWidget. We make the widget a child of the
121 viewport; this way, we do not have to calculate which part of
122 the widget to draw but can simply move the widget with
123 QWidget::move(). When the area contents or the viewport size
124 changes, we do the following:
125
126 \snippet doc/src/snippets/myscrollarea.cpp 1
127
128 When the scroll bars change value, we need to update the widget
129 position, i.e., find the part of the widget that is to be drawn in
130 the viewport:
131
132 \snippet doc/src/snippets/myscrollarea.cpp 0
133
134 In order to track scroll bar movements, reimplement the virtual
135 function scrollContentsBy(). In order to fine-tune scrolling
136 behavior, connect to a scroll bar's
137 QAbstractSlider::actionTriggered() signal and adjust the \l
138 QAbstractSlider::sliderPosition as you wish.
139
140 For convenience, QAbstractScrollArea makes all viewport events
141 available in the virtual viewportEvent() handler. QWidget's
142 specialized handlers are remapped to viewport events in the cases
143 where this makes sense. The remapped specialized handlers are:
144 paintEvent(), mousePressEvent(), mouseReleaseEvent(),
145 mouseDoubleClickEvent(), mouseMoveEvent(), wheelEvent(),
146 dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(), dropEvent(),
147 contextMenuEvent(), and resizeEvent().
148
149 QScrollArea, which inherits QAbstractScrollArea, provides smooth
150 scrolling for any QWidget (i.e., the widget is scrolled pixel by
151 pixel). You only need to subclass QAbstractScrollArea if you need
152 more specialized behavior. This is, for instance, true if the
153 entire contents of the area is not suitable for being drawn on a
154 QWidget or if you do not want smooth scrolling.
155
156 \sa QScrollArea
157*/
158
159QAbstractScrollAreaPrivate::QAbstractScrollAreaPrivate()
160 :hbar(0), vbar(0), vbarpolicy(Qt::ScrollBarAsNeeded), hbarpolicy(Qt::ScrollBarAsNeeded),
161 viewport(0), cornerWidget(0), left(0), top(0), right(0), bottom(0),
162 xoffset(0), yoffset(0), viewportFilter(0)
163#ifdef Q_WS_WIN
164 , singleFingerPanEnabled(false)
165#endif
166{
167}
168
169QAbstractScrollAreaScrollBarContainer::QAbstractScrollAreaScrollBarContainer(Qt::Orientation orientation, QWidget *parent)
170 :QWidget(parent), scrollBar(new QScrollBar(orientation, this)),
171 layout(new QBoxLayout(orientation == Qt::Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom)),
172 orientation(orientation)
173{
174 setLayout(layout);
175 layout->setMargin(0);
176 layout->setSpacing(0);
177 layout->addWidget(scrollBar);
178}
179
180/*! \internal
181 Adds a widget to the scroll bar container.
182*/
183void QAbstractScrollAreaScrollBarContainer::addWidget(QWidget *widget, LogicalPosition position)
184{
185 QSizePolicy policy = widget->sizePolicy();
186 if (orientation == Qt::Vertical)
187 policy.setHorizontalPolicy(QSizePolicy::Ignored);
188 else
189 policy.setVerticalPolicy(QSizePolicy::Ignored);
190 widget->setSizePolicy(policy);
191 widget->setParent(this);
192
193 const int insertIndex = (position & LogicalLeft) ? 0 : scrollBarLayoutIndex() + 1;
194 layout->insertWidget(insertIndex, widget);
195}
196
197/*! \internal
198 Retuns a list of scroll bar widgets for the given position. The scroll bar
199 itself is not returned.
200*/
201QWidgetList QAbstractScrollAreaScrollBarContainer::widgets(LogicalPosition position)
202{
203 QWidgetList list;
204 const int scrollBarIndex = scrollBarLayoutIndex();
205 if (position == LogicalLeft) {
206 for (int i = 0; i < scrollBarIndex; ++i)
207 list.append(layout->itemAt(i)->widget());
208 } else if (position == LogicalRight) {
209 const int layoutItemCount = layout->count();
210 for (int i = scrollBarIndex + 1; i < layoutItemCount; ++i)
211 list.append(layout->itemAt(i)->widget());
212 }
213 return list;
214}
215
216/*! \internal
217 Returns the layout index for the scroll bar. This needs to be
218 recalculated by a linear search for each use, since items in
219 the layout can be removed at any time (i.e. when a widget is
220 deleted or re-parented).
221*/
222int QAbstractScrollAreaScrollBarContainer::scrollBarLayoutIndex() const
223{
224 const int layoutItemCount = layout->count();
225 for (int i = 0; i < layoutItemCount; ++i) {
226 if (qobject_cast<QScrollBar *>(layout->itemAt(i)->widget()))
227 return i;
228 }
229 return -1;
230}
231
232/*! \internal
233*/
234void QAbstractScrollAreaPrivate::replaceScrollBar(QScrollBar *scrollBar,
235 Qt::Orientation orientation)
236{
237 Q_Q(QAbstractScrollArea);
238
239 QAbstractScrollAreaScrollBarContainer *container = scrollBarContainers[orientation];
240 bool horizontal = (orientation == Qt::Horizontal);
241 QScrollBar *oldBar = horizontal ? hbar : vbar;
242 if (horizontal)
243 hbar = scrollBar;
244 else
245 vbar = scrollBar;
246 scrollBar->setParent(container);
247 container->scrollBar = scrollBar;
248 container->layout->removeWidget(oldBar);
249 container->layout->insertWidget(0, scrollBar);
250 scrollBar->setVisible(oldBar->isVisibleTo(container));
251 scrollBar->setInvertedAppearance(oldBar->invertedAppearance());
252 scrollBar->setInvertedControls(oldBar->invertedControls());
253 scrollBar->setRange(oldBar->minimum(), oldBar->maximum());
254 scrollBar->setOrientation(oldBar->orientation());
255 scrollBar->setPageStep(oldBar->pageStep());
256 scrollBar->setSingleStep(oldBar->singleStep());
257 scrollBar->setSliderDown(oldBar->isSliderDown());
258 scrollBar->setSliderPosition(oldBar->sliderPosition());
259 scrollBar->setTracking(oldBar->hasTracking());
260 scrollBar->setValue(oldBar->value());
261 delete oldBar;
262
263 QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
264 q, horizontal ? SLOT(_q_hslide(int)) : SLOT(_q_vslide(int)));
265 QObject::connect(scrollBar, SIGNAL(rangeChanged(int,int)),
266 q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
267}
268
269void QAbstractScrollAreaPrivate::init()
270{
271 Q_Q(QAbstractScrollArea);
272 viewport = new QWidget(q);
273 viewport->setObjectName(QLatin1String("qt_scrollarea_viewport"));
274 viewport->setBackgroundRole(QPalette::Base);
275 viewport->setAutoFillBackground(true);
276 scrollBarContainers[Qt::Horizontal] = new QAbstractScrollAreaScrollBarContainer(Qt::Horizontal, q);
277 scrollBarContainers[Qt::Horizontal]->setObjectName(QLatin1String("qt_scrollarea_hcontainer"));
278 hbar = scrollBarContainers[Qt::Horizontal]->scrollBar;
279 hbar->setRange(0,0);
280 scrollBarContainers[Qt::Horizontal]->setVisible(false);
281 QObject::connect(hbar, SIGNAL(valueChanged(int)), q, SLOT(_q_hslide(int)));
282 QObject::connect(hbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
283 scrollBarContainers[Qt::Vertical] = new QAbstractScrollAreaScrollBarContainer(Qt::Vertical, q);
284 scrollBarContainers[Qt::Vertical]->setObjectName(QLatin1String("qt_scrollarea_vcontainer"));
285 vbar = scrollBarContainers[Qt::Vertical]->scrollBar;
286 vbar->setRange(0,0);
287 scrollBarContainers[Qt::Vertical]->setVisible(false);
288 QObject::connect(vbar, SIGNAL(valueChanged(int)), q, SLOT(_q_vslide(int)));
289 QObject::connect(vbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
290 viewportFilter.reset(new QAbstractScrollAreaFilter(this));
291 viewport->installEventFilter(viewportFilter.data());
292 viewport->setFocusProxy(q);
293 q->setFocusPolicy(Qt::WheelFocus);
294 q->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
295 q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
296 layoutChildren();
297#ifndef Q_WS_MAC
298 viewport->grabGesture(Qt::PanGesture);
299#endif
300}
301
302#ifdef Q_WS_WIN
303void QAbstractScrollAreaPrivate::setSingleFingerPanEnabled(bool on)
304{
305 singleFingerPanEnabled = on;
306 QWidgetPrivate *dd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(viewport));
307 if (dd)
308 dd->winSetupGestures();
309}
310#endif // Q_WS_WIN
311
312void QAbstractScrollAreaPrivate::layoutChildren()
313{
314 Q_Q(QAbstractScrollArea);
315 bool needh = (hbarpolicy == Qt::ScrollBarAlwaysOn
316 || (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum()));
317
318 bool needv = (vbarpolicy == Qt::ScrollBarAlwaysOn
319 || (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum()));
320
321#ifdef Q_WS_MAC
322 QWidget * const window = q->window();
323
324 // Use small scroll bars for tool windows, to match the native size grip.
325 bool hbarIsSmall = hbar->testAttribute(Qt::WA_MacSmallSize);
326 bool vbarIsSmall = vbar->testAttribute(Qt::WA_MacSmallSize);
327 const Qt::WindowType windowType = window->windowType();
328 if (windowType == Qt::Tool) {
329 if (!hbarIsSmall) {
330 hbar->setAttribute(Qt::WA_MacMiniSize, false);
331 hbar->setAttribute(Qt::WA_MacNormalSize, false);
332 hbar->setAttribute(Qt::WA_MacSmallSize, true);
333 }
334 if (!vbarIsSmall) {
335 vbar->setAttribute(Qt::WA_MacMiniSize, false);
336 vbar->setAttribute(Qt::WA_MacNormalSize, false);
337 vbar->setAttribute(Qt::WA_MacSmallSize, true);
338 }
339 } else {
340 if (hbarIsSmall) {
341 hbar->setAttribute(Qt::WA_MacMiniSize, false);
342 hbar->setAttribute(Qt::WA_MacNormalSize, false);
343 hbar->setAttribute(Qt::WA_MacSmallSize, false);
344 }
345 if (vbarIsSmall) {
346 vbar->setAttribute(Qt::WA_MacMiniSize, false);
347 vbar->setAttribute(Qt::WA_MacNormalSize, false);
348 vbar->setAttribute(Qt::WA_MacSmallSize, false);
349 }
350 }
351#endif
352
353 const int hsbExt = hbar->sizeHint().height();
354 const int vsbExt = vbar->sizeHint().width();
355 const QPoint extPoint(vsbExt, hsbExt);
356 const QSize extSize(vsbExt, hsbExt);
357
358 const QRect widgetRect = q->rect();
359 QStyleOption opt(0);
360 opt.init(q);
361
362 const bool hasCornerWidget = (cornerWidget != 0);
363
364// If the scroll bars are at the very right and bottom of the window we
365// move their positions to be aligned with the size grip.
366#ifdef Q_WS_MAC
367 // Check if a native sizegrip is present.
368 bool hasMacReverseSizeGrip = false;
369 bool hasMacSizeGrip = false;
370 bool nativeGripPresent = false;
371 if (q->testAttribute(Qt::WA_WState_Created))
372 nativeGripPresent = qt_mac_checkForNativeSizeGrip(q);
373
374 if (nativeGripPresent) {
375 // Look for a native size grip at the visual window bottom right and at the
376 // absolute window bottom right. In reverse mode, the native size grip does not
377 // swich side, so we need to check if it is on the "wrong side".
378 const QPoint scrollAreaBottomRight = q->mapTo(window, widgetRect.bottomRight() - QPoint(frameWidth, frameWidth));
379 const QPoint windowBottomRight = window->rect().bottomRight();
380 const QPoint visualWindowBottomRight = QStyle::visualPos(opt.direction, opt.rect, windowBottomRight);
381 const QPoint offset = windowBottomRight - scrollAreaBottomRight;
382 const QPoint visualOffset = visualWindowBottomRight - scrollAreaBottomRight;
383 hasMacSizeGrip = (visualOffset.manhattanLength() < vsbExt);
384 hasMacReverseSizeGrip = (hasMacSizeGrip == false && (offset.manhattanLength() < hsbExt));
385 }
386#endif
387
388 QPoint cornerOffset(needv ? vsbExt : 0, needh ? hsbExt : 0);
389 QRect controlsRect;
390 QRect viewportRect;
391
392 // In FrameOnlyAroundContents mode the frame is drawn between the controls and
393 // the viewport, else the frame rect is equal to the widget rect.
394 if ((frameStyle != QFrame::NoFrame) &&
395 q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, q)) {
396 controlsRect = widgetRect;
397 const int extra = q->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, q);
398 const QPoint cornerExtra(needv ? extra : 0, needh ? extra : 0);
399 QRect frameRect = widgetRect;
400 frameRect.adjust(0, 0, -cornerOffset.x() - cornerExtra.x(), -cornerOffset.y() - cornerExtra.y());
401 q->setFrameRect(QStyle::visualRect(opt.direction, opt.rect, frameRect));
402 // The frame rect needs to be in logical coords, however we need to flip
403 // the contentsRect back before passing it on to the viewportRect
404 // since the viewportRect has its logical coords calculated later.
405 viewportRect = QStyle::visualRect(opt.direction, opt.rect, q->contentsRect());
406 } else {
407 q->setFrameRect(QStyle::visualRect(opt.direction, opt.rect, widgetRect));
408 controlsRect = q->contentsRect();
409 viewportRect = QRect(controlsRect.topLeft(), controlsRect.bottomRight() - cornerOffset);
410 }
411
412 // If we have a corner widget and are only showing one scroll bar, we need to move it
413 // to make room for the corner widget.
414 if (hasCornerWidget && (needv || needh))
415 cornerOffset = extPoint;
416
417#ifdef Q_WS_MAC
418 // Also move the scroll bars if they are covered by the native Mac size grip.
419 if (hasMacSizeGrip)
420 cornerOffset = extPoint;
421#endif
422
423 // The corner point is where the scroll bar rects, the corner widget rect and the
424 // viewport rect meets.
425 const QPoint cornerPoint(controlsRect.bottomRight() + QPoint(1, 1) - cornerOffset);
426
427 // Some styles paints the corner if both scorllbars are showing and there is
428 // no corner widget. Also, on the Mac we paint if there is a native
429 // (transparent) sizegrip in the area where a corner widget would be.
430 if ((needv && needh && hasCornerWidget == false)
431 || ((needv || needh)
432#ifdef Q_WS_MAC
433 && hasMacSizeGrip
434#endif
435 )
436 ) {
437 cornerPaintingRect = QStyle::visualRect(opt.direction, opt.rect, QRect(cornerPoint, extSize));
438 } else {
439 cornerPaintingRect = QRect();
440 }
441
442#ifdef Q_WS_MAC
443 if (hasMacReverseSizeGrip)
444 reverseCornerPaintingRect = QRect(controlsRect.bottomRight() + QPoint(1, 1) - extPoint, extSize);
445 else
446 reverseCornerPaintingRect = QRect();
447#endif
448
449 if (needh) {
450 QRect horizontalScrollBarRect(QPoint(controlsRect.left(), cornerPoint.y()), QPoint(cornerPoint.x() - 1, controlsRect.bottom()));
451#ifdef Q_WS_MAC
452 if (hasMacReverseSizeGrip)
453 horizontalScrollBarRect.adjust(vsbExt, 0, 0, 0);
454#endif
455 scrollBarContainers[Qt::Horizontal]->setGeometry(QStyle::visualRect(opt.direction, opt.rect, horizontalScrollBarRect));
456 scrollBarContainers[Qt::Horizontal]->raise();
457 }
458
459 if (needv) {
460 const QRect verticalScrollBarRect (QPoint(cornerPoint.x(), controlsRect.top()), QPoint(controlsRect.right(), cornerPoint.y() - 1));
461 scrollBarContainers[Qt::Vertical]->setGeometry(QStyle::visualRect(opt.direction, opt.rect, verticalScrollBarRect));
462 scrollBarContainers[Qt::Vertical]->raise();
463 }
464
465 if (cornerWidget) {
466 const QRect cornerWidgetRect(cornerPoint, controlsRect.bottomRight());
467 cornerWidget->setGeometry(QStyle::visualRect(opt.direction, opt.rect, cornerWidgetRect));
468 }
469
470 scrollBarContainers[Qt::Horizontal]->setVisible(needh);
471 scrollBarContainers[Qt::Vertical]->setVisible(needv);
472
473 if (q->isRightToLeft())
474 viewportRect.adjust(right, top, -left, -bottom);
475 else
476 viewportRect.adjust(left, top, -right, -bottom);
477
478 viewport->setGeometry(QStyle::visualRect(opt.direction, opt.rect, viewportRect)); // resize the viewport last
479}
480
481/*!
482 \internal
483
484 Creates a new QAbstractScrollAreaPrivate, \a dd with the given \a parent.
485*/
486QAbstractScrollArea::QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget *parent)
487 :QFrame(dd, parent)
488{
489 Q_D(QAbstractScrollArea);
490 QT_TRY {
491 d->init();
492 } QT_CATCH(...) {
493 d->viewportFilter.reset();
494 QT_RETHROW;
495 }
496}
497
498/*!
499 Constructs a viewport.
500
501 The \a parent arguments is sent to the QWidget constructor.
502*/
503QAbstractScrollArea::QAbstractScrollArea(QWidget *parent)
504 :QFrame(*new QAbstractScrollAreaPrivate, parent)
505{
506 Q_D(QAbstractScrollArea);
507 QT_TRY {
508 d->init();
509 } QT_CATCH(...) {
510 d->viewportFilter.reset();
511 QT_RETHROW;
512 }
513}
514
515
516/*!
517 Destroys the viewport.
518 */
519QAbstractScrollArea::~QAbstractScrollArea()
520{
521 Q_D(QAbstractScrollArea);
522 // reset it here, otherwise we'll have a dangling pointer in ~QWidget
523 d->viewportFilter.reset();
524}
525
526
527/*!
528 \since 4.2
529 Sets the viewport to be the given \a widget.
530 The QAbstractScrollArea will take ownership of the given \a widget.
531
532 If \a widget is 0, QAbstractScrollArea will assign a new QWidget instance
533 for the viewport.
534
535 \sa viewport()
536*/
537void QAbstractScrollArea::setViewport(QWidget *widget)
538{
539 Q_D(QAbstractScrollArea);
540 if (widget != d->viewport) {
541 QWidget *oldViewport = d->viewport;
542 if (!widget)
543 widget = new QWidget;
544 d->viewport = widget;
545 d->viewport->setParent(this);
546 d->viewport->setFocusProxy(this);
547 d->viewport->installEventFilter(d->viewportFilter.data());
548#ifndef Q_WS_MAC
549 d->viewport->grabGesture(Qt::PanGesture);
550#endif
551 d->layoutChildren();
552 if (isVisible())
553 d->viewport->show();
554 QMetaObject::invokeMethod(this, "setupViewport", Q_ARG(QWidget *, widget));
555 delete oldViewport;
556 }
557}
558
559/*!
560 Returns the viewport widget.
561
562 Use the QScrollArea::widget() function to retrieve the contents of
563 the viewport widget.
564
565 \sa QScrollArea::widget()
566*/
567QWidget *QAbstractScrollArea::viewport() const
568{
569 Q_D(const QAbstractScrollArea);
570 return d->viewport;
571}
572
573
574/*!
575Returns the size of the viewport as if the scroll bars had no valid
576scrolling range.
577*/
578// ### still thinking about the name
579QSize QAbstractScrollArea::maximumViewportSize() const
580{
581 Q_D(const QAbstractScrollArea);
582 int hsbExt = d->hbar->sizeHint().height();
583 int vsbExt = d->vbar->sizeHint().width();
584
585 int f = 2 * d->frameWidth;
586 QSize max = size() - QSize(f + d->left + d->right, f + d->top + d->bottom);
587 if (d->vbarpolicy == Qt::ScrollBarAlwaysOn)
588 max.rwidth() -= vsbExt;
589 if (d->hbarpolicy == Qt::ScrollBarAlwaysOn)
590 max.rheight() -= hsbExt;
591 return max;
592}
593
594/*!
595 \property QAbstractScrollArea::verticalScrollBarPolicy
596 \brief the policy for the vertical scroll bar
597
598 The default policy is Qt::ScrollBarAsNeeded.
599
600 \sa horizontalScrollBarPolicy
601*/
602
603Qt::ScrollBarPolicy QAbstractScrollArea::verticalScrollBarPolicy() const
604{
605 Q_D(const QAbstractScrollArea);
606 return d->vbarpolicy;
607}
608
609void QAbstractScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
610{
611 Q_D(QAbstractScrollArea);
612 const Qt::ScrollBarPolicy oldPolicy = d->vbarpolicy;
613 d->vbarpolicy = policy;
614 if (isVisible())
615 d->layoutChildren();
616 if (oldPolicy != d->vbarpolicy)
617 d->scrollBarPolicyChanged(Qt::Vertical, d->vbarpolicy);
618}
619
620
621/*!
622 Returns the vertical scroll bar.
623
624 \sa verticalScrollBarPolicy, horizontalScrollBar()
625 */
626QScrollBar *QAbstractScrollArea::verticalScrollBar() const
627{
628 Q_D(const QAbstractScrollArea);
629 return d->vbar;
630}
631
632/*!
633 \since 4.2
634 Replaces the existing vertical scroll bar with \a scrollBar, and sets all
635 the former scroll bar's slider properties on the new scroll bar. The former
636 scroll bar is then deleted.
637
638 QAbstractScrollArea already provides vertical and horizontal scroll bars by
639 default. You can call this function to replace the default vertical
640 scroll bar with your own custom scroll bar.
641
642 \sa verticalScrollBar(), setHorizontalScrollBar()
643*/
644void QAbstractScrollArea::setVerticalScrollBar(QScrollBar *scrollBar)
645{
646 Q_D(QAbstractScrollArea);
647 if (!scrollBar) {
648 qWarning("QAbstractScrollArea::setVerticalScrollBar: Cannot set a null scroll bar");
649 return;
650 }
651
652 d->replaceScrollBar(scrollBar, Qt::Vertical);
653}
654
655/*!
656 \property QAbstractScrollArea::horizontalScrollBarPolicy
657 \brief the policy for the horizontal scroll bar
658
659 The default policy is Qt::ScrollBarAsNeeded.
660
661 \sa verticalScrollBarPolicy
662*/
663
664Qt::ScrollBarPolicy QAbstractScrollArea::horizontalScrollBarPolicy() const
665{
666 Q_D(const QAbstractScrollArea);
667 return d->hbarpolicy;
668}
669
670void QAbstractScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
671{
672 Q_D(QAbstractScrollArea);
673 const Qt::ScrollBarPolicy oldPolicy = d->hbarpolicy;
674 d->hbarpolicy = policy;
675 if (isVisible())
676 d->layoutChildren();
677 if (oldPolicy != d->hbarpolicy)
678 d->scrollBarPolicyChanged(Qt::Horizontal, d->hbarpolicy);
679}
680
681/*!
682 Returns the horizontal scroll bar.
683
684 \sa horizontalScrollBarPolicy, verticalScrollBar()
685 */
686QScrollBar *QAbstractScrollArea::horizontalScrollBar() const
687{
688 Q_D(const QAbstractScrollArea);
689 return d->hbar;
690}
691
692/*!
693 \since 4.2
694
695 Replaces the existing horizontal scroll bar with \a scrollBar, and sets all
696 the former scroll bar's slider properties on the new scroll bar. The former
697 scroll bar is then deleted.
698
699 QAbstractScrollArea already provides horizontal and vertical scroll bars by
700 default. You can call this function to replace the default horizontal
701 scroll bar with your own custom scroll bar.
702
703 \sa horizontalScrollBar(), setVerticalScrollBar()
704*/
705void QAbstractScrollArea::setHorizontalScrollBar(QScrollBar *scrollBar)
706{
707 Q_D(QAbstractScrollArea);
708 if (!scrollBar) {
709 qWarning("QAbstractScrollArea::setHorizontalScrollBar: Cannot set a null scroll bar");
710 return;
711 }
712
713 d->replaceScrollBar(scrollBar, Qt::Horizontal);
714}
715
716/*!
717 \since 4.2
718
719 Returns the widget in the corner between the two scroll bars.
720
721 By default, no corner widget is present.
722*/
723QWidget *QAbstractScrollArea::cornerWidget() const
724{
725 Q_D(const QAbstractScrollArea);
726 return d->cornerWidget;
727}
728
729/*!
730 \since 4.2
731
732 Sets the widget in the corner between the two scroll bars to be
733 \a widget.
734
735 You will probably also want to set at least one of the scroll bar
736 modes to \c AlwaysOn.
737
738 Passing 0 shows no widget in the corner.
739
740 Any previous corner widget is hidden.
741
742 You may call setCornerWidget() with the same widget at different
743 times.
744
745 All widgets set here will be deleted by the scroll area when it is
746 destroyed unless you separately reparent the widget after setting
747 some other corner widget (or 0).
748
749 Any \e newly set widget should have no current parent.
750
751 By default, no corner widget is present.
752
753 \sa horizontalScrollBarPolicy, horizontalScrollBarPolicy
754*/
755void QAbstractScrollArea::setCornerWidget(QWidget *widget)
756{
757 Q_D(QAbstractScrollArea);
758 QWidget* oldWidget = d->cornerWidget;
759 if (oldWidget != widget) {
760 if (oldWidget)
761 oldWidget->hide();
762 d->cornerWidget = widget;
763
764 if (widget && widget->parentWidget() != this)
765 widget->setParent(this);
766
767 d->layoutChildren();
768 if (widget)
769 widget->show();
770 } else {
771 d->cornerWidget = widget;
772 d->layoutChildren();
773 }
774}
775
776/*!
777 \since 4.2
778 Adds \a widget as a scroll bar widget in the location specified
779 by \a alignment.
780
781 Scroll bar widgets are shown next to the horizontal or vertical
782 scroll bar, and can be placed on either side of it. If you want
783 the scroll bar widgets to be always visible, set the
784 scrollBarPolicy for the corresponding scroll bar to \c AlwaysOn.
785
786 \a alignment must be one of Qt::Alignleft and Qt::AlignRight,
787 which maps to the horizontal scroll bar, or Qt::AlignTop and
788 Qt::AlignBottom, which maps to the vertical scroll bar.
789
790 A scroll bar widget can be removed by either re-parenting the
791 widget or deleting it. It's also possible to hide a widget with
792 QWidget::hide()
793
794 The scroll bar widget will be resized to fit the scroll bar
795 geometry for the current style. The following describes the case
796 for scroll bar widgets on the horizontal scroll bar:
797
798 The height of the widget will be set to match the height of the
799 scroll bar. To control the width of the widget, use
800 QWidget::setMinimumWidth and QWidget::setMaximumWidth, or
801 implement QWidget::sizeHint() and set a horizontal size policy.
802 If you want a square widget, call
803 QStyle::pixelMetric(QStyle::PM_ScrollBarExtent) and set the
804 width to this value.
805
806 \sa scrollBarWidgets()
807*/
808void QAbstractScrollArea::addScrollBarWidget(QWidget *widget, Qt::Alignment alignment)
809{
810 Q_D(QAbstractScrollArea);
811
812 if (widget == 0)
813 return;
814
815 const Qt::Orientation scrollBarOrientation
816 = ((alignment & Qt::AlignLeft) || (alignment & Qt::AlignRight)) ? Qt::Horizontal : Qt::Vertical;
817 const QAbstractScrollAreaScrollBarContainer::LogicalPosition position
818 = ((alignment & Qt::AlignRight) || (alignment & Qt::AlignBottom))
819 ? QAbstractScrollAreaScrollBarContainer::LogicalRight : QAbstractScrollAreaScrollBarContainer::LogicalLeft;
820 d->scrollBarContainers[scrollBarOrientation]->addWidget(widget, position);
821 d->layoutChildren();
822 if (isHidden() == false)
823 widget->show();
824}
825
826/*!
827 \since 4.2
828 Returns a list of the currently set scroll bar widgets. \a alignment
829 can be any combination of the four location flags.
830
831 \sa addScrollBarWidget()
832*/
833QWidgetList QAbstractScrollArea::scrollBarWidgets(Qt::Alignment alignment)
834{
835 Q_D(QAbstractScrollArea);
836
837 QWidgetList list;
838
839 if (alignment & Qt::AlignLeft)
840 list += d->scrollBarContainers[Qt::Horizontal]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalLeft);
841 if (alignment & Qt::AlignRight)
842 list += d->scrollBarContainers[Qt::Horizontal]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalRight);
843 if (alignment & Qt::AlignTop)
844 list += d->scrollBarContainers[Qt::Vertical]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalLeft);
845 if (alignment & Qt::AlignBottom)
846 list += d->scrollBarContainers[Qt::Vertical]->widgets(QAbstractScrollAreaScrollBarContainer::LogicalRight);
847
848 return list;
849}
850
851/*!
852 Sets the margins around the scrolling area to \a left, \a top, \a
853 right and \a bottom. This is useful for applications such as
854 spreadsheets with "locked" rows and columns. The marginal space is
855 is left blank; put widgets in the unused area.
856
857 Note that this function is frequently called by QTreeView and
858 QTableView, so margins must be implemented by QAbstractScrollArea
859 subclasses. Also, if the subclasses are to be used in item views,
860 they should not call this function.
861
862 By default all margins are zero.
863
864*/
865void QAbstractScrollArea::setViewportMargins(int left, int top, int right, int bottom)
866{
867 Q_D(QAbstractScrollArea);
868 d->left = left;
869 d->top = top;
870 d->right = right;
871 d->bottom = bottom;
872 d->layoutChildren();
873}
874
875/*!
876 \since 4.6
877 Sets \a margins around the scrolling area. This is useful for
878 applications such as spreadsheets with "locked" rows and columns.
879 The marginal space is is left blank; put widgets in the unused
880 area.
881
882 By default all margins are zero.
883
884*/
885void QAbstractScrollArea::setViewportMargins(const QMargins &margins)
886{
887 setViewportMargins(margins.left(), margins.top(),
888 margins.right(), margins.bottom());
889}
890
891/*!
892 \fn bool QAbstractScrollArea::event(QEvent *event)
893
894 \reimp
895
896 This is the main event handler for the QAbstractScrollArea widget (\e not
897 the scrolling area viewport()). The specified \a event is a general event
898 object that may need to be cast to the appropriate class depending on its
899 type.
900
901 \sa QEvent::type()
902*/
903bool QAbstractScrollArea::event(QEvent *e)
904{
905 Q_D(QAbstractScrollArea);
906 switch (e->type()) {
907 case QEvent::AcceptDropsChange:
908 // There was a chance that with accessibility client we get an
909 // event before the viewport was created.
910 // Also, in some cases we might get here from QWidget::event() virtual function which is (indirectly) called
911 // from the viewport constructor at the time when the d->viewport is not yet initialized even without any
912 // accessibility client. See qabstractscrollarea autotest for a test case.
913 if (d->viewport)
914 d->viewport->setAcceptDrops(acceptDrops());
915 break;
916 case QEvent::MouseTrackingChange:
917 d->viewport->setMouseTracking(hasMouseTracking());
918 break;
919 case QEvent::Resize:
920 d->layoutChildren();
921 break;
922 case QEvent::Paint: {
923 QStyleOption option;
924 option.initFrom(this);
925 if (d->cornerPaintingRect.isValid()) {
926 option.rect = d->cornerPaintingRect;
927 QPainter p(this);
928 style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this);
929 }
930#ifdef Q_WS_MAC
931 if (d->reverseCornerPaintingRect.isValid()) {
932 option.rect = d->reverseCornerPaintingRect;
933 QPainter p(this);
934 style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this);
935 }
936#endif
937 }
938 QFrame::paintEvent((QPaintEvent*)e);
939 break;
940#ifndef QT_NO_CONTEXTMENU
941 case QEvent::ContextMenu:
942 if (static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard)
943 return QFrame::event(e);
944 e->ignore();
945 break;
946#endif // QT_NO_CONTEXTMENU
947 case QEvent::MouseButtonPress:
948 case QEvent::MouseButtonRelease:
949 case QEvent::MouseButtonDblClick:
950 case QEvent::MouseMove:
951 case QEvent::Wheel:
952#ifndef QT_NO_DRAGANDDROP
953 case QEvent::Drop:
954 case QEvent::DragEnter:
955 case QEvent::DragMove:
956 case QEvent::DragLeave:
957#endif
958 // ignore touch events in case they have been propagated from the viewport
959 case QEvent::TouchBegin:
960 case QEvent::TouchUpdate:
961 case QEvent::TouchEnd:
962 return false;
963 case QEvent::Gesture:
964 {
965 QGestureEvent *ge = static_cast<QGestureEvent *>(e);
966 QPanGesture *g = static_cast<QPanGesture *>(ge->gesture(Qt::PanGesture));
967 if (g) {
968 QScrollBar *hBar = horizontalScrollBar();
969 QScrollBar *vBar = verticalScrollBar();
970 QPointF delta = g->delta();
971 if (!delta.isNull()) {
972 if (QApplication::isRightToLeft())
973 delta.rx() *= -1;
974 int newX = hBar->value() - delta.x();
975 int newY = vBar->value() - delta.y();
976 hBar->setValue(newX);
977 vBar->setValue(newY);
978 }
979 return true;
980 }
981 return false;
982 }
983 case QEvent::StyleChange:
984 case QEvent::LayoutDirectionChange:
985 case QEvent::ApplicationLayoutDirectionChange:
986 d->layoutChildren();
987 // fall through
988 default:
989 return QFrame::event(e);
990 }
991 return true;
992}
993
994/*!
995 \fn bool QAbstractScrollArea::viewportEvent(QEvent *event)
996
997 The main event handler for the scrolling area (the viewport() widget).
998 It handles the \a event specified, and can be called by subclasses to
999 provide reasonable default behavior.
1000
1001 Returns true to indicate to the event system that the event has been
1002 handled, and needs no further processing; otherwise returns false to
1003 indicate that the event should be propagated further.
1004
1005 You can reimplement this function in a subclass, but we recommend
1006 using one of the specialized event handlers instead.
1007
1008 Specialised handlers for viewport events are: paintEvent(),
1009 mousePressEvent(), mouseReleaseEvent(), mouseDoubleClickEvent(),
1010 mouseMoveEvent(), wheelEvent(), dragEnterEvent(), dragMoveEvent(),
1011 dragLeaveEvent(), dropEvent(), contextMenuEvent(), and
1012 resizeEvent().
1013*/
1014bool QAbstractScrollArea::viewportEvent(QEvent *e)
1015{
1016 switch (e->type()) {
1017 case QEvent::Resize:
1018 case QEvent::Paint:
1019 case QEvent::MouseButtonPress:
1020 case QEvent::MouseButtonRelease:
1021 case QEvent::MouseButtonDblClick:
1022 case QEvent::TouchBegin:
1023 case QEvent::TouchUpdate:
1024 case QEvent::TouchEnd:
1025 case QEvent::MouseMove:
1026 case QEvent::ContextMenu:
1027#ifndef QT_NO_WHEELEVENT
1028 case QEvent::Wheel:
1029#endif
1030#ifndef QT_NO_DRAGANDDROP
1031 case QEvent::Drop:
1032 case QEvent::DragEnter:
1033 case QEvent::DragMove:
1034 case QEvent::DragLeave:
1035#endif
1036 return QFrame::event(e);
1037 case QEvent::LayoutRequest:
1038 case QEvent::Gesture:
1039 case QEvent::GestureOverride:
1040 return event(e);
1041 default:
1042 break;
1043 }
1044 return false; // let the viewport widget handle the event
1045}
1046
1047/*!
1048 \fn void QAbstractScrollArea::resizeEvent(QResizeEvent *event)
1049
1050 This event handler can be reimplemented in a subclass to receive
1051 resize events (passed in \a event), for the viewport() widget.
1052
1053 When resizeEvent() is called, the viewport already has its new
1054 geometry: Its new size is accessible through the
1055 QResizeEvent::size() function, and the old size through
1056 QResizeEvent::oldSize().
1057
1058 \sa QWidget::resizeEvent()
1059 */
1060void QAbstractScrollArea::resizeEvent(QResizeEvent *)
1061{
1062}
1063
1064/*!
1065 \fn void QAbstractScrollArea::paintEvent(QPaintEvent *event)
1066
1067 This event handler can be reimplemented in a subclass to receive
1068 paint events (passed in \a event), for the viewport() widget.
1069
1070 \note If you open a painter, make sure to open it on the viewport().
1071
1072 \sa QWidget::paintEvent()
1073*/
1074void QAbstractScrollArea::paintEvent(QPaintEvent*)
1075{
1076}
1077
1078/*!
1079 This event handler can be reimplemented in a subclass to receive
1080 mouse press events for the viewport() widget. The event is passed
1081 in \a e.
1082
1083 \sa QWidget::mousePressEvent()
1084*/
1085void QAbstractScrollArea::mousePressEvent(QMouseEvent *e)
1086{
1087 e->ignore();
1088}
1089
1090/*!
1091 This event handler can be reimplemented in a subclass to receive
1092 mouse release events for the viewport() widget. The event is
1093 passed in \a e.
1094
1095 \sa QWidget::mouseReleaseEvent()
1096*/
1097void QAbstractScrollArea::mouseReleaseEvent(QMouseEvent *e)
1098{
1099 e->ignore();
1100}
1101
1102/*!
1103 This event handler can be reimplemented in a subclass to receive
1104 mouse double click events for the viewport() widget. The event is
1105 passed in \a e.
1106
1107 \sa QWidget::mouseDoubleClickEvent()
1108*/
1109void QAbstractScrollArea::mouseDoubleClickEvent(QMouseEvent *e)
1110{
1111 e->ignore();
1112}
1113
1114/*!
1115 This event handler can be reimplemented in a subclass to receive
1116 mouse move events for the viewport() widget. The event is passed
1117 in \a e.
1118
1119 \sa QWidget::mouseMoveEvent()
1120*/
1121void QAbstractScrollArea::mouseMoveEvent(QMouseEvent *e)
1122{
1123 e->ignore();
1124}
1125
1126/*!
1127 This event handler can be reimplemented in a subclass to receive
1128 wheel events for the viewport() widget. The event is passed in \a
1129 e.
1130
1131 \sa QWidget::wheelEvent()
1132*/
1133#ifndef QT_NO_WHEELEVENT
1134void QAbstractScrollArea::wheelEvent(QWheelEvent *e)
1135{
1136 Q_D(QAbstractScrollArea);
1137 if (static_cast<QWheelEvent*>(e)->orientation() == Qt::Horizontal)
1138 QApplication::sendEvent(d->hbar, e);
1139 else
1140 QApplication::sendEvent(d->vbar, e);
1141}
1142#endif
1143
1144#ifndef QT_NO_CONTEXTMENU
1145/*!
1146 This event handler can be reimplemented in a subclass to receive
1147 context menu events for the viewport() widget. The event is passed
1148 in \a e.
1149
1150 \sa QWidget::contextMenuEvent()
1151*/
1152void QAbstractScrollArea::contextMenuEvent(QContextMenuEvent *e)
1153{
1154 e->ignore();
1155}
1156#endif // QT_NO_CONTEXTMENU
1157
1158/*!
1159 This function is called with key event \a e when key presses
1160 occur. It handles PageUp, PageDown, Up, Down, Left, and Right, and
1161 ignores all other key presses.
1162*/
1163void QAbstractScrollArea::keyPressEvent(QKeyEvent * e)
1164{
1165 Q_D(QAbstractScrollArea);
1166 if (false){
1167#ifndef QT_NO_SHORTCUT
1168 } else if (e == QKeySequence::MoveToPreviousPage) {
1169 d->vbar->triggerAction(QScrollBar::SliderPageStepSub);
1170 } else if (e == QKeySequence::MoveToNextPage) {
1171 d->vbar->triggerAction(QScrollBar::SliderPageStepAdd);
1172#endif
1173 } else {
1174#ifdef QT_KEYPAD_NAVIGATION
1175 if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
1176 e->ignore();
1177 return;
1178 }
1179#endif
1180 switch (e->key()) {
1181 case Qt::Key_Up:
1182 d->vbar->triggerAction(QScrollBar::SliderSingleStepSub);
1183 break;
1184 case Qt::Key_Down:
1185 d->vbar->triggerAction(QScrollBar::SliderSingleStepAdd);
1186 break;
1187 case Qt::Key_Left:
1188#ifdef QT_KEYPAD_NAVIGATION
1189 if (QApplication::keypadNavigationEnabled() && hasEditFocus()
1190 && (!d->hbar->isVisible() || d->hbar->value() == d->hbar->minimum())) {
1191 //if we aren't using the hbar or we are already at the leftmost point ignore
1192 e->ignore();
1193 return;
1194 }
1195#endif
1196 d->hbar->triggerAction(
1197 layoutDirection() == Qt::LeftToRight
1198 ? QScrollBar::SliderSingleStepSub : QScrollBar::SliderSingleStepAdd);
1199 break;
1200 case Qt::Key_Right:
1201#ifdef QT_KEYPAD_NAVIGATION
1202 if (QApplication::keypadNavigationEnabled() && hasEditFocus()
1203 && (!d->hbar->isVisible() || d->hbar->value() == d->hbar->maximum())) {
1204 //if we aren't using the hbar or we are already at the rightmost point ignore
1205 e->ignore();
1206 return;
1207 }
1208#endif
1209 d->hbar->triggerAction(
1210 layoutDirection() == Qt::LeftToRight
1211 ? QScrollBar::SliderSingleStepAdd : QScrollBar::SliderSingleStepSub);
1212 break;
1213 default:
1214 e->ignore();
1215 return;
1216 }
1217 }
1218 e->accept();
1219}
1220
1221
1222#ifndef QT_NO_DRAGANDDROP
1223/*!
1224 \fn void QAbstractScrollArea::dragEnterEvent(QDragEnterEvent *event)
1225
1226 This event handler can be reimplemented in a subclass to receive
1227 drag enter events (passed in \a event), for the viewport() widget.
1228
1229 \sa QWidget::dragEnterEvent()
1230*/
1231void QAbstractScrollArea::dragEnterEvent(QDragEnterEvent *)
1232{
1233}
1234
1235/*!
1236 \fn void QAbstractScrollArea::dragMoveEvent(QDragMoveEvent *event)
1237
1238 This event handler can be reimplemented in a subclass to receive
1239 drag move events (passed in \a event), for the viewport() widget.
1240
1241 \sa QWidget::dragMoveEvent()
1242*/
1243void QAbstractScrollArea::dragMoveEvent(QDragMoveEvent *)
1244{
1245}
1246
1247/*!
1248 \fn void QAbstractScrollArea::dragLeaveEvent(QDragLeaveEvent *event)
1249
1250 This event handler can be reimplemented in a subclass to receive
1251 drag leave events (passed in \a event), for the viewport() widget.
1252
1253 \sa QWidget::dragLeaveEvent()
1254*/
1255void QAbstractScrollArea::dragLeaveEvent(QDragLeaveEvent *)
1256{
1257}
1258
1259/*!
1260 \fn void QAbstractScrollArea::dropEvent(QDropEvent *event)
1261
1262 This event handler can be reimplemented in a subclass to receive
1263 drop events (passed in \a event), for the viewport() widget.
1264
1265 \sa QWidget::dropEvent()
1266*/
1267void QAbstractScrollArea::dropEvent(QDropEvent *)
1268{
1269}
1270
1271
1272#endif
1273
1274/*!
1275 This virtual handler is called when the scroll bars are moved by
1276 \a dx, \a dy, and consequently the viewport's contents should be
1277 scrolled accordingly.
1278
1279 The default implementation simply calls update() on the entire
1280 viewport(), subclasses can reimplement this handler for
1281 optimization purposes, or - like QScrollArea - to move a contents
1282 widget. The parameters \a dx and \a dy are there for convenience,
1283 so that the class knows how much should be scrolled (useful
1284 e.g. when doing pixel-shifts). You may just as well ignore these
1285 values and scroll directly to the position the scroll bars
1286 indicate.
1287
1288 Calling this function in order to scroll programmatically is an
1289 error, use the scroll bars instead (e.g. by calling
1290 QScrollBar::setValue() directly).
1291*/
1292void QAbstractScrollArea::scrollContentsBy(int, int)
1293{
1294 viewport()->update();
1295}
1296
1297void QAbstractScrollAreaPrivate::_q_hslide(int x)
1298{
1299 Q_Q(QAbstractScrollArea);
1300 int dx = xoffset - x;
1301 xoffset = x;
1302 q->scrollContentsBy(dx, 0);
1303}
1304
1305void QAbstractScrollAreaPrivate::_q_vslide(int y)
1306{
1307 Q_Q(QAbstractScrollArea);
1308 int dy = yoffset - y;
1309 yoffset = y;
1310 q->scrollContentsBy(0, dy);
1311}
1312
1313void QAbstractScrollAreaPrivate::_q_showOrHideScrollBars()
1314{
1315 layoutChildren();
1316#ifdef Q_WS_WIN
1317 // Need to re-subscribe to gestures as the content changes to make sure we
1318 // enable/disable panning when needed.
1319 QWidgetPrivate *dd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(viewport));
1320 if (dd)
1321 dd->winSetupGestures();
1322#endif // Q_WS_WIN
1323}
1324
1325QPoint QAbstractScrollAreaPrivate::contentsOffset() const
1326{
1327 Q_Q(const QAbstractScrollArea);
1328 QPoint offset;
1329 if (vbar->isVisible())
1330 offset.setY(vbar->value());
1331 if (hbar->isVisible()) {
1332 if (q->isRightToLeft())
1333 offset.setX(hbar->maximum() - hbar->value());
1334 else
1335 offset.setX(hbar->value());
1336 }
1337 return offset;
1338}
1339
1340/*!
1341 \reimp
1342
1343*/
1344QSize QAbstractScrollArea::minimumSizeHint() const
1345{
1346 Q_D(const QAbstractScrollArea);
1347 int hsbExt = d->hbar->sizeHint().height();
1348 int vsbExt = d->vbar->sizeHint().width();
1349 int extra = 2 * d->frameWidth;
1350 QStyleOption opt;
1351 opt.initFrom(this);
1352 if ((d->frameStyle != QFrame::NoFrame)
1353 && style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, this)) {
1354 extra += style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, this);
1355 }
1356 return QSize(d->scrollBarContainers[Qt::Horizontal]->sizeHint().width() + vsbExt + extra,
1357 d->scrollBarContainers[Qt::Vertical]->sizeHint().height() + hsbExt + extra);
1358}
1359
1360/*!
1361 \reimp
1362*/
1363QSize QAbstractScrollArea::sizeHint() const
1364{
1365 return QSize(256, 192);
1366#if 0
1367 Q_D(const QAbstractScrollArea);
1368 int h = qMax(10, fontMetrics().height());
1369 int f = 2 * d->frameWidth;
1370 return QSize((6 * h) + f, (4 * h) + f);
1371#endif
1372}
1373
1374/*!
1375 This slot is called by QAbstractScrollArea after setViewport(\a
1376 viewport) has been called. Reimplement this function in a
1377 subclass of QAbstractScrollArea to initialize the new \a viewport
1378 before it is used.
1379
1380 \sa setViewport()
1381*/
1382void QAbstractScrollArea::setupViewport(QWidget *viewport)
1383{
1384 Q_UNUSED(viewport);
1385}
1386
1387QT_END_NAMESPACE
1388
1389#include "moc_qabstractscrollarea.cpp"
1390#include "moc_qabstractscrollarea_p.cpp"
1391
1392#endif // QT_NO_SCROLLAREA
Note: See TracBrowser for help on using the repository browser.