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