source: vendor/trolltech/current/src/widgets/qscrollview.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 78.2 KB
Line 
1/****************************************************************************
2** $Id: qscrollview.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QScrollView class
5**
6** Created : 950524
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qwidget.h"
39#ifndef QT_NO_SCROLLVIEW
40#include "qscrollbar.h"
41#include "qobjectlist.h"
42#include "qpainter.h"
43#include "qpixmap.h"
44#include "qcursor.h"
45#include "qfocusdata.h"
46#include "qscrollview.h"
47#include "qptrdict.h"
48#include "qapplication.h"
49#include "qtimer.h"
50#include "qstyle.h"
51#ifdef Q_WS_MAC
52# include "qt_mac.h"
53#endif
54
55static const int coord_limit = 4000;
56static const int autoscroll_margin = 16;
57static const int initialScrollTime = 30;
58static const int initialScrollAccel = 5;
59
60struct QSVChildRec {
61 QSVChildRec(QWidget* c, int xx, int yy) :
62 child(c),
63 x(xx), y(yy)
64 {
65 }
66
67 void hideOrShow(QScrollView* sv, QWidget* clipped_viewport);
68 void moveTo(QScrollView* sv, int xx, int yy, QWidget* clipped_viewport)
69 {
70 if ( x != xx || y != yy ) {
71 x = xx;
72 y = yy;
73 hideOrShow(sv,clipped_viewport);
74 }
75 }
76 QWidget* child;
77 int x, y;
78};
79
80void QSVChildRec::hideOrShow(QScrollView* sv, QWidget* clipped_viewport)
81{
82 if ( clipped_viewport ) {
83 if ( x+child->width() < sv->contentsX()+clipped_viewport->x()
84 || x > sv->contentsX()+clipped_viewport->width()
85 || y+child->height() < sv->contentsY()+clipped_viewport->y()
86 || y > sv->contentsY()+clipped_viewport->height() ) {
87 child->move(clipped_viewport->width(),
88 clipped_viewport->height());
89 } else {
90 child->move(x-sv->contentsX()-clipped_viewport->x(),
91 y-sv->contentsY()-clipped_viewport->y());
92 }
93 } else {
94 child->move(x-sv->contentsX(), y-sv->contentsY());
95 }
96}
97
98class QViewportWidget : public QWidget
99{
100 Q_OBJECT
101
102public:
103 QViewportWidget( QScrollView* parent=0, const char* name=0, WFlags f = 0 )
104 : QWidget( parent, name, f ) {}
105};
106
107class QClipperWidget : public QWidget
108{
109 Q_OBJECT
110
111public:
112 QClipperWidget( QWidget * parent=0, const char * name=0, WFlags f=0 )
113 : QWidget ( parent,name,f) {}
114};
115
116#include "qscrollview.moc"
117
118class QScrollViewData {
119public:
120 QScrollViewData(QScrollView* parent, int vpwflags) :
121 hbar( new QScrollBar( QScrollBar::Horizontal, parent, "qt_hbar" ) ),
122 vbar( new QScrollBar( QScrollBar::Vertical, parent, "qt_vbar" ) ),
123 viewport( new QViewportWidget( parent, "qt_viewport", vpwflags ) ),
124 clipped_viewport( 0 ),
125 flags( vpwflags ),
126 vx( 0 ), vy( 0 ), vwidth( 1 ), vheight( 1 ),
127#ifndef QT_NO_DRAGANDDROP
128 autoscroll_timer( parent, "scrollview autoscroll timer" ),
129 drag_autoscroll( TRUE ),
130#endif
131 scrollbar_timer( parent, "scrollview scrollbar timer" ),
132 inresize( FALSE ), use_cached_size_hint( TRUE )
133 {
134 l_marg = r_marg = t_marg = b_marg = 0;
135 viewport->polish();
136 viewport->setBackgroundMode( QWidget::PaletteDark );
137 viewport->setBackgroundOrigin( QWidget::WidgetOrigin );
138 vMode = QScrollView::Auto;
139 hMode = QScrollView::Auto;
140 corner = 0;
141 defaultCorner = new QWidget( parent, "qt_default_corner" );
142 defaultCorner->hide();
143 vbar->setSteps( 20, 1/*set later*/ );
144 hbar->setSteps( 20, 1/*set later*/ );
145 policy = QScrollView::Default;
146 signal_choke = FALSE;
147 static_bg = FALSE;
148 fake_scroll = FALSE;
149 hbarPressed = FALSE;
150 vbarPressed = FALSE;
151 }
152 ~QScrollViewData();
153
154 QSVChildRec* rec(QWidget* w) { return childDict.find(w); }
155 QSVChildRec* ancestorRec(QWidget* w);
156 QSVChildRec* addChildRec(QWidget* w, int x, int y )
157 {
158 QSVChildRec *r = new QSVChildRec(w,x,y);
159 children.append(r);
160 childDict.insert(w, r);
161 return r;
162 }
163 void deleteChildRec(QSVChildRec* r)
164 {
165 childDict.remove(r->child);
166 children.removeRef(r);
167 delete r;
168 }
169
170 void hideOrShowAll(QScrollView* sv, bool isScroll = FALSE );
171 void moveAllBy(int dx, int dy);
172 bool anyVisibleChildren();
173 void autoMove(QScrollView* sv);
174 void autoResize(QScrollView* sv);
175 void autoResizeHint(QScrollView* sv);
176 void viewportResized( int w, int h );
177
178 QScrollBar* hbar;
179 QScrollBar* vbar;
180 bool hbarPressed;
181 bool vbarPressed;
182 QViewportWidget* viewport;
183 QClipperWidget* clipped_viewport;
184 int flags;
185 QPtrList<QSVChildRec> children;
186 QPtrDict<QSVChildRec> childDict;
187 QWidget* corner, *defaultCorner;
188 int vx, vy, vwidth, vheight; // for drawContents-style usage
189 int l_marg, r_marg, t_marg, b_marg;
190 QScrollView::ResizePolicy policy;
191 QScrollView::ScrollBarMode vMode;
192 QScrollView::ScrollBarMode hMode;
193#ifndef QT_NO_DRAGANDDROP
194 QPoint cpDragStart;
195 QTimer autoscroll_timer;
196 int autoscroll_time;
197 int autoscroll_accel;
198 bool drag_autoscroll;
199#endif
200 QTimer scrollbar_timer;
201
202 uint static_bg : 1;
203 uint fake_scroll : 1;
204
205 // This variable allows ensureVisible to move the contents then
206 // update both the sliders. Otherwise, updating the sliders would
207 // cause two image scrolls, creating ugly flashing.
208 //
209 uint signal_choke : 1;
210
211 // This variables indicates in updateScrollBars() that we are
212 // in a resizeEvent() and thus don't want to flash scrollbars
213 uint inresize : 1;
214 uint use_cached_size_hint : 1;
215 QSize cachedSizeHint;
216
217 inline int contentsX() const { return -vx; }
218 inline int contentsY() const { return -vy; }
219 inline int contentsWidth() const { return vwidth; }
220};
221
222inline QScrollViewData::~QScrollViewData()
223{
224 children.setAutoDelete( TRUE );
225}
226
227QSVChildRec* QScrollViewData::ancestorRec(QWidget* w)
228{
229 if ( clipped_viewport ) {
230 while (w->parentWidget() != clipped_viewport) {
231 w = w->parentWidget();
232 if (!w) return 0;
233 }
234 } else {
235 while (w->parentWidget() != viewport) {
236 w = w->parentWidget();
237 if (!w) return 0;
238 }
239 }
240 return rec(w);
241}
242
243void QScrollViewData::hideOrShowAll(QScrollView* sv, bool isScroll )
244{
245 if ( !clipped_viewport )
246 return;
247 if ( clipped_viewport->x() <= 0
248 && clipped_viewport->y() <= 0
249 && clipped_viewport->width()+clipped_viewport->x() >=
250 viewport->width()
251 && clipped_viewport->height()+clipped_viewport->y() >=
252 viewport->height() ) {
253 // clipped_viewport still covers viewport
254 if( static_bg )
255 clipped_viewport->repaint( TRUE );
256 else if ( ( !isScroll && !clipped_viewport->testWFlags( Qt::WStaticContents) )
257 || static_bg )
258 QApplication::postEvent( clipped_viewport,
259 new QPaintEvent( clipped_viewport->clipRegion(),
260 !clipped_viewport->testWFlags(Qt::WResizeNoErase) ) );
261 } else {
262 // Re-center
263 int nx = ( viewport->width() - clipped_viewport->width() ) / 2;
264 int ny = ( viewport->height() - clipped_viewport->height() ) / 2;
265 clipped_viewport->move(nx,ny);
266 // no need to update, we'll receive a paintevent after move
267 // (with the safe assumption that the newly exposed area
268 // covers the entire viewport)
269 }
270 for (QSVChildRec *r = children.first(); r; r=children.next()) {
271 r->hideOrShow(sv, clipped_viewport);
272 }
273}
274
275void QScrollViewData::moveAllBy(int dx, int dy)
276{
277 if ( clipped_viewport && !static_bg ) {
278 clipped_viewport->move( clipped_viewport->x()+dx,
279 clipped_viewport->y()+dy );
280 } else {
281 for (QSVChildRec *r = children.first(); r; r=children.next()) {
282 r->child->move(r->child->x()+dx,r->child->y()+dy);
283 }
284 if ( static_bg )
285 viewport->repaint( TRUE );
286 }
287}
288
289bool QScrollViewData::anyVisibleChildren()
290{
291 for (QSVChildRec *r = children.first(); r; r=children.next()) {
292 if (r->child->isVisible()) return TRUE;
293 }
294 return FALSE;
295}
296
297void QScrollViewData::autoMove(QScrollView* sv)
298{
299 if ( policy == QScrollView::AutoOne ) {
300 QSVChildRec* r = children.first();
301 if (r)
302 sv->setContentsPos(-r->child->x(),-r->child->y());
303 }
304}
305
306void QScrollViewData::autoResize(QScrollView* sv)
307{
308 if ( policy == QScrollView::AutoOne ) {
309 QSVChildRec* r = children.first();
310 if (r)
311 sv->resizeContents(r->child->width(),r->child->height());
312 }
313}
314
315void QScrollViewData::autoResizeHint(QScrollView* sv)
316{
317 if ( policy == QScrollView::AutoOne ) {
318 QSVChildRec* r = children.first();
319 if (r) {
320 QSize s = r->child->sizeHint();
321 if ( s.isValid() )
322 r->child->resize(s);
323 }
324 } else if ( policy == QScrollView::AutoOneFit ) {
325 QSVChildRec* r = children.first();
326 if (r) {
327 QSize sh = r->child->sizeHint();
328 sh = sh.boundedTo( r->child->maximumSize() );
329 sv->resizeContents( sh.width(), sh.height() );
330 }
331 }
332}
333
334void QScrollViewData::viewportResized( int w, int h )
335{
336 if ( policy == QScrollView::AutoOneFit ) {
337 QSVChildRec* r = children.first();
338 if (r) {
339 QSize sh = r->child->sizeHint();
340 sh = sh.boundedTo( r->child->maximumSize() );
341 r->child->resize( QMAX(w,sh.width()), QMAX(h,sh.height()) );
342 }
343
344 }
345}
346
347
348/*!
349 \class QScrollView qscrollview.h
350 \brief The QScrollView widget provides a scrolling area with on-demand scroll bars.
351
352 \ingroup abstractwidgets
353 \mainclass
354
355 The QScrollView is a large canvas - potentially larger than the
356 coordinate system normally supported by the underlying window
357 system. This is important because it is quite easy to go beyond
358 these limitations (e.g. many web pages are more than 32000 pixels
359 high). Additionally, the QScrollView can have QWidgets positioned
360 on it that scroll around with the drawn content. These sub-widgets
361 can also have positions outside the normal coordinate range (but
362 they are still limited in size).
363
364 To provide content for the widget, inherit from QScrollView,
365 reimplement drawContents() and use resizeContents() to set the
366 size of the viewed area. Use addChild() and moveChild() to
367 position widgets on the view.
368
369 To use QScrollView effectively it is important to understand its
370 widget structure in the three styles of use: a single large child
371 widget, a large panning area with some widgets and a large panning
372 area with many widgets.
373
374 \section1 Using One Big Widget
375
376 \img qscrollview-vp2.png
377
378 The first, simplest usage of QScrollView (depicted above), is
379 appropriate for scrolling areas that are never more than about
380 4000 pixels in either dimension (this is about the maximum
381 reliable size on X11 servers). In this usage, you just make one
382 large child in the QScrollView. The child should be a child of the
383 viewport() of the scrollview and be added with addChild():
384 \code
385 QScrollView* sv = new QScrollView(...);
386 QVBox* big_box = new QVBox(sv->viewport());
387 sv->addChild(big_box);
388 \endcode
389 You can go on to add arbitrary child widgets to the single child
390 in the scrollview as you would with any widget:
391 \code
392 QLabel* child1 = new QLabel("CHILD", big_box);
393 QLabel* child2 = new QLabel("CHILD", big_box);
394 QLabel* child3 = new QLabel("CHILD", big_box);
395 ...
396 \endcode
397
398 Here the QScrollView has four children: the viewport(), the
399 verticalScrollBar(), the horizontalScrollBar() and a small
400 cornerWidget(). The viewport() has one child: the big QVBox. The
401 QVBox has the three QLabel objects as child widgets. When the view
402 is scrolled, the QVBox is moved; its children move with it as
403 child widgets normally do.
404
405 \section1 Using a Very Big View with Some Widgets
406
407 \img qscrollview-vp.png
408
409 The second usage of QScrollView (depicted above) is appropriate
410 when few, if any, widgets are on a very large scrolling area that
411 is potentially larger than 4000 pixels in either dimension. In
412 this usage you call resizeContents() to set the size of the area
413 and reimplement drawContents() to paint the contents. You may also
414 add some widgets by making them children of the viewport() and
415 adding them with addChild() (this is the same as the process for
416 the single large widget in the previous example):
417 \code
418 QScrollView* sv = new QScrollView(...);
419 QLabel* child1 = new QLabel("CHILD", sv->viewport());
420 sv->addChild(child1);
421 QLabel* child2 = new QLabel("CHILD", sv->viewport());
422 sv->addChild(child2);
423 QLabel* child3 = new QLabel("CHILD", sv->viewport());
424 sv->addChild(child3);
425 \endcode
426 Here, the QScrollView has the same four children: the viewport(),
427 the verticalScrollBar(), the horizontalScrollBar() and a small
428 cornerWidget(). The viewport() has the three QLabel objects as
429 child widgets. When the view is scrolled, the scrollview moves the
430 child widgets individually.
431
432 \section1 Using a Very Big View with Many Widgets
433
434 \target enableclipper
435 \img qscrollview-cl.png
436
437 The final usage of QScrollView (depicted above) is appropriate
438 when many widgets are on a very large scrolling area that is
439 potentially larger than 4000 pixels in either dimension. In this
440 usage you call resizeContents() to set the size of the area and
441 reimplement drawContents() to paint the contents. You then call
442 enableClipper(TRUE) and add widgets, again by making them children
443 of the viewport(), and adding them with addChild():
444 \code
445 QScrollView* sv = new QScrollView(...);
446 sv->enableClipper(TRUE);
447 QLabel* child1 = new QLabel("CHILD", sv->viewport());
448 sv->addChild(child1);
449 QLabel* child2 = new QLabel("CHILD", sv->viewport());
450 sv->addChild(child2);
451 QLabel* child3 = new QLabel("CHILD", sv->viewport());
452 sv->addChild(child3);
453 \endcode
454
455 Here, the QScrollView has four children: the clipper() (not the
456 viewport() this time), the verticalScrollBar(), the
457 horizontalScrollBar() and a small cornerWidget(). The clipper()
458 has one child: the viewport(). The viewport() has the same three
459 labels as child widgets. When the view is scrolled the viewport()
460 is moved; its children move with it as child widgets normally do.
461
462 \target allviews
463 \section1 Details Relevant for All Views
464
465 Normally you will use the first or third method if you want any
466 child widgets in the view.
467
468 Note that the widget you see in the scrolled area is the
469 viewport() widget, not the QScrollView itself. So to turn mouse
470 tracking on, for example, use viewport()->setMouseTracking(TRUE).
471
472 To enable drag-and-drop, you would setAcceptDrops(TRUE) on the
473 QScrollView (because drag-and-drop events propagate to the
474 parent). But to work out the logical position in the view, you
475 would need to map the drop co-ordinate from being relative to the
476 QScrollView to being relative to the contents; use the function
477 viewportToContents() for this.
478
479 To handle mouse events on the scrolling area, subclass scrollview
480 as you would subclass other widgets, but rather than
481 reimplementing mousePressEvent(), reimplement
482 contentsMousePressEvent() instead. The contents specific event
483 handlers provide translated events in the coordinate system of the
484 scrollview. If you reimplement mousePressEvent(), you'll get
485 called only when part of the QScrollView is clicked: and the only
486 such part is the "corner" (if you don't set a cornerWidget()) and
487 the frame; everything else is covered up by the viewport, clipper
488 or scroll bars.
489
490 When you construct a QScrollView, some of the widget flags apply
491 to the viewport() instead of being sent to the QWidget constructor
492 for the QScrollView. This applies to \c WNoAutoErase, \c
493 WStaticContents, and \c WPaintClever. See \l Qt::WidgetFlags for
494 documentation about these flags. Here are some examples:
495
496 \list
497
498 \i An image-manipulation widget would use \c
499 WNoAutoErase|WStaticContents because the widget draws all pixels
500 itself, and when its size increases, it only needs a paint event
501 for the new part because the old part remains unchanged.
502
503 \i A scrolling game widget in which the background scrolls as the
504 characters move might use \c WNoAutoErase (in addition to \c
505 WStaticContents) so that the window system background does not
506 flash in and out during scrolling.
507
508 \i A word processing widget might use \c WNoAutoErase and repaint
509 itself line by line to get a less-flickery resizing. If the widget
510 is in a mode in which no text justification can take place, it
511 might use \c WStaticContents too, so that it would only get a
512 repaint for the newly visible parts.
513
514 \endlist
515
516 Child widgets may be moved using addChild() or moveChild(). Use
517 childX() and childY() to get the position of a child widget.
518
519 A widget may be placed in the corner between the vertical and
520 horizontal scrollbars with setCornerWidget(). You can get access
521 to the scrollbars using horizontalScrollBar() and
522 verticalScrollBar(), and to the viewport with viewport(). The
523 scroll view can be scrolled using scrollBy(), ensureVisible(),
524 setContentsPos() or center().
525
526 The visible area is given by visibleWidth() and visibleHeight(),
527 and the contents area by contentsWidth() and contentsHeight(). The
528 contents may be repainted using one of the repaintContents() or
529 updateContents() functions.
530
531 Coordinate conversion is provided by contentsToViewport() and
532 viewportToContents().
533
534 The contentsMoving() signal is emitted just before the contents
535 are moved to a new position.
536
537 \warning QScrollView currently does not erase the background when
538 resized, i.e. you must always clear the background manually in
539 scrollview subclasses. This will change in a future version of Qt
540 and we recommend specifying the WNoAutoErase flag explicitly.
541
542 <img src=qscrollview-m.png> <img src=qscrollview-w.png>
543*/
544
545
546/*!
547 \enum QScrollView::ResizePolicy
548
549 This enum type is used to control a QScrollView's reaction to
550 resize events.
551
552 \value Default the QScrollView selects one of the other settings
553 automatically when it has to. In this version of Qt, QScrollView
554 changes to \c Manual if you resize the contents with
555 resizeContents() and to \c AutoOne if a child is added.
556
557 \value Manual the contents stays the size set by resizeContents().
558
559 \value AutoOne if there is only one child widget the contents stays
560 the size of that widget. Otherwise the behavior is undefined.
561
562 \value AutoOneFit if there is only one child widget the contents stays
563 the size of that widget's sizeHint(). If the scrollview is resized
564 larger than the child's sizeHint(), the child will be resized to
565 fit. If there is more than one child, the behavior is undefined.
566
567*/
568//#### The widget will be resized to its sizeHint() when a LayoutHint event
569//#### is received
570
571/*!
572 Constructs a QScrollView called \a name with parent \a parent and
573 widget flags \a f.
574
575 The widget flags \c WStaticContents, \c WNoAutoErase and \c
576 WPaintClever are propagated to the viewport() widget. The other
577 widget flags are propagated to the parent constructor as usual.
578*/
579
580QScrollView::QScrollView( QWidget *parent, const char *name, WFlags f ) :
581 QFrame( parent, name, f & (~WStaticContents) & (~WResizeNoErase) )
582{
583 WFlags flags = WResizeNoErase | (f&WPaintClever) | (f&WRepaintNoErase) | (f&WStaticContents);
584 d = new QScrollViewData( this, flags );
585
586#ifndef QT_NO_DRAGANDDROP
587 connect( &d->autoscroll_timer, SIGNAL( timeout() ),
588 this, SLOT( doDragAutoScroll() ) );
589#endif
590
591 connect( d->hbar, SIGNAL( valueChanged(int) ),
592 this, SLOT( hslide(int) ) );
593 connect( d->vbar, SIGNAL( valueChanged(int) ),
594 this, SLOT( vslide(int) ) );
595
596 connect( d->hbar, SIGNAL(sliderPressed()), this, SLOT(hbarIsPressed()) );
597 connect( d->hbar, SIGNAL(sliderReleased()), this, SLOT(hbarIsReleased()) );
598 connect( d->vbar, SIGNAL(sliderPressed()), this, SLOT(vbarIsPressed()) );
599 connect( d->vbar, SIGNAL(sliderReleased()), this, SLOT(vbarIsReleased()) );
600
601
602 d->viewport->installEventFilter( this );
603
604 connect( &d->scrollbar_timer, SIGNAL( timeout() ),
605 this, SLOT( updateScrollBars() ) );
606
607 setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
608 setLineWidth( style().pixelMetric(QStyle::PM_DefaultFrameWidth, this) );
609 setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
610}
611
612
613/*!
614 Destroys the QScrollView. Any children added with addChild() will
615 be deleted.
616*/
617QScrollView::~QScrollView()
618{
619 // Be careful not to get all those useless events...
620 if ( d->clipped_viewport )
621 d->clipped_viewport->removeEventFilter( this );
622 else
623 d->viewport->removeEventFilter( this );
624
625 // order is important
626 // ~QWidget may cause a WM_ERASEBKGND on Windows
627 delete d->vbar;
628 d->vbar = 0;
629 delete d->hbar;
630 d->hbar = 0;
631 delete d->viewport;
632 d->viewport = 0;
633 delete d;
634 d = 0;
635}
636
637/*!
638 \fn void QScrollView::horizontalSliderPressed()
639
640 This signal is emitted whenever the user presses the horizontal slider.
641*/
642/*!
643 \fn void QScrollView::horizontalSliderReleased()
644
645 This signal is emitted whenever the user releases the horizontal slider.
646*/
647/*!
648 \fn void QScrollView::verticalSliderPressed()
649
650 This signal is emitted whenever the user presses the vertical slider.
651*/
652/*!
653 \fn void QScrollView::verticalSliderReleased()
654
655 This signal is emitted whenever the user releases the vertical slider.
656*/
657void QScrollView::hbarIsPressed()
658{
659 d->hbarPressed = TRUE;
660 emit( horizontalSliderPressed() );
661}
662
663void QScrollView::hbarIsReleased()
664{
665 d->hbarPressed = FALSE;
666 emit( horizontalSliderReleased() );
667}
668
669/*!
670 Returns TRUE if horizontal slider is pressed by user; otherwise returns FALSE.
671*/
672bool QScrollView::isHorizontalSliderPressed()
673{
674 return d->hbarPressed;
675}
676
677void QScrollView::vbarIsPressed()
678{
679 d->vbarPressed = TRUE;
680 emit( verticalSliderPressed() );
681}
682
683void QScrollView::vbarIsReleased()
684{
685 d->vbarPressed = FALSE;
686 emit( verticalSliderReleased() );
687}
688
689/*!
690 Returns TRUE if vertical slider is pressed by user; otherwise returns FALSE.
691*/
692bool QScrollView::isVerticalSliderPressed()
693{
694 return d->vbarPressed;
695}
696
697/*!
698 \reimp
699*/
700void QScrollView::styleChange( QStyle& old )
701{
702 QWidget::styleChange( old );
703 updateScrollBars();
704 d->cachedSizeHint = QSize();
705}
706
707/*!
708 \reimp
709*/
710void QScrollView::fontChange( const QFont &old )
711{
712 QWidget::fontChange( old );
713 updateScrollBars();
714 d->cachedSizeHint = QSize();
715}
716
717void QScrollView::hslide( int pos )
718{
719 if ( !d->signal_choke ) {
720 moveContents( -pos, -d->contentsY() );
721 QApplication::syncX();
722 }
723}
724
725void QScrollView::vslide( int pos )
726{
727 if ( !d->signal_choke ) {
728 moveContents( -d->contentsX(), -pos );
729 QApplication::syncX();
730 }
731}
732
733/*!
734 Called when the horizontal scroll bar geometry changes. This is
735 provided as a protected function so that subclasses can do
736 interesting things such as providing extra buttons in some of the
737 space normally used by the scroll bars.
738
739 The default implementation simply gives all the space to \a hbar.
740 The new geometry is given by \a x, \a y, \a w and \a h.
741
742 \sa setVBarGeometry()
743*/
744void QScrollView::setHBarGeometry(QScrollBar& hbar,
745 int x, int y, int w, int h)
746{
747 hbar.setGeometry( x, y, w, h );
748}
749
750/*!
751 Called when the vertical scroll bar geometry changes. This is
752 provided as a protected function so that subclasses can do
753 interesting things such as providing extra buttons in some of the
754 space normally used by the scroll bars.
755
756 The default implementation simply gives all the space to \a vbar.
757 The new geometry is given by \a x, \a y, \a w and \a h.
758
759 \sa setHBarGeometry()
760*/
761void QScrollView::setVBarGeometry( QScrollBar& vbar,
762 int x, int y, int w, int h)
763{
764 vbar.setGeometry( x, y, w, h );
765}
766
767
768/*!
769 Returns the viewport size for size (\a x, \a y).
770
771 The viewport size depends on \a (x, y) (the size of the contents),
772 the size of this widget and the modes of the horizontal and
773 vertical scroll bars.
774
775 This function permits widgets that can trade vertical and
776 horizontal space for each other to control scroll bar appearance
777 better. For example, a word processor or web browser can control
778 the width of the right margin accurately, whether or not there
779 needs to be a vertical scroll bar.
780*/
781
782QSize QScrollView::viewportSize( int x, int y ) const
783{
784 int fw = frameWidth();
785 int lmarg = fw+d->l_marg;
786 int rmarg = fw+d->r_marg;
787 int tmarg = fw+d->t_marg;
788 int bmarg = fw+d->b_marg;
789
790 int w = width();
791 int h = height();
792
793 bool needh, needv;
794 bool showh, showv;
795 int hsbExt = horizontalScrollBar()->sizeHint().height();
796 int vsbExt = verticalScrollBar()->sizeHint().width();
797
798 if ( d->policy != AutoOne || d->anyVisibleChildren() ) {
799 // Do we definitely need the scrollbar?
800 needh = w-lmarg-rmarg < x;
801 needv = h-tmarg-bmarg < y;
802
803 // Do we intend to show the scrollbar?
804 if (d->hMode == AlwaysOn)
805 showh = TRUE;
806 else if (d->hMode == AlwaysOff)
807 showh = FALSE;
808 else
809 showh = needh;
810
811 if (d->vMode == AlwaysOn)
812 showv = TRUE;
813 else if (d->vMode == AlwaysOff)
814 showv = FALSE;
815 else
816 showv = needv;
817
818 // Given other scrollbar will be shown, NOW do we need one?
819 if ( showh && h-vsbExt-tmarg-bmarg < y ) {
820 if (d->vMode == Auto)
821 showv=TRUE;
822 }
823 if ( showv && w-hsbExt-lmarg-rmarg < x ) {
824 if (d->hMode == Auto)
825 showh=TRUE;
826 }
827 } else {
828 // Scrollbars not needed, only show scrollbar that are always on.
829 showh = d->hMode == AlwaysOn;
830 showv = d->vMode == AlwaysOn;
831 }
832
833 return QSize( w-lmarg-rmarg - (showv ? vsbExt : 0),
834 h-tmarg-bmarg - (showh ? hsbExt : 0) );
835}
836
837
838/*!
839 Updates scroll bars: all possibilities are considered. You should
840 never need to call this in your code.
841*/
842void QScrollView::updateScrollBars()
843{
844 if(!horizontalScrollBar() && !verticalScrollBar())
845 return;
846
847 // I support this should use viewportSize()... but it needs
848 // so many of the temporary variables from viewportSize. hm.
849 int fw = frameWidth();
850 int lmarg = fw+d->l_marg;
851 int rmarg = fw+d->r_marg;
852 int tmarg = fw+d->t_marg;
853 int bmarg = fw+d->b_marg;
854
855 int w = width();
856 int h = height();
857
858 int portw, porth;
859
860 bool needh;
861 bool needv;
862 bool showh;
863 bool showv;
864 bool showc = FALSE;
865
866 int hsbExt = horizontalScrollBar()->sizeHint().height();
867 int vsbExt = verticalScrollBar()->sizeHint().width();
868
869 QSize oldVisibleSize( visibleWidth(), visibleHeight() );
870
871 if ( d->policy != AutoOne || d->anyVisibleChildren() ) {
872 // Do we definitely need the scrollbar?
873 needh = w-lmarg-rmarg < d->contentsWidth();
874 if ( d->inresize )
875 needh = !horizontalScrollBar()->isHidden();
876 needv = h-tmarg-bmarg < contentsHeight();
877
878 // Do we intend to show the scrollbar?
879 if (d->hMode == AlwaysOn)
880 showh = TRUE;
881 else if (d->hMode == AlwaysOff)
882 showh = FALSE;
883 else
884 showh = needh;
885
886 if (d->vMode == AlwaysOn)
887 showv = TRUE;
888 else if (d->vMode == AlwaysOff)
889 showv = FALSE;
890 else
891 showv = needv;
892
893#ifdef Q_WS_MAC
894 bool mac_need_scroll = FALSE;
895 if(!parentWidget()) {
896 mac_need_scroll = TRUE;
897 } else {
898 QWidget *tlw = topLevelWidget();
899 QPoint tlw_br = QPoint(tlw->width(), tlw->height()),
900 my_br = posInWindow(this) + QPoint(w, h);
901 if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3)
902 mac_need_scroll = TRUE;
903 }
904 if(mac_need_scroll) {
905 WindowAttributes attr;
906 GetWindowAttributes((WindowPtr)handle(), &attr);
907 mac_need_scroll = (attr & kWindowResizableAttribute);
908 }
909 if(mac_need_scroll) {
910 showc = TRUE;
911 if(d->vMode == Auto)
912 showv = TRUE;
913 if(d->hMode == Auto)
914 showh = TRUE;
915 }
916#endif
917
918 // Given other scrollbar will be shown, NOW do we need one?
919 if ( showh && h-vsbExt-tmarg-bmarg < contentsHeight() ) {
920 needv=TRUE;
921 if (d->vMode == Auto)
922 showv=TRUE;
923 }
924 if ( showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth() ) {
925 needh=TRUE;
926 if (d->hMode == Auto)
927 showh=TRUE;
928 }
929 } else {
930 // Scrollbars not needed, only show scrollbar that are always on.
931 needh = needv = FALSE;
932 showh = d->hMode == AlwaysOn;
933 showv = d->vMode == AlwaysOn;
934 }
935
936 bool sc = d->signal_choke;
937 d->signal_choke=TRUE;
938
939 // Hide unneeded scrollbar, calculate viewport size
940 if ( showh ) {
941 porth=h-hsbExt-tmarg-bmarg;
942 } else {
943 if (!needh)
944 d->hbar->setValue(0);
945 d->hbar->hide();
946 porth=h-tmarg-bmarg;
947 }
948 if ( showv ) {
949 portw=w-vsbExt-lmarg-rmarg;
950 } else {
951 if (!needv)
952 d->vbar->setValue(0);
953 d->vbar->hide();
954 portw=w-lmarg-rmarg;
955 }
956
957 // Configure scrollbars that we will show
958 if ( needv ) {
959 d->vbar->setRange( 0, contentsHeight()-porth );
960 d->vbar->setSteps( QScrollView::d->vbar->lineStep(), porth );
961 } else {
962 d->vbar->setRange( 0, 0 );
963 }
964 if ( needh ) {
965 d->hbar->setRange( 0, QMAX(0, d->contentsWidth()-portw) );
966 d->hbar->setSteps( QScrollView::d->hbar->lineStep(), portw );
967 } else {
968 d->hbar->setRange( 0, 0 );
969 }
970
971 // Position the scrollbars, viewport and corner widget.
972 int bottom;
973 bool reverse = QApplication::reverseLayout();
974 int xoffset = ( reverse && (showv || cornerWidget() )) ? vsbExt : 0;
975 int xpos = reverse ? 0 : w - vsbExt;
976 bool frameContentsOnly =
977 style().styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
978
979 if( ! frameContentsOnly ) {
980 if ( reverse )
981 xpos += fw;
982 else
983 xpos -= fw;
984 }
985 if ( showh ) {
986 int right = ( showc || showv || cornerWidget() ) ? w-vsbExt : w;
987 if ( ! frameContentsOnly )
988 setHBarGeometry( *d->hbar, fw + xoffset, h-hsbExt-fw,
989 right-fw-fw, hsbExt );
990 else
991 setHBarGeometry( *d->hbar, 0 + xoffset, h-hsbExt, right,
992 hsbExt );
993 bottom=h-hsbExt;
994 } else {
995 bottom=h;
996 }
997 if ( showv ) {
998 clipper()->setGeometry( lmarg + xoffset, tmarg,
999 w-vsbExt-lmarg-rmarg,
1000 bottom-tmarg-bmarg );
1001 d->viewportResized( w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg );
1002 if ( ! frameContentsOnly )
1003 changeFrameRect(QRect(0, 0, w, h) );
1004 else
1005 changeFrameRect(QRect(xoffset, 0, w-vsbExt, bottom));
1006 if (showc || cornerWidget()) {
1007 if ( ! frameContentsOnly )
1008 setVBarGeometry( *d->vbar, xpos,
1009 fw, vsbExt,
1010 h-hsbExt-fw-fw );
1011 else
1012 setVBarGeometry( *d->vbar, xpos, 0,
1013 vsbExt,
1014 h-hsbExt );
1015 }
1016 else {
1017 if ( ! frameContentsOnly )
1018 setVBarGeometry( *d->vbar, xpos,
1019 fw, vsbExt,
1020 bottom-fw-fw );
1021 else
1022 setVBarGeometry( *d->vbar, xpos, 0,
1023 vsbExt, bottom );
1024 }
1025 } else {
1026 if ( ! frameContentsOnly )
1027 changeFrameRect(QRect(0, 0, w, h));
1028 else
1029 changeFrameRect(QRect(0, 0, w, bottom));
1030 clipper()->setGeometry( lmarg, tmarg,
1031 w-lmarg-rmarg, bottom-tmarg-bmarg );
1032 d->viewportResized( w-lmarg-rmarg, bottom-tmarg-bmarg );
1033 }
1034
1035 QWidget *corner = d->corner;
1036 if ( !d->corner )
1037 corner = d->defaultCorner;
1038 if ( ! frameContentsOnly )
1039 corner->setGeometry( xpos,
1040 h-hsbExt-fw,
1041 vsbExt,
1042 hsbExt );
1043 else
1044 corner->setGeometry( xpos,
1045 h-hsbExt,
1046 vsbExt,
1047 hsbExt );
1048
1049 d->signal_choke=sc;
1050
1051 if ( d->contentsX()+visibleWidth() > d->contentsWidth() ) {
1052 int x;
1053#if 0
1054 if ( reverse )
1055 x =QMIN(0,d->contentsWidth()-visibleWidth());
1056 else
1057#endif
1058 x =QMAX(0,d->contentsWidth()-visibleWidth());
1059 d->hbar->setValue(x);
1060 // Do it even if it is recursive
1061 moveContents( -x, -d->contentsY() );
1062 }
1063 if ( d->contentsY()+visibleHeight() > contentsHeight() ) {
1064 int y=QMAX(0,contentsHeight()-visibleHeight());
1065 d->vbar->setValue(y);
1066 // Do it even if it is recursive
1067 moveContents( -d->contentsX(), -y );
1068 }
1069
1070 // Finally, show the scroll bars
1071 if ( showh && ( d->hbar->isHidden() || !d->hbar->isVisible() ) )
1072 d->hbar->show();
1073 if ( showv && ( d->vbar->isHidden() || !d->vbar->isVisible() ) )
1074 d->vbar->show();
1075
1076 d->signal_choke=TRUE;
1077 d->vbar->setValue( d->contentsY() );
1078 d->hbar->setValue( d->contentsX() );
1079 d->signal_choke=FALSE;
1080
1081 QSize newVisibleSize( visibleWidth(), visibleHeight() );
1082 if ( d->clipped_viewport && oldVisibleSize != newVisibleSize ) {
1083 QResizeEvent e( newVisibleSize, oldVisibleSize );
1084 viewportResizeEvent( &e );
1085 }
1086}
1087
1088
1089/*!
1090 \reimp
1091*/
1092void QScrollView::show()
1093{
1094 if ( isVisible() )
1095 return;
1096 QWidget::show();
1097 updateScrollBars();
1098 d->hideOrShowAll(this);
1099}
1100
1101/*!
1102 \reimp
1103 */
1104void QScrollView::resize( int w, int h )
1105{
1106 QWidget::resize( w, h );
1107}
1108
1109/*!
1110 \reimp
1111*/
1112void QScrollView::resize( const QSize& s )
1113{
1114 resize( s.width(), s.height() );
1115}
1116
1117/*!
1118 \reimp
1119*/
1120void QScrollView::resizeEvent( QResizeEvent* event )
1121{
1122 QFrame::resizeEvent( event );
1123
1124#if 0
1125 if ( QApplication::reverseLayout() ) {
1126 d->fake_scroll = TRUE;
1127 scrollBy( -event->size().width() + event->oldSize().width(), 0 );
1128 d->fake_scroll = FALSE;
1129 }
1130#endif
1131
1132 bool inresize = d->inresize;
1133 d->inresize = TRUE;
1134 updateScrollBars();
1135 d->inresize = inresize;
1136 d->scrollbar_timer.start( 0, TRUE );
1137
1138 d->hideOrShowAll(this);
1139}
1140
1141
1142
1143/*!
1144 \reimp
1145*/
1146void QScrollView::mousePressEvent( QMouseEvent * e) //#### remove for 4.0
1147{
1148 e->ignore();
1149}
1150
1151/*!
1152 \reimp
1153*/
1154void QScrollView::mouseReleaseEvent( QMouseEvent *e ) //#### remove for 4.0
1155{
1156 e->ignore();
1157}
1158
1159
1160/*!
1161 \reimp
1162*/
1163void QScrollView::mouseDoubleClickEvent( QMouseEvent *e ) //#### remove for 4.0
1164{
1165 e->ignore();
1166}
1167
1168/*!
1169 \reimp
1170*/
1171void QScrollView::mouseMoveEvent( QMouseEvent *e ) //#### remove for 4.0
1172{
1173 e->ignore();
1174}
1175
1176/*!
1177 \reimp
1178*/
1179#ifndef QT_NO_WHEELEVENT
1180void QScrollView::wheelEvent( QWheelEvent *e )
1181{
1182 QWheelEvent ce( viewport()->mapFromGlobal( e->globalPos() ),
1183 e->globalPos(), e->delta(), e->state());
1184 viewportWheelEvent(&ce);
1185 if ( !ce.isAccepted() ) {
1186 if ( e->orientation() == Horizontal && horizontalScrollBar() )
1187 QApplication::sendEvent( horizontalScrollBar(), e);
1188 else if (e->orientation() == Vertical && verticalScrollBar() )
1189 QApplication::sendEvent( verticalScrollBar(), e);
1190 } else {
1191 e->accept();
1192 }
1193}
1194#endif
1195
1196/*!
1197 \reimp
1198*/
1199void QScrollView::contextMenuEvent( QContextMenuEvent *e )
1200{
1201 if ( e->reason() != QContextMenuEvent::Keyboard ) {
1202 e->ignore();
1203 return;
1204 }
1205
1206 QContextMenuEvent ce( e->reason(), viewport()->mapFromGlobal( e->globalPos() ),
1207 e->globalPos(), e->state() );
1208 viewportContextMenuEvent( &ce );
1209 if ( ce.isAccepted() )
1210 e->accept();
1211 else
1212 e->ignore();
1213}
1214
1215QScrollView::ScrollBarMode QScrollView::vScrollBarMode() const
1216{
1217 return d->vMode;
1218}
1219
1220
1221/*!
1222 \enum QScrollView::ScrollBarMode
1223
1224 This enum type describes the various modes of QScrollView's scroll
1225 bars.
1226
1227 \value Auto QScrollView shows a scroll bar when the content is
1228 too large to fit and not otherwise. This is the default.
1229
1230 \value AlwaysOff QScrollView never shows a scroll bar.
1231
1232 \value AlwaysOn QScrollView always shows a scroll bar.
1233
1234 (The modes for the horizontal and vertical scroll bars are
1235 independent.)
1236*/
1237
1238
1239/*!
1240 \property QScrollView::vScrollBarMode
1241 \brief the mode for the vertical scroll bar
1242
1243 The default mode is \c QScrollView::Auto.
1244
1245 \sa hScrollBarMode
1246*/
1247void QScrollView::setVScrollBarMode( ScrollBarMode mode )
1248{
1249 if (d->vMode != mode) {
1250 d->vMode = mode;
1251 updateScrollBars();
1252 }
1253}
1254
1255
1256/*!
1257 \property QScrollView::hScrollBarMode
1258 \brief the mode for the horizontal scroll bar
1259
1260 The default mode is \c QScrollView::Auto.
1261
1262 \sa vScrollBarMode
1263*/
1264QScrollView::ScrollBarMode QScrollView::hScrollBarMode() const
1265{
1266 return d->hMode;
1267}
1268
1269void QScrollView::setHScrollBarMode( ScrollBarMode mode )
1270{
1271 if (d->hMode != mode) {
1272 d->hMode = mode;
1273 updateScrollBars();
1274 }
1275}
1276
1277
1278/*!
1279 Returns the widget in the corner between the two scroll bars.
1280
1281 By default, no corner widget is present.
1282*/
1283QWidget* QScrollView::cornerWidget() const
1284{
1285 return d->corner;
1286}
1287
1288/*!
1289 Sets the widget in the \a corner between the two scroll bars.
1290
1291 You will probably also want to set at least one of the scroll bar
1292 modes to \c AlwaysOn.
1293
1294 Passing 0 shows no widget in the corner.
1295
1296 Any previous \a corner widget is hidden.
1297
1298 You may call setCornerWidget() with the same widget at different
1299 times.
1300
1301 All widgets set here will be deleted by the QScrollView when it is
1302 destroyed unless you separately reparent the widget after setting
1303 some other corner widget (or 0).
1304
1305 Any \e newly set widget should have no current parent.
1306
1307 By default, no corner widget is present.
1308
1309 \sa setVScrollBarMode(), setHScrollBarMode()
1310*/
1311void QScrollView::setCornerWidget(QWidget* corner)
1312{
1313 QWidget* oldcorner = d->corner;
1314 if (oldcorner != corner) {
1315 if (oldcorner) oldcorner->hide();
1316 d->corner = corner;
1317
1318 if ( corner && corner->parentWidget() != this ) {
1319 // #### No clean way to get current WFlags
1320 corner->reparent( this, (((QScrollView*)corner))->getWFlags(),
1321 QPoint(0,0), FALSE );
1322 }
1323
1324 updateScrollBars();
1325 if ( corner ) corner->show();
1326 }
1327}
1328
1329
1330void QScrollView::setResizePolicy( ResizePolicy r )
1331{
1332 d->policy = r;
1333}
1334
1335/*!
1336 \property QScrollView::resizePolicy
1337 \brief the resize policy
1338
1339 The default is \c Default.
1340
1341 \sa ResizePolicy
1342*/
1343QScrollView::ResizePolicy QScrollView::resizePolicy() const
1344{
1345 return d->policy;
1346}
1347
1348/*!
1349 \reimp
1350*/
1351void QScrollView::setEnabled( bool enable )
1352{
1353 QFrame::setEnabled( enable );
1354}
1355
1356/*!
1357 Removes the \a child widget from the scrolled area. Note that this
1358 happens automatically if the \a child is deleted.
1359*/
1360void QScrollView::removeChild(QWidget* child)
1361{
1362 if ( !d || !child ) // First check in case we are destructing
1363 return;
1364
1365 QSVChildRec *r = d->rec(child);
1366 if ( r ) d->deleteChildRec( r );
1367}
1368
1369/*!
1370 \reimp
1371*/
1372void QScrollView::removeChild(QObject* child)
1373{
1374 QFrame::removeChild(child);
1375}
1376
1377/*!
1378 Inserts the widget, \a child, into the scrolled area positioned at
1379 (\a x, \a y). The position defaults to (0, 0). If the child is
1380 already in the view, it is just moved.
1381
1382 You may want to call enableClipper(TRUE) if you add a large number
1383 of widgets.
1384*/
1385void QScrollView::addChild(QWidget* child, int x, int y)
1386{
1387 if ( !child ) {
1388#if defined(QT_CHECK_NULL)
1389 qWarning( "QScrollView::addChild(): Cannot add null child" );
1390#endif
1391 return;
1392 }
1393 child->polish();
1394 child->setBackgroundOrigin(WidgetOrigin);
1395
1396 if ( child->parentWidget() == viewport() ) {
1397 // May already be there
1398 QSVChildRec *r = d->rec(child);
1399 if (r) {
1400 r->moveTo(this,x,y,d->clipped_viewport);
1401 if ( d->policy > Manual ) {
1402 d->autoResizeHint(this);
1403 d->autoResize(this); // #### better to just deal with this one widget!
1404 }
1405 return;
1406 }
1407 }
1408
1409 if ( d->children.isEmpty() && d->policy != Manual ) {
1410 if ( d->policy == Default )
1411 setResizePolicy( AutoOne );
1412 child->installEventFilter( this );
1413 } else if ( d->policy == AutoOne ) {
1414 child->removeEventFilter( this ); //#### ?????
1415 setResizePolicy( Manual );
1416 }
1417 if ( child->parentWidget() != viewport() ) {
1418 child->reparent( viewport(), 0, QPoint(0,0), FALSE );
1419 }
1420 d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport);
1421
1422 if ( d->policy > Manual ) {
1423 d->autoResizeHint(this);
1424 d->autoResize(this); // #### better to just deal with this one widget!
1425 }
1426}
1427
1428/*!
1429 Repositions the \a child widget to (\a x, \a y). This function is
1430 the same as addChild().
1431*/
1432void QScrollView::moveChild(QWidget* child, int x, int y)
1433{
1434 addChild(child,x,y);
1435}
1436
1437/*!
1438 Returns the X position of the given \a child widget. Use this
1439 rather than QWidget::x() for widgets added to the view.
1440
1441 This function returns 0 if \a child has not been added to the view.
1442*/
1443int QScrollView::childX(QWidget* child)
1444{
1445 QSVChildRec *r = d->rec(child);
1446 return r ? r->x : 0;
1447}
1448
1449/*!
1450 Returns the Y position of the given \a child widget. Use this
1451 rather than QWidget::y() for widgets added to the view.
1452
1453 This function returns 0 if \a child has not been added to the view.
1454*/
1455int QScrollView::childY(QWidget* child)
1456{
1457 QSVChildRec *r = d->rec(child);
1458 return r ? r->y : 0;
1459}
1460
1461/*! \fn bool QScrollView::childIsVisible(QWidget*)
1462 \obsolete
1463
1464 Returns TRUE if \a child is visible. This is equivalent
1465 to child->isVisible().
1466*/
1467
1468/*! \fn void QScrollView::showChild(QWidget* child, bool y)
1469 \obsolete
1470
1471 Sets the visibility of \a child. Equivalent to
1472 QWidget::show() or QWidget::hide().
1473*/
1474
1475/*!
1476 This event filter ensures the scroll bars are updated when a
1477 single contents widget is resized, shown, hidden or destroyed; it
1478 passes mouse events to the QScrollView. The event is in \a e and
1479 the object is in \a obj.
1480*/
1481
1482bool QScrollView::eventFilter( QObject *obj, QEvent *e )
1483{
1484 if ( !d )
1485 return FALSE; // we are destructing
1486 if ( obj == d->viewport || obj == d->clipped_viewport ) {
1487 switch ( e->type() ) {
1488 /* Forward many events to viewport...() functions */
1489 case QEvent::Paint:
1490 viewportPaintEvent( (QPaintEvent*)e );
1491 break;
1492 case QEvent::Resize:
1493 if ( !d->clipped_viewport )
1494 viewportResizeEvent( (QResizeEvent *)e );
1495 break;
1496 case QEvent::MouseButtonPress:
1497 viewportMousePressEvent( (QMouseEvent*)e );
1498 if ( ((QMouseEvent*)e)->isAccepted() )
1499 return TRUE;
1500 break;
1501 case QEvent::MouseButtonRelease:
1502 viewportMouseReleaseEvent( (QMouseEvent*)e );
1503 if ( ((QMouseEvent*)e)->isAccepted() )
1504 return TRUE;
1505 break;
1506 case QEvent::MouseButtonDblClick:
1507 viewportMouseDoubleClickEvent( (QMouseEvent*)e );
1508 if ( ((QMouseEvent*)e)->isAccepted() )
1509 return TRUE;
1510 break;
1511 case QEvent::MouseMove:
1512 viewportMouseMoveEvent( (QMouseEvent*)e );
1513 if ( ((QMouseEvent*)e)->isAccepted() )
1514 return TRUE;
1515 break;
1516#ifndef QT_NO_DRAGANDDROP
1517 case QEvent::DragEnter:
1518 viewportDragEnterEvent( (QDragEnterEvent*)e );
1519 break;
1520 case QEvent::DragMove: {
1521 if ( d->drag_autoscroll ) {
1522 QPoint vp = ((QDragMoveEvent*) e)->pos();
1523 QRect inside_margin( autoscroll_margin, autoscroll_margin,
1524 visibleWidth() - autoscroll_margin * 2,
1525 visibleHeight() - autoscroll_margin * 2 );
1526 if ( !inside_margin.contains( vp ) ) {
1527 startDragAutoScroll();
1528 // Keep sending move events
1529 ( (QDragMoveEvent*)e )->accept( QRect(0,0,0,0) );
1530 }
1531 }
1532 viewportDragMoveEvent( (QDragMoveEvent*)e );
1533 } break;
1534 case QEvent::DragLeave:
1535 stopDragAutoScroll();
1536 viewportDragLeaveEvent( (QDragLeaveEvent*)e );
1537 break;
1538 case QEvent::Drop:
1539 stopDragAutoScroll();
1540 viewportDropEvent( (QDropEvent*)e );
1541 break;
1542#endif // QT_NO_DRAGANDDROP
1543 case QEvent::ContextMenu:
1544 viewportContextMenuEvent( (QContextMenuEvent*)e );
1545 if ( ((QContextMenuEvent*)e)->isAccepted() )
1546 return TRUE;
1547 break;
1548 case QEvent::ChildRemoved:
1549 removeChild((QWidget*)((QChildEvent*)e)->child());
1550 break;
1551 case QEvent::LayoutHint:
1552 d->autoResizeHint(this);
1553 break;
1554 default:
1555 break;
1556 }
1557 } else if ( d && d->rec((QWidget*)obj) ) { // must be a child
1558 if ( e->type() == QEvent::Resize )
1559 d->autoResize(this);
1560 else if ( e->type() == QEvent::Move )
1561 d->autoMove(this);
1562 }
1563 return QFrame::eventFilter( obj, e ); // always continue with standard event processing
1564}
1565
1566/*!
1567 This event handler is called whenever the QScrollView receives a
1568 mousePressEvent(): the press position in \a e is translated to be a point
1569 on the contents.
1570*/
1571void QScrollView::contentsMousePressEvent( QMouseEvent* e )
1572{
1573 e->ignore();
1574}
1575
1576/*!
1577 This event handler is called whenever the QScrollView receives a
1578 mouseReleaseEvent(): the release position in \a e is translated to be a
1579 point on the contents.
1580*/
1581void QScrollView::contentsMouseReleaseEvent( QMouseEvent* e )
1582{
1583 e->ignore();
1584}
1585
1586/*!
1587 This event handler is called whenever the QScrollView receives a
1588 mouseDoubleClickEvent(): the click position in \a e is translated to be a
1589 point on the contents.
1590
1591 The default implementation generates a normal mouse press event.
1592*/
1593void QScrollView::contentsMouseDoubleClickEvent( QMouseEvent* e )
1594{
1595 contentsMousePressEvent(e); // try mouse press event
1596}
1597
1598/*!
1599 This event handler is called whenever the QScrollView receives a
1600 mouseMoveEvent(): the mouse position in \a e is translated to be a point
1601 on the contents.
1602*/
1603void QScrollView::contentsMouseMoveEvent( QMouseEvent* e )
1604{
1605 e->ignore();
1606}
1607
1608#ifndef QT_NO_DRAGANDDROP
1609
1610/*!
1611 This event handler is called whenever the QScrollView receives a
1612 dragEnterEvent(): the drag position is translated to be a point
1613 on the contents.
1614*/
1615void QScrollView::contentsDragEnterEvent( QDragEnterEvent * )
1616{
1617}
1618
1619/*!
1620 This event handler is called whenever the QScrollView receives a
1621 dragMoveEvent(): the drag position is translated to be a point on
1622 the contents.
1623*/
1624void QScrollView::contentsDragMoveEvent( QDragMoveEvent * )
1625{
1626}
1627
1628/*!
1629 This event handler is called whenever the QScrollView receives a
1630 dragLeaveEvent(): the drag position is translated to be a point
1631 on the contents.
1632*/
1633void QScrollView::contentsDragLeaveEvent( QDragLeaveEvent * )
1634{
1635}
1636
1637/*!
1638 This event handler is called whenever the QScrollView receives a
1639 dropEvent(): the drop position is translated to be a point on the
1640 contents.
1641*/
1642void QScrollView::contentsDropEvent( QDropEvent * )
1643{
1644}
1645
1646#endif // QT_NO_DRAGANDDROP
1647
1648/*!
1649 This event handler is called whenever the QScrollView receives a
1650 wheelEvent() in \a{e}: the mouse position is translated to be a
1651 point on the contents.
1652*/
1653#ifndef QT_NO_WHEELEVENT
1654void QScrollView::contentsWheelEvent( QWheelEvent * e )
1655{
1656 e->ignore();
1657}
1658#endif
1659/*!
1660 This event handler is called whenever the QScrollView receives a
1661 contextMenuEvent() in \a{e}: the mouse position is translated to
1662 be a point on the contents.
1663*/
1664void QScrollView::contentsContextMenuEvent( QContextMenuEvent *e )
1665{
1666 e->ignore();
1667}
1668
1669/*!
1670 This is a low-level painting routine that draws the viewport
1671 contents. Reimplement this if drawContents() is too high-level
1672 (for example, if you don't want to open a QPainter on the
1673 viewport). The paint event is passed in \a pe.
1674*/
1675void QScrollView::viewportPaintEvent( QPaintEvent* pe )
1676{
1677 QWidget* vp = viewport();
1678
1679 QPainter p(vp);
1680 QRect r = pe->rect();
1681
1682 if ( d->clipped_viewport ) {
1683 QRect rr(
1684 -d->clipped_viewport->x(), -d->clipped_viewport->y(),
1685 d->viewport->width(), d->viewport->height()
1686 );
1687 r &= rr;
1688 if ( r.isValid() ) {
1689 int ex = r.x() + d->clipped_viewport->x() + d->contentsX();
1690 int ey = r.y() + d->clipped_viewport->y() + d->contentsY();
1691 int ew = r.width();
1692 int eh = r.height();
1693 drawContentsOffset(&p,
1694 d->contentsX()+d->clipped_viewport->x(),
1695 d->contentsY()+d->clipped_viewport->y(),
1696 ex, ey, ew, eh);
1697 }
1698 } else {
1699 r &= d->viewport->rect();
1700 int ex = r.x() + d->contentsX();
1701 int ey = r.y() + d->contentsY();
1702 int ew = r.width();
1703 int eh = r.height();
1704 drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh);
1705 }
1706}
1707
1708
1709/*!
1710 To provide simple processing of events on the contents, this
1711 function receives all resize events sent to the viewport.
1712
1713 \sa QWidget::resizeEvent()
1714*/
1715void QScrollView::viewportResizeEvent( QResizeEvent* )
1716{
1717}
1718
1719/*! \internal
1720
1721 To provide simple processing of events on the contents, this
1722 function receives all mouse press events sent to the viewport,
1723 translates the event and calls contentsMousePressEvent().
1724
1725 \sa contentsMousePressEvent(), QWidget::mousePressEvent()
1726*/
1727void QScrollView::viewportMousePressEvent( QMouseEvent* e )
1728{
1729 QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1730 e->globalPos(), e->button(), e->state());
1731 contentsMousePressEvent(&ce);
1732 if ( !ce.isAccepted() )
1733 e->ignore();
1734}
1735
1736/*!\internal
1737
1738 To provide simple processing of events on the contents, this function
1739 receives all mouse release events sent to the viewport, translates
1740 the event and calls contentsMouseReleaseEvent().
1741
1742 \sa QWidget::mouseReleaseEvent()
1743*/
1744void QScrollView::viewportMouseReleaseEvent( QMouseEvent* e )
1745{
1746 QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1747 e->globalPos(), e->button(), e->state());
1748 contentsMouseReleaseEvent(&ce);
1749 if ( !ce.isAccepted() )
1750 e->ignore();
1751}
1752
1753/*!\internal
1754
1755 To provide simple processing of events on the contents, this function
1756 receives all mouse double click events sent to the viewport,
1757 translates the event and calls contentsMouseDoubleClickEvent().
1758
1759 \sa QWidget::mouseDoubleClickEvent()
1760*/
1761void QScrollView::viewportMouseDoubleClickEvent( QMouseEvent* e )
1762{
1763 QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1764 e->globalPos(), e->button(), e->state());
1765 contentsMouseDoubleClickEvent(&ce);
1766 if ( !ce.isAccepted() )
1767 e->ignore();
1768}
1769
1770/*!\internal
1771
1772 To provide simple processing of events on the contents, this function
1773 receives all mouse move events sent to the viewport, translates the
1774 event and calls contentsMouseMoveEvent().
1775
1776 \sa QWidget::mouseMoveEvent()
1777*/
1778void QScrollView::viewportMouseMoveEvent( QMouseEvent* e )
1779{
1780 QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1781 e->globalPos(), e->button(), e->state());
1782 contentsMouseMoveEvent(&ce);
1783 if ( !ce.isAccepted() )
1784 e->ignore();
1785}
1786
1787#ifndef QT_NO_DRAGANDDROP
1788
1789/*!\internal
1790
1791 To provide simple processing of events on the contents, this function
1792 receives all drag enter events sent to the viewport, translates the
1793 event and calls contentsDragEnterEvent().
1794
1795 \sa QWidget::dragEnterEvent()
1796*/
1797void QScrollView::viewportDragEnterEvent( QDragEnterEvent* e )
1798{
1799 e->setPoint(viewportToContents(e->pos()));
1800 contentsDragEnterEvent(e);
1801 e->setPoint(contentsToViewport(e->pos()));
1802}
1803
1804/*!\internal
1805
1806 To provide simple processing of events on the contents, this function
1807 receives all drag move events sent to the viewport, translates the
1808 event and calls contentsDragMoveEvent().
1809
1810 \sa QWidget::dragMoveEvent()
1811*/
1812void QScrollView::viewportDragMoveEvent( QDragMoveEvent* e )
1813{
1814 e->setPoint(viewportToContents(e->pos()));
1815 contentsDragMoveEvent(e);
1816 e->setPoint(contentsToViewport(e->pos()));
1817}
1818
1819/*!\internal
1820
1821 To provide simple processing of events on the contents, this function
1822 receives all drag leave events sent to the viewport and calls
1823 contentsDragLeaveEvent().
1824
1825 \sa QWidget::dragLeaveEvent()
1826*/
1827void QScrollView::viewportDragLeaveEvent( QDragLeaveEvent* e )
1828{
1829 contentsDragLeaveEvent(e);
1830}
1831
1832/*!\internal
1833
1834 To provide simple processing of events on the contents, this function
1835 receives all drop events sent to the viewport, translates the event
1836 and calls contentsDropEvent().
1837
1838 \sa QWidget::dropEvent()
1839*/
1840void QScrollView::viewportDropEvent( QDropEvent* e )
1841{
1842 e->setPoint(viewportToContents(e->pos()));
1843 contentsDropEvent(e);
1844 e->setPoint(contentsToViewport(e->pos()));
1845}
1846
1847#endif // QT_NO_DRAGANDDROP
1848
1849/*!\internal
1850
1851 To provide simple processing of events on the contents, this function
1852 receives all wheel events sent to the viewport, translates the
1853 event and calls contentsWheelEvent().
1854
1855 \sa QWidget::wheelEvent()
1856*/
1857#ifndef QT_NO_WHEELEVENT
1858void QScrollView::viewportWheelEvent( QWheelEvent* e )
1859{
1860 /*
1861 Different than standard mouse events, because wheel events might
1862 be sent to the focus widget if the widget-under-mouse doesn't want
1863 the event itself.
1864 */
1865 QWheelEvent ce( viewportToContents(e->pos()),
1866 e->globalPos(), e->delta(), e->state());
1867 contentsWheelEvent(&ce);
1868 if ( ce.isAccepted() )
1869 e->accept();
1870 else
1871 e->ignore();
1872}
1873#endif
1874
1875/*! \internal
1876
1877 To provide simple processing of events on the contents, this function
1878 receives all context menu events sent to the viewport, translates the
1879 event and calls contentsContextMenuEvent().
1880*/
1881void QScrollView::viewportContextMenuEvent( QContextMenuEvent *e )
1882{
1883 QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state() );
1884 contentsContextMenuEvent( &ce );
1885 if ( ce.isAccepted() )
1886 e->accept();
1887 else
1888 e->ignore();
1889}
1890
1891/*!
1892 Returns the component horizontal scroll bar. It is made available
1893 to allow accelerators, autoscrolling, etc.
1894
1895 It should not be used for other purposes.
1896
1897 This function never returns 0.
1898*/
1899QScrollBar* QScrollView::horizontalScrollBar() const
1900{
1901 return d->hbar;
1902}
1903
1904/*!
1905 Returns the component vertical scroll bar. It is made available to
1906 allow accelerators, autoscrolling, etc.
1907
1908 It should not be used for other purposes.
1909
1910 This function never returns 0.
1911*/
1912QScrollBar* QScrollView::verticalScrollBar() const {
1913 return d->vbar;
1914}
1915
1916
1917/*!
1918 Scrolls the content so that the point \a (x, y) is visible with at
1919 least 50-pixel margins (if possible, otherwise centered).
1920*/
1921void QScrollView::ensureVisible( int x, int y )
1922{
1923 ensureVisible(x, y, 50, 50);
1924}
1925
1926/*!
1927 \overload
1928
1929 Scrolls the content so that the point \a (x, y) is visible with at
1930 least the \a xmargin and \a ymargin margins (if possible,
1931 otherwise centered).
1932*/
1933void QScrollView::ensureVisible( int x, int y, int xmargin, int ymargin )
1934{
1935 int pw=visibleWidth();
1936 int ph=visibleHeight();
1937
1938 int cx=-d->contentsX();
1939 int cy=-d->contentsY();
1940 int cw=d->contentsWidth();
1941 int ch=contentsHeight();
1942
1943 if ( pw < xmargin*2 )
1944 xmargin=pw/2;
1945 if ( ph < ymargin*2 )
1946 ymargin=ph/2;
1947
1948 if ( cw <= pw ) {
1949 xmargin=0;
1950 cx=0;
1951 }
1952 if ( ch <= ph ) {
1953 ymargin=0;
1954 cy=0;
1955 }
1956
1957 if ( x < -cx+xmargin )
1958 cx = -x+xmargin;
1959 else if ( x >= -cx+pw-xmargin )
1960 cx = -x+pw-xmargin;
1961
1962 if ( y < -cy+ymargin )
1963 cy = -y+ymargin;
1964 else if ( y >= -cy+ph-ymargin )
1965 cy = -y+ph-ymargin;
1966
1967 if ( cx > 0 )
1968 cx=0;
1969 else if ( cx < pw-cw && cw>pw )
1970 cx=pw-cw;
1971
1972 if ( cy > 0 )
1973 cy=0;
1974 else if ( cy < ph-ch && ch>ph )
1975 cy=ph-ch;
1976
1977 setContentsPos( -cx, -cy );
1978}
1979
1980/*!
1981 Scrolls the content so that the point \a (x, y) is in the top-left
1982 corner.
1983*/
1984void QScrollView::setContentsPos( int x, int y )
1985{
1986#if 0
1987 // bounds checking...
1988 if ( QApplication::reverseLayout() )
1989 if ( x > d->contentsWidth() - visibleWidth() ) x = d->contentsWidth() - visibleWidth();
1990 else
1991#endif
1992 if ( x < 0 ) x = 0;
1993 if ( y < 0 ) y = 0;
1994 // Choke signal handling while we update BOTH sliders.
1995 d->signal_choke=TRUE;
1996 moveContents( -x, -y );
1997 d->vbar->setValue( y );
1998 d->hbar->setValue( x );
1999 d->signal_choke=FALSE;
2000}
2001
2002/*!
2003 Scrolls the content by \a dx to the left and \a dy upwards.
2004*/
2005void QScrollView::scrollBy( int dx, int dy )
2006{
2007 setContentsPos( QMAX( d->contentsX()+dx, 0 ), QMAX( d->contentsY()+dy, 0 ) );
2008}
2009
2010/*!
2011 Scrolls the content so that the point \a (x, y) is in the center
2012 of visible area.
2013*/
2014void QScrollView::center( int x, int y )
2015{
2016 ensureVisible( x, y, 32000, 32000 );
2017}
2018
2019/*!
2020 \overload
2021
2022 Scrolls the content so that the point \a (x, y) is visible with
2023 the \a xmargin and \a ymargin margins (as fractions of visible
2024 the area).
2025
2026 For example:
2027 \list
2028 \i Margin 0.0 allows (x, y) to be on the edge of the visible area.
2029 \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area.
2030 \i Margin 1.0 ensures that (x, y) is in the center of the the visible area.
2031 \endlist
2032*/
2033void QScrollView::center( int x, int y, float xmargin, float ymargin )
2034{
2035 int pw=visibleWidth();
2036 int ph=visibleHeight();
2037 ensureVisible( x, y, int( xmargin/2.0*pw+0.5 ), int( ymargin/2.0*ph+0.5 ) );
2038}
2039
2040
2041/*!
2042 \fn void QScrollView::contentsMoving(int x, int y)
2043
2044 This signal is emitted just before the contents are moved to
2045 position \a (x, y).
2046
2047 \sa contentsX(), contentsY()
2048*/
2049
2050/*!
2051 Moves the contents by \a (x, y).
2052*/
2053void QScrollView::moveContents(int x, int y)
2054{
2055 if ( -x+visibleWidth() > d->contentsWidth() )
2056#if 0
2057 if( QApplication::reverseLayout() )
2058 x=QMAX(0,-d->contentsWidth()+visibleWidth());
2059 else
2060#endif
2061 x=QMIN(0,-d->contentsWidth()+visibleWidth());
2062 if ( -y+visibleHeight() > contentsHeight() )
2063 y=QMIN(0,-contentsHeight()+visibleHeight());
2064
2065 int dx = x - d->vx;
2066 int dy = y - d->vy;
2067
2068 if (!dx && !dy)
2069 return; // Nothing to do
2070
2071 emit contentsMoving( -x, -y );
2072
2073 d->vx = x;
2074 d->vy = y;
2075
2076 if ( d->clipped_viewport || d->static_bg ) {
2077 // Cheap move (usually)
2078 d->moveAllBy(dx,dy);
2079 } else if ( /*dx && dy ||*/
2080 ( QABS(dy) * 5 > visibleHeight() * 4 ) ||
2081 ( QABS(dx) * 5 > visibleWidth() * 4 )
2082 )
2083 {
2084 // Big move
2085 if ( viewport()->isUpdatesEnabled() )
2086 viewport()->update();
2087 d->moveAllBy(dx,dy);
2088 } else if ( !d->fake_scroll || d->contentsWidth() > visibleWidth() ) {
2089 // Small move
2090 clipper()->scroll(dx,dy);
2091 }
2092 d->hideOrShowAll(this, TRUE );
2093}
2094
2095#if (QT_VERSION-0 >= 0x040000)
2096#if defined(Q_CC_GNU)
2097#warning "Should rename contents{X,Y,Width,Height} to viewport{...}"
2098#endif
2099// Because it's the viewport rectangle that is "moving", not the contents.
2100#endif
2101
2102/*!
2103 \property QScrollView::contentsX
2104 \brief the X coordinate of the contents that are at the left edge of
2105 the viewport.
2106*/
2107int QScrollView::contentsX() const
2108{
2109 return d->contentsX();
2110}
2111
2112/*!
2113 \property QScrollView::contentsY
2114 \brief the Y coordinate of the contents that are at the top edge of
2115 the viewport.
2116*/
2117int QScrollView::contentsY() const
2118{
2119 return d->contentsY();
2120}
2121
2122/*!
2123 \property QScrollView::contentsWidth
2124 \brief the width of the contents area
2125*/
2126int QScrollView::contentsWidth() const
2127{
2128 return d->contentsWidth();
2129}
2130
2131/*!
2132 \property QScrollView::contentsHeight
2133 \brief the height of the contents area
2134*/
2135int QScrollView::contentsHeight() const
2136{
2137 return d->vheight;
2138}
2139
2140/*!
2141 Sets the size of the contents area to \a w pixels wide and \a h
2142 pixels high and updates the viewport accordingly.
2143*/
2144void QScrollView::resizeContents( int w, int h )
2145{
2146 int ow = d->vwidth;
2147 int oh = d->vheight;
2148 d->vwidth = w;
2149 d->vheight = h;
2150
2151 d->scrollbar_timer.start( 0, TRUE );
2152
2153 if ( d->children.isEmpty() && d->policy == Default )
2154 setResizePolicy( Manual );
2155
2156 if ( ow > w ) {
2157 // Swap
2158 int t=w;
2159 w=ow;
2160 ow=t;
2161 }
2162 // Refresh area ow..w
2163 if ( ow < visibleWidth() && w >= 0 ) {
2164 if ( ow < 0 )
2165 ow = 0;
2166 if ( w > visibleWidth() )
2167 w = visibleWidth();
2168 clipper()->update( d->contentsX()+ow, 0, w-ow, visibleHeight() );
2169 }
2170
2171 if ( oh > h ) {
2172 // Swap
2173 int t=h;
2174 h=oh;
2175 oh=t;
2176 }
2177 // Refresh area oh..h
2178 if ( oh < visibleHeight() && h >= 0 ) {
2179 if ( oh < 0 )
2180 oh = 0;
2181 if ( h > visibleHeight() )
2182 h = visibleHeight();
2183 clipper()->update( 0, d->contentsY()+oh, visibleWidth(), h-oh);
2184 }
2185}
2186
2187/*!
2188 Calls update() on a rectangle defined by \a x, \a y, \a w, \a h,
2189 translated appropriately. If the rectangle is not visible, nothing
2190 is repainted.
2191
2192 \sa repaintContents()
2193*/
2194void QScrollView::updateContents( int x, int y, int w, int h )
2195{
2196 if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible )
2197 return;
2198
2199 QWidget* vp = viewport();
2200
2201 // Translate
2202 x -= d->contentsX();
2203 y -= d->contentsY();
2204
2205 // Clip to QCOORD space
2206 if ( x < 0 ) {
2207 w += x;
2208 x = 0;
2209 }
2210 if ( y < 0 ) {
2211 h += y;
2212 y = 0;
2213 }
2214
2215 if ( w < 0 || h < 0 )
2216 return;
2217 if ( x > visibleWidth() || y > visibleHeight() )
2218 return;
2219
2220 if ( w > visibleWidth() )
2221 w = visibleWidth();
2222 if ( h > visibleHeight() )
2223 h = visibleHeight();
2224
2225 if ( d->clipped_viewport ) {
2226 // Translate clipper() to viewport()
2227 x -= d->clipped_viewport->x();
2228 y -= d->clipped_viewport->y();
2229 }
2230
2231 vp->update( x, y, w, h );
2232}
2233
2234/*!
2235 \overload
2236
2237 Updates the contents in rectangle \a r
2238*/
2239void QScrollView::updateContents( const QRect& r )
2240{
2241 updateContents(r.x(), r.y(), r.width(), r.height());
2242}
2243
2244/*!
2245 \overload
2246*/
2247void QScrollView::updateContents()
2248{
2249 updateContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight() );
2250}
2251
2252/*!
2253 \overload
2254
2255 Repaints the contents of rectangle \a r. If \a erase is TRUE the
2256 background is cleared using the background color.
2257*/
2258void QScrollView::repaintContents( const QRect& r, bool erase )
2259{
2260 repaintContents(r.x(), r.y(), r.width(), r.height(), erase);
2261}
2262
2263
2264/*!
2265 \overload
2266
2267 Repaints the contents. If \a erase is TRUE the background is
2268 cleared using the background color.
2269*/
2270void QScrollView::repaintContents( bool erase )
2271{
2272 repaintContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase );
2273}
2274
2275
2276/*!
2277 Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h,
2278 translated appropriately. If the rectangle is not visible, nothing
2279 is repainted. If \a erase is TRUE the background is cleared using
2280 the background color.
2281
2282 \sa updateContents()
2283*/
2284void QScrollView::repaintContents( int x, int y, int w, int h, bool erase )
2285{
2286 if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible )
2287 return;
2288
2289 QWidget* vp = viewport();
2290
2291 // Translate logical to clipper()
2292 x -= d->contentsX();
2293 y -= d->contentsY();
2294
2295 // Clip to QCOORD space
2296 if ( x < 0 ) {
2297 w += x;
2298 x = 0;
2299 }
2300 if ( y < 0 ) {
2301 h += y;
2302 y = 0;
2303 }
2304
2305 if ( w < 0 || h < 0 )
2306 return;
2307 if ( w > visibleWidth() )
2308 w = visibleWidth();
2309 if ( h > visibleHeight() )
2310 h = visibleHeight();
2311
2312 if ( d->clipped_viewport ) {
2313 // Translate clipper() to viewport()
2314 x -= d->clipped_viewport->x();
2315 y -= d->clipped_viewport->y();
2316 }
2317
2318 vp->repaint( x, y, w, h, erase );
2319}
2320
2321
2322/*!
2323 For backward-compatibility only. It is easier to use
2324 drawContents(QPainter*,int,int,int,int).
2325
2326 The default implementation translates the painter appropriately
2327 and calls drawContents(QPainter*,int,int,int,int). See
2328 drawContents() for an explanation of the parameters \a p, \a
2329 offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph.
2330*/
2331void QScrollView::drawContentsOffset(QPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph)
2332{
2333 p->translate(-offsetx,-offsety);
2334 drawContents(p, clipx, clipy, clipw, cliph);
2335}
2336
2337/*!
2338 \fn void QScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph)
2339
2340 Reimplement this function if you are viewing a drawing area rather
2341 than a widget.
2342
2343 The function should draw the rectangle (\a clipx, \a clipy, \a
2344 clipw, \a cliph) of the contents using painter \a p. The clip
2345 rectangle is in the scrollview's coordinates.
2346
2347 For example:
2348 \code
2349 {
2350 // Fill a 40000 by 50000 rectangle at (100000,150000)
2351
2352 // Calculate the coordinates...
2353 int x1 = 100000, y1 = 150000;
2354 int x2 = x1+40000-1, y2 = y1+50000-1;
2355
2356 // Clip the coordinates so X/Windows will not have problems...
2357 if (x1 < clipx) x1=clipx;
2358 if (y1 < clipy) y1=clipy;
2359 if (x2 > clipx+clipw-1) x2=clipx+clipw-1;
2360 if (y2 > clipy+cliph-1) y2=clipy+cliph-1;
2361
2362 // Paint using the small coordinates...
2363 if ( x2 >= x1 && y2 >= y1 )
2364 p->fillRect(x1, y1, x2-x1+1, y2-y1+1, red);
2365 }
2366 \endcode
2367
2368 The clip rectangle and translation of the painter \a p is already
2369 set appropriately.
2370*/
2371void QScrollView::drawContents(QPainter*, int, int, int, int)
2372{
2373}
2374
2375
2376/*!
2377 \reimp
2378*/
2379void QScrollView::frameChanged()
2380{
2381 updateScrollBars();
2382}
2383
2384
2385/*!
2386 Returns the viewport widget of the scrollview. This is the widget
2387 containing the contents widget or which is the drawing area.
2388*/
2389QWidget* QScrollView::viewport() const
2390{
2391 if ( d->clipped_viewport )
2392 return d->clipped_viewport;
2393 return d->viewport;
2394}
2395
2396/*!
2397 Returns the clipper widget. Contents in the scrollview are
2398 ultimately clipped to be inside the clipper widget.
2399
2400 You should not need to use this function.
2401
2402 \sa visibleWidth(), visibleHeight()
2403*/
2404QWidget* QScrollView::clipper() const
2405{
2406 return d->viewport;
2407}
2408
2409/*!
2410 \property QScrollView::visibleWidth
2411 \brief the horizontal amount of the content that is visible
2412*/
2413int QScrollView::visibleWidth() const
2414{
2415 return clipper()->width();
2416}
2417
2418/*!
2419 \property QScrollView::visibleHeight
2420 \brief the vertical amount of the content that is visible
2421*/
2422int QScrollView::visibleHeight() const
2423{
2424 return clipper()->height();
2425}
2426
2427
2428void QScrollView::changeFrameRect(const QRect& r)
2429{
2430 QRect oldr = frameRect();
2431 if (oldr != r) {
2432 QRect cr = contentsRect();
2433 QRegion fr( frameRect() );
2434 fr = fr.subtract( contentsRect() );
2435 setFrameRect( r );
2436 if ( isVisible() ) {
2437 cr = cr.intersect( contentsRect() );
2438 fr = fr.unite( frameRect() );
2439 fr = fr.subtract( cr );
2440 if ( !fr.isEmpty() )
2441 QApplication::postEvent( this, new QPaintEvent( fr, FALSE ) );
2442 }
2443 }
2444}
2445
2446
2447/*!
2448 Sets the margins around the scrolling area to \a left, \a top, \a
2449 right and \a bottom. This is useful for applications such as
2450 spreadsheets with "locked" rows and columns. The marginal space is
2451 \e inside the frameRect() and is left blank; reimplement
2452 drawContents() or put widgets in the unused area.
2453
2454 By default all margins are zero.
2455
2456 \sa frameChanged()
2457*/
2458void QScrollView::setMargins(int left, int top, int right, int bottom)
2459{
2460 if ( left == d->l_marg &&
2461 top == d->t_marg &&
2462 right == d->r_marg &&
2463 bottom == d->b_marg )
2464 return;
2465
2466 d->l_marg = left;
2467 d->t_marg = top;
2468 d->r_marg = right;
2469 d->b_marg = bottom;
2470 updateScrollBars();
2471}
2472
2473
2474/*!
2475 Returns the left margin.
2476
2477 \sa setMargins()
2478*/
2479int QScrollView::leftMargin() const
2480{
2481 return d->l_marg;
2482}
2483
2484
2485/*!
2486 Returns the top margin.
2487
2488 \sa setMargins()
2489*/
2490int QScrollView::topMargin() const
2491{
2492 return d->t_marg;
2493}
2494
2495
2496/*!
2497 Returns the right margin.
2498
2499 \sa setMargins()
2500*/
2501int QScrollView::rightMargin() const
2502{
2503 return d->r_marg;
2504}
2505
2506
2507/*!
2508 Returns the bottom margin.
2509
2510 \sa setMargins()
2511*/
2512int QScrollView::bottomMargin() const
2513{
2514 return d->b_marg;
2515}
2516
2517/*!
2518 \reimp
2519*/
2520bool QScrollView::focusNextPrevChild( bool next )
2521{
2522 // Makes sure that the new focus widget is on-screen, if
2523 // necessary by scrolling the scroll view.
2524
2525 // first set things up for the scan
2526 QFocusData *f = focusData();
2527 QWidget *startingPoint = f->home();
2528 QWidget *candidate = 0;
2529 QWidget *w = next ? f->next() : f->prev();
2530 QSVChildRec *r;
2531
2532 // then scan for a possible focus widget candidate
2533 while( !candidate && w != startingPoint ) {
2534 if ( w != startingPoint &&
2535 (w->focusPolicy() & TabFocus) == TabFocus
2536 && w->isEnabled() &&!w->focusProxy() && w->isVisible() )
2537 candidate = w;
2538 w = next ? f->next() : f->prev();
2539 }
2540
2541 // if we could not find one, maybe super or parentWidget() can?
2542 if ( !candidate )
2543 return QFrame::focusNextPrevChild( next );
2544
2545 // we've found one.
2546 r = d->ancestorRec( candidate );
2547 if ( r && ( r->child == candidate ||
2548 candidate->isVisibleTo( r->child ) ) ) {
2549 QPoint cp = r->child->mapToGlobal(QPoint(0,0));
2550 QPoint cr = candidate->mapToGlobal(QPoint(0,0)) - cp;
2551 ensureVisible( r->x+cr.x()+candidate->width()/2,
2552 r->y+cr.y()+candidate->height()/2,
2553 candidate->width()/2,
2554 candidate->height()/2 );
2555 }
2556
2557 candidate->setFocus();
2558 return TRUE;
2559}
2560
2561
2562
2563/*!
2564 When a large numbers of child widgets are in a scrollview,
2565 especially if they are close together, the scrolling performance
2566 can suffer greatly. If \a y is TRUE the scrollview will use an
2567 extra widget to group child widgets.
2568
2569 Note that you may only call enableClipper() prior to adding
2570 widgets.
2571
2572 For a full discussion, see this class's \link #enableclipper
2573 detailed description\endlink.
2574*/
2575void QScrollView::enableClipper(bool y)
2576{
2577 if ( !d->clipped_viewport == !y )
2578 return;
2579 if ( d->children.count() )
2580 qFatal("May only call QScrollView::enableClipper() before adding widgets");
2581 if ( y ) {
2582 d->clipped_viewport = new QClipperWidget(clipper(), "qt_clipped_viewport", d->flags);
2583 d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2,
2584 coord_limit,coord_limit);
2585 d->clipped_viewport->setBackgroundMode( d->viewport->backgroundMode() );
2586 d->viewport->setBackgroundMode(NoBackground); // no exposures for this
2587 d->viewport->removeEventFilter( this );
2588 d->clipped_viewport->installEventFilter( this );
2589 d->clipped_viewport->show();
2590 } else {
2591 delete d->clipped_viewport;
2592 d->clipped_viewport = 0;
2593 }
2594}
2595
2596/*!
2597 Sets the scrollview to have a static background if \a y is TRUE,
2598 or a scrolling background if \a y is FALSE. By default, the
2599 background is scrolling.
2600
2601 Be aware that this mode is quite slow, as a full repaint of the
2602 visible area has to be triggered on every contents move.
2603
2604 \sa hasStaticBackground()
2605*/
2606void QScrollView::setStaticBackground(bool y)
2607{
2608 d->static_bg = y;
2609}
2610
2611/*!
2612 Returns TRUE if QScrollView uses a static background; otherwise
2613 returns FALSE.
2614
2615 \sa setStaticBackground()
2616*/
2617bool QScrollView::hasStaticBackground() const
2618{
2619 return d->static_bg;
2620}
2621
2622/*!
2623 \overload
2624
2625 Returns the point \a p translated to a point on the viewport()
2626 widget.
2627*/
2628QPoint QScrollView::contentsToViewport( const QPoint& p ) const
2629{
2630 if ( d->clipped_viewport ) {
2631 return QPoint( p.x() - d->contentsX() - d->clipped_viewport->x(),
2632 p.y() - d->contentsY() - d->clipped_viewport->y() );
2633 } else {
2634 return QPoint( p.x() - d->contentsX(),
2635 p.y() - d->contentsY() );
2636 }
2637}
2638
2639/*!
2640 \overload
2641
2642 Returns the point on the viewport \a vp translated to a point in
2643 the contents.
2644*/
2645QPoint QScrollView::viewportToContents( const QPoint& vp ) const
2646{
2647 if ( d->clipped_viewport ) {
2648 return QPoint( vp.x() + d->contentsX() + d->clipped_viewport->x(),
2649 vp.y() + d->contentsY() + d->clipped_viewport->y() );
2650 } else {
2651 return QPoint( vp.x() + d->contentsX(),
2652 vp.y() + d->contentsY() );
2653 }
2654}
2655
2656
2657/*!
2658 Translates a point (\a x, \a y) in the contents to a point (\a vx,
2659 \a vy) on the viewport() widget.
2660*/
2661void QScrollView::contentsToViewport( int x, int y, int& vx, int& vy ) const
2662{
2663 const QPoint v = contentsToViewport(QPoint(x,y));
2664 vx = v.x();
2665 vy = v.y();
2666}
2667
2668/*!
2669 Translates a point (\a vx, \a vy) on the viewport() widget to a
2670 point (\a x, \a y) in the contents.
2671*/
2672void QScrollView::viewportToContents( int vx, int vy, int& x, int& y ) const
2673{
2674 const QPoint c = viewportToContents(QPoint(vx,vy));
2675 x = c.x();
2676 y = c.y();
2677}
2678
2679/*!
2680 \reimp
2681*/
2682QSize QScrollView::sizeHint() const
2683{
2684 if ( d->use_cached_size_hint && d->cachedSizeHint.isValid() )
2685 return d->cachedSizeHint;
2686
2687 constPolish();
2688 int f = 2 * frameWidth();
2689 int h = fontMetrics().height();
2690 QSize sz( f, f );
2691 if ( d->policy > Manual ) {
2692 QSVChildRec *r = d->children.first();
2693 if ( r ) {
2694 QSize cs = r->child->sizeHint();
2695 if ( cs.isValid() )
2696 sz += cs.boundedTo( r->child->maximumSize() );
2697 else
2698 sz += r->child->size();
2699 }
2700 } else {
2701 sz += QSize( d->contentsWidth(), contentsHeight() );
2702 }
2703 if (d->hMode == AlwaysOn)
2704 sz.setWidth(sz.width() + d->hbar->sizeHint().width());
2705 if (d->vMode == AlwaysOn)
2706 sz.setHeight(sz.height() + d->hbar->sizeHint().height());
2707 return sz.expandedTo( QSize(12 * h, 8 * h) )
2708 .boundedTo( QSize(36 * h, 24 * h) );
2709}
2710
2711
2712/*!
2713 \reimp
2714*/
2715QSize QScrollView::minimumSizeHint() const
2716{
2717 int h = fontMetrics().height();
2718 if ( h < 10 )
2719 h = 10;
2720 int f = 2 * frameWidth();
2721 return QSize( (6 * h) + f, (4 * h) + f );
2722}
2723
2724
2725/*!
2726 \reimp
2727
2728 (Implemented to get rid of a compiler warning.)
2729*/
2730void QScrollView::drawContents( QPainter * )
2731{
2732}
2733
2734#ifndef QT_NO_DRAGANDDROP
2735
2736/*!
2737 \internal
2738*/
2739void QScrollView::startDragAutoScroll()
2740{
2741 if ( !d->autoscroll_timer.isActive() ) {
2742 d->autoscroll_time = initialScrollTime;
2743 d->autoscroll_accel = initialScrollAccel;
2744 d->autoscroll_timer.start( d->autoscroll_time );
2745 }
2746}
2747
2748
2749/*!
2750 \internal
2751*/
2752void QScrollView::stopDragAutoScroll()
2753{
2754 d->autoscroll_timer.stop();
2755}
2756
2757
2758/*!
2759 \internal
2760*/
2761void QScrollView::doDragAutoScroll()
2762{
2763 QPoint p = d->viewport->mapFromGlobal( QCursor::pos() );
2764
2765 if ( d->autoscroll_accel-- <= 0 && d->autoscroll_time ) {
2766 d->autoscroll_accel = initialScrollAccel;
2767 d->autoscroll_time--;
2768 d->autoscroll_timer.start( d->autoscroll_time );
2769 }
2770 int l = QMAX( 1, ( initialScrollTime- d->autoscroll_time ) );
2771
2772 int dx = 0, dy = 0;
2773 if ( p.y() < autoscroll_margin ) {
2774 dy = -l;
2775 } else if ( p.y() > visibleHeight() - autoscroll_margin ) {
2776 dy = +l;
2777 }
2778 if ( p.x() < autoscroll_margin ) {
2779 dx = -l;
2780 } else if ( p.x() > visibleWidth() - autoscroll_margin ) {
2781 dx = +l;
2782 }
2783 if ( dx || dy ) {
2784 scrollBy(dx,dy);
2785 } else {
2786 stopDragAutoScroll();
2787 }
2788}
2789
2790
2791/*!
2792 \property QScrollView::dragAutoScroll
2793 \brief whether autoscrolling in drag move events is enabled
2794
2795 If this property is set to TRUE (the default), the QScrollView
2796 automatically scrolls the contents in drag move events if the user
2797 moves the cursor close to a border of the view. Of course this
2798 works only if the viewport accepts drops. Specifying FALSE
2799 disables this autoscroll feature.
2800*/
2801
2802void QScrollView::setDragAutoScroll( bool b )
2803{
2804 d->drag_autoscroll = b;
2805}
2806
2807bool QScrollView::dragAutoScroll() const
2808{
2809 return d->drag_autoscroll;
2810}
2811
2812#endif // QT_NO_DRAGANDDROP
2813
2814/*!\internal
2815 */
2816void QScrollView::setCachedSizeHint( const QSize &sh ) const
2817{
2818 if ( isVisible() && !d->cachedSizeHint.isValid() )
2819 d->cachedSizeHint = sh;
2820}
2821
2822/*!\internal
2823 */
2824void QScrollView::disableSizeHintCaching()
2825{
2826 d->use_cached_size_hint = FALSE;
2827}
2828
2829/*!\internal
2830 */
2831QSize QScrollView::cachedSizeHint() const
2832{
2833 return d->use_cached_size_hint ? d->cachedSizeHint : QSize();
2834}
2835
2836#endif // QT_NO_SCROLLVIEW
Note: See TracBrowser for help on using the repository browser.