source: trunk/src/qt3support/widgets/q3scrollview.cpp@ 182

Last change on this file since 182 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 76.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt3Support module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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
60QT_BEGIN_NAMESPACE
61
62using namespace Qt;
63
64static const int coord_limit = 4000;
65static const int autoscroll_margin = 16;
66static const int initialScrollTime = 30;
67static const int initialScrollAccel = 5;
68
69struct QSVChildRec {
70 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);
77 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
89void 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
107class QAbstractScrollAreaWidget : public QWidget
108{
109 Q_OBJECT
110
111public:
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
119class QClipperWidget : public QWidget
120{
121 Q_OBJECT
122
123public:
124 QClipperWidget(QWidget * parent=0, const char * name=0, Qt::WindowFlags f=0)
125 : QWidget (parent,name,f) {}
126};
127
128QT_BEGIN_INCLUDE_NAMESPACE
129#include "q3scrollview.moc"
130QT_END_INCLUDE_NAMESPACE
131
132class Q3ScrollViewData {
133public:
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
165 QSVChildRec* rec(QWidget* w) { return childDict.find(w); }
166 QSVChildRec* ancestorRec(QWidget* w);
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 }
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
228 inline int contentsX() const { return -vx; }
229 inline int contentsY() const { return -vy; }
230 inline int contentsWidth() const { return vwidth; }
231};
232
233inline Q3ScrollViewData::~Q3ScrollViewData()
234{
235 children.setAutoDelete(true);
236}
237
238QSVChildRec* 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
254void 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
281void 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
295bool 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
303void 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
312void 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
321void 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
340void 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
554Q3ScrollView::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*/
591Q3ScrollView::~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*/
631void Q3ScrollView::hbarIsPressed()
632{
633 d->hbarPressed = true;
634 emit(horizontalSliderPressed());
635}
636
637void 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*/
646bool Q3ScrollView::isHorizontalSliderPressed()
647{
648 return d->hbarPressed;
649}
650
651void Q3ScrollView::vbarIsPressed()
652{
653 d->vbarPressed = true;
654 emit(verticalSliderPressed());
655}
656
657void 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*/
666bool Q3ScrollView::isVerticalSliderPressed()
667{
668 return d->vbarPressed;
669}
670
671/*!
672 \reimp
673*/
674void Q3ScrollView::styleChange(QStyle& old)
675{
676 QWidget::styleChange(old);
677 updateScrollBars();
678 d->cachedSizeHint = QSize();
679}
680
681/*!
682 \reimp
683*/
684void Q3ScrollView::fontChange(const QFont &old)
685{
686 QWidget::fontChange(old);
687 updateScrollBars();
688 d->cachedSizeHint = QSize();
689}
690
691void Q3ScrollView::hslide(int pos)
692{
693 if (!d->signal_choke) {
694 moveContents(-pos, -d->contentsY());
695 QApplication::syncX();
696 }
697}
698
699void 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*/
718void 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*/
735void 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
756QSize 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*/
816void 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 QPoint tlw_br = QPoint(tlw->width(), tlw->height()),
874 my_br = qt_mac_posInWindow(this) + QPoint(w, h);
875 if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3)
876 mac_need_scroll = true;
877 }
878 if(mac_need_scroll) {
879 WindowAttributes attr;
880 GetWindowAttributes((WindowPtr)handle(), &attr);
881 mac_need_scroll = (attr & kWindowResizableAttribute);
882 }
883 if(mac_need_scroll) {
884 showc = true;
885 if(d->vMode == Auto)
886 showv = true;
887 if(d->hMode == Auto)
888 showh = true;
889 }
890#endif
891
892 // Given other scroll bar will be shown, NOW do we need one?
893 if (showh && h-vsbExt-tmarg-bmarg < contentsHeight()) {
894 needv=true;
895 if (d->vMode == Auto)
896 showv=true;
897 }
898 if (showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth()) {
899 needh=true;
900 if (d->hMode == Auto)
901 showh=true;
902 }
903 } else {
904 // Scrollbars not needed, only show scroll bar that are always on.
905 needh = needv = false;
906 showh = d->hMode == AlwaysOn;
907 showv = d->vMode == AlwaysOn;
908 }
909
910 bool sc = d->signal_choke;
911 d->signal_choke=true;
912
913 // Hide unneeded scroll bar, calculate viewport size
914 if (showh) {
915 porth=h-hsbExt-tmarg-bmarg;
916 } else {
917 if (!needh)
918 d->hbar->setValue(0);
919 d->hbar->hide();
920 porth=h-tmarg-bmarg;
921 }
922 if (showv) {
923 portw=w-vsbExt-lmarg-rmarg;
924 } else {
925 if (!needv)
926 d->vbar->setValue(0);
927 d->vbar->hide();
928 portw=w-lmarg-rmarg;
929 }
930
931 // Configure scroll bars that we will show
932 if (needv) {
933 d->vbar->setRange(0, contentsHeight()-porth);
934 d->vbar->setSteps(Q3ScrollView::d->vbar->lineStep(), porth);
935 } else {
936 d->vbar->setRange(0, 0);
937 }
938 if (needh) {
939 d->hbar->setRange(0, QMAX(0, d->contentsWidth()-portw));
940 d->hbar->setSteps(Q3ScrollView::d->hbar->lineStep(), portw);
941 } else {
942 d->hbar->setRange(0, 0);
943 }
944
945 // Position the scroll bars, viewport and corner widget.
946 int bottom;
947 bool reverse = QApplication::reverseLayout();
948 int xoffset = (reverse && (showv || cornerWidget())) ? vsbExt : 0;
949 int xpos = reverse ? 0 : w - vsbExt;
950 bool frameContentsOnly =
951 style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
952
953 if(! frameContentsOnly) {
954 if (reverse)
955 xpos += fw;
956 else
957 xpos -= fw;
958 }
959 if (showh) {
960 int right = (showc || showv || cornerWidget()) ? w-vsbExt : w;
961 if (! frameContentsOnly)
962 setHBarGeometry(*d->hbar, fw + xoffset, h-hsbExt-fw,
963 right-fw-fw, hsbExt);
964 else
965 setHBarGeometry(*d->hbar, 0 + xoffset, h-hsbExt, right,
966 hsbExt);
967 bottom=h-hsbExt;
968 } else {
969 bottom=h;
970 }
971 if (showv) {
972 clipper()->setGeometry(lmarg + xoffset, tmarg,
973 w-vsbExt-lmarg-rmarg,
974 bottom-tmarg-bmarg);
975 d->viewportResized(w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg);
976 if (! frameContentsOnly)
977 changeFrameRect(QRect(0, 0, w, h));
978 else
979 changeFrameRect(QRect(xoffset, 0, w-vsbExt, bottom));
980 if (showc || cornerWidget()) {
981 if (! frameContentsOnly)
982 setVBarGeometry(*d->vbar, xpos,
983 fw, vsbExt,
984 h-hsbExt-fw-fw);
985 else
986 setVBarGeometry(*d->vbar, xpos, 0,
987 vsbExt,
988 h-hsbExt);
989 }
990 else {
991 if (! frameContentsOnly)
992 setVBarGeometry(*d->vbar, xpos,
993 fw, vsbExt,
994 bottom-fw-fw);
995 else
996 setVBarGeometry(*d->vbar, xpos, 0,
997 vsbExt, bottom);
998 }
999 } else {
1000 if (! frameContentsOnly)
1001 changeFrameRect(QRect(0, 0, w, h));
1002 else
1003 changeFrameRect(QRect(0, 0, w, bottom));
1004 clipper()->setGeometry(lmarg, tmarg,
1005 w-lmarg-rmarg, bottom-tmarg-bmarg);
1006 d->viewportResized(w-lmarg-rmarg, bottom-tmarg-bmarg);
1007 }
1008
1009 QWidget *corner = d->corner;
1010 if (d->corner) {
1011 if (! frameContentsOnly)
1012 corner->setGeometry(xpos,
1013 h-hsbExt-fw,
1014 vsbExt,
1015 hsbExt);
1016 else
1017 corner->setGeometry(xpos,
1018 h-hsbExt,
1019 vsbExt,
1020 hsbExt);
1021 }
1022
1023 d->signal_choke=sc;
1024
1025 if (d->contentsX()+visibleWidth() > d->contentsWidth()) {
1026 int x;
1027#if 0
1028 if (reverse)
1029 x =QMIN(0,d->contentsWidth()-visibleWidth());
1030 else
1031#endif
1032 x =QMAX(0,d->contentsWidth()-visibleWidth());
1033 d->hbar->setValue(x);
1034 // Do it even if it is recursive
1035 moveContents(-x, -d->contentsY());
1036 }
1037 if (d->contentsY()+visibleHeight() > contentsHeight()) {
1038 int y=QMAX(0,contentsHeight()-visibleHeight());
1039 d->vbar->setValue(y);
1040 // Do it even if it is recursive
1041 moveContents(-d->contentsX(), -y);
1042 }
1043
1044 // Finally, show the scroll bars
1045 if (showh && (d->hbar->isHidden() || !d->hbar->isVisible()))
1046 d->hbar->show();
1047 if (showv && (d->vbar->isHidden() || !d->vbar->isVisible()))
1048 d->vbar->show();
1049
1050 d->signal_choke=true;
1051 d->vbar->setValue(d->contentsY());
1052 d->hbar->setValue(d->contentsX());
1053 d->signal_choke=false;
1054
1055 QSize newVisibleSize(visibleWidth(), visibleHeight());
1056 if (d->clipped_viewport && oldVisibleSize != newVisibleSize) {
1057 QResizeEvent e(newVisibleSize, oldVisibleSize);
1058 viewportResizeEvent(&e);
1059 }
1060}
1061
1062
1063/*!
1064 \reimp
1065*/
1066void Q3ScrollView::setVisible(bool visible)
1067{
1068 if (visible && !isVisible()) {
1069 QWidget::setVisible(visible);
1070 updateScrollBars();
1071 d->hideOrShowAll(this);
1072 } else {
1073 QWidget::setVisible(visible);
1074 }
1075}
1076
1077/*!
1078 \internal
1079 */
1080void Q3ScrollView::resize(int w, int h)
1081{
1082 QWidget::resize(w, h);
1083}
1084
1085/*!
1086 \internal
1087*/
1088void Q3ScrollView::resize(const QSize& s)
1089{
1090 resize(s.width(), s.height());
1091}
1092
1093/*!
1094 \reimp
1095*/
1096void Q3ScrollView::resizeEvent(QResizeEvent* event)
1097{
1098 Q3Frame::resizeEvent(event);
1099
1100#if 0
1101 if (QApplication::reverseLayout()) {
1102 d->fake_scroll = true;
1103 scrollBy(-event->size().width() + event->oldSize().width(), 0);
1104 d->fake_scroll = false;
1105 }
1106#endif
1107
1108 bool inresize = d->inresize;
1109 d->inresize = true;
1110 updateScrollBars();
1111 d->inresize = inresize;
1112 d->scrollbar_timer.start(0, true);
1113
1114 d->hideOrShowAll(this);
1115}
1116
1117
1118
1119/*!
1120 \reimp
1121*/
1122void Q3ScrollView::mousePressEvent(QMouseEvent * e)
1123{
1124 e->ignore();
1125}
1126
1127/*!
1128 \reimp
1129*/
1130void Q3ScrollView::mouseReleaseEvent(QMouseEvent *e)
1131{
1132 e->ignore();
1133}
1134
1135
1136/*!
1137 \reimp
1138*/
1139void Q3ScrollView::mouseDoubleClickEvent(QMouseEvent *e)
1140{
1141 e->ignore();
1142}
1143
1144/*!
1145 \reimp
1146*/
1147void Q3ScrollView::mouseMoveEvent(QMouseEvent *e)
1148{
1149 e->ignore();
1150}
1151
1152/*!
1153 \reimp
1154*/
1155#ifndef QT_NO_WHEELEVENT
1156void Q3ScrollView::wheelEvent(QWheelEvent *e)
1157{
1158 QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()),
1159 e->globalPos(), e->delta(), e->state());
1160 viewportWheelEvent(&ce);
1161 if (!ce.isAccepted()) {
1162 if (e->orientation() == Horizontal && horizontalScrollBar())
1163 horizontalScrollBar()->event(e);
1164 else if (e->orientation() == Vertical && verticalScrollBar())
1165 verticalScrollBar()->event(e);
1166 } else {
1167 e->accept();
1168 }
1169}
1170#endif
1171
1172/*!
1173 \reimp
1174*/
1175void Q3ScrollView::contextMenuEvent(QContextMenuEvent *e)
1176{
1177 if (e->reason() != QContextMenuEvent::Keyboard) {
1178 e->ignore();
1179 return;
1180 }
1181
1182 QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()),
1183 e->globalPos(), e->state());
1184 viewportContextMenuEvent(&ce);
1185 if (ce.isAccepted())
1186 e->accept();
1187 else
1188 e->ignore();
1189}
1190
1191Q3ScrollView::ScrollBarMode Q3ScrollView::vScrollBarMode() const
1192{
1193 return d->vMode;
1194}
1195
1196
1197/*!
1198 \enum Q3ScrollView::ScrollBarMode
1199
1200 This enum type describes the various modes of Q3ScrollView's scroll
1201 bars.
1202
1203 \value Auto Q3ScrollView shows a scroll bar when the content is
1204 too large to fit and not otherwise. This is the default.
1205
1206 \value AlwaysOff Q3ScrollView never shows a scroll bar.
1207
1208 \value AlwaysOn Q3ScrollView always shows a scroll bar.
1209
1210 (The modes for the horizontal and vertical scroll bars are
1211 independent.)
1212*/
1213
1214
1215/*!
1216 \property Q3ScrollView::vScrollBarMode
1217 \brief the mode for the vertical scroll bar
1218
1219 The default mode is Q3ScrollView::Auto.
1220
1221 \sa hScrollBarMode
1222*/
1223void Q3ScrollView::setVScrollBarMode(ScrollBarMode mode)
1224{
1225 if (d->vMode != mode) {
1226 d->vMode = mode;
1227 updateScrollBars();
1228 }
1229}
1230
1231
1232/*!
1233 \property Q3ScrollView::hScrollBarMode
1234 \brief the mode for the horizontal scroll bar
1235
1236 The default mode is Q3ScrollView::Auto.
1237
1238 \sa vScrollBarMode
1239*/
1240Q3ScrollView::ScrollBarMode Q3ScrollView::hScrollBarMode() const
1241{
1242 return d->hMode;
1243}
1244
1245void Q3ScrollView::setHScrollBarMode(ScrollBarMode mode)
1246{
1247 if (d->hMode != mode) {
1248 d->hMode = mode;
1249 updateScrollBars();
1250 }
1251}
1252
1253
1254/*!
1255 Returns the widget in the corner between the two scroll bars.
1256
1257 By default, no corner widget is present.
1258*/
1259QWidget* Q3ScrollView::cornerWidget() const
1260{
1261 return d->corner;
1262}
1263
1264/*!
1265 Sets the widget in the \a corner between the two scroll bars.
1266
1267 You will probably also want to set at least one of the scroll bar
1268 modes to \c AlwaysOn.
1269
1270 Passing 0 shows no widget in the corner.
1271
1272 Any previous \a corner widget is hidden.
1273
1274 You may call setCornerWidget() with the same widget at different
1275 times.
1276
1277 All widgets set here will be deleted by the Q3ScrollView when it is
1278 destroyed unless you separately reparent the widget after setting
1279 some other corner widget (or 0).
1280
1281 Any \e newly set widget should have no current parent.
1282
1283 By default, no corner widget is present.
1284
1285 \sa setVScrollBarMode(), setHScrollBarMode()
1286*/
1287void Q3ScrollView::setCornerWidget(QWidget* corner)
1288{
1289 QWidget* oldcorner = d->corner;
1290 if (oldcorner != corner) {
1291 if (oldcorner) oldcorner->hide();
1292 d->corner = corner;
1293 if (corner) corner->setParent(this);
1294 updateScrollBars();
1295 if (corner) corner->show();
1296 }
1297}
1298
1299
1300void Q3ScrollView::setResizePolicy(ResizePolicy r)
1301{
1302 d->policy = r;
1303}
1304
1305/*!
1306 \property Q3ScrollView::resizePolicy
1307 \brief the resize policy
1308
1309 The default is \c Default.
1310
1311 \sa ResizePolicy
1312*/
1313Q3ScrollView::ResizePolicy Q3ScrollView::resizePolicy() const
1314{
1315 return d->policy;
1316}
1317
1318/*!
1319 \internal
1320*/
1321void Q3ScrollView::setEnabled(bool enable)
1322{
1323 Q3Frame::setEnabled(enable);
1324}
1325
1326/*!
1327 Removes the \a child widget from the scrolled area. Note that this
1328 happens automatically if the \a child is deleted.
1329*/
1330void Q3ScrollView::removeChild(QWidget* child)
1331{
1332 if (!d || !child) // First check in case we are destructing
1333 return;
1334
1335 QSVChildRec *r = d->rec(child);
1336 if (r) d->deleteChildRec(r);
1337}
1338
1339/*!
1340 \internal
1341*/
1342void Q3ScrollView::removeChild(QObject* child)
1343{
1344 Q3Frame::removeChild(child);
1345}
1346
1347/*!
1348 Inserts the widget, \a child, into the scrolled area positioned at
1349 (\a x, \a y). The position defaults to (0, 0). If the child is
1350 already in the view, it is just moved.
1351
1352 You may want to call enableClipper(true) if you add a large number
1353 of widgets.
1354*/
1355void Q3ScrollView::addChild(QWidget* child, int x, int y)
1356{
1357 if (!child) {
1358#if defined(QT_CHECK_NULL)
1359 qWarning("Q3ScrollView::addChild(): Cannot add null child");
1360#endif
1361 return;
1362 }
1363 child->polish();
1364 child->setBackgroundOrigin(WidgetOrigin);
1365
1366 if (child->parentWidget() == viewport()) {
1367 // May already be there
1368 QSVChildRec *r = d->rec(child);
1369 if (r) {
1370 r->moveTo(this,x,y,d->clipped_viewport);
1371 if (d->policy > Manual) {
1372 d->autoResizeHint(this);
1373 d->autoResize(this); // #### better to just deal with this one widget!
1374 }
1375 return;
1376 }
1377 }
1378
1379 if (d->children.isEmpty() && d->policy != Manual) {
1380 if (d->policy == Default)
1381 setResizePolicy(AutoOne);
1382 child->installEventFilter(this);
1383 } else if (d->policy == AutoOne) {
1384 child->removeEventFilter(this); //#### ?????
1385 setResizePolicy(Manual);
1386 }
1387 if (child->parentWidget() != viewport()) {
1388 child->reparent(viewport(), 0, QPoint(0,0), false);
1389 }
1390 d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport);
1391
1392 if (d->policy > Manual) {
1393 d->autoResizeHint(this);
1394 d->autoResize(this); // #### better to just deal with this one widget!
1395 }
1396}
1397
1398/*!
1399 Repositions the \a child widget to (\a x, \a y). This function is
1400 the same as addChild().
1401*/
1402void Q3ScrollView::moveChild(QWidget* child, int x, int y)
1403{
1404 addChild(child,x,y);
1405}
1406
1407/*!
1408 Returns the X position of the given \a child widget. Use this
1409 rather than QWidget::x() for widgets added to the view.
1410
1411 This function returns 0 if \a child has not been added to the view.
1412*/
1413int Q3ScrollView::childX(QWidget* child)
1414{
1415 QSVChildRec *r = d->rec(child);
1416 return r ? r->x : 0;
1417}
1418
1419/*!
1420 Returns the Y position of the given \a child widget. Use this
1421 rather than QWidget::y() for widgets added to the view.
1422
1423 This function returns 0 if \a child has not been added to the view.
1424*/
1425int Q3ScrollView::childY(QWidget* child)
1426{
1427 QSVChildRec *r = d->rec(child);
1428 return r ? r->y : 0;
1429}
1430
1431/*! \fn bool Q3ScrollView::childIsVisible(QWidget*)
1432 \obsolete
1433
1434 Returns true if \a child is visible. This is equivalent
1435 to child->isVisible().
1436*/
1437
1438/*! \fn void Q3ScrollView::showChild(QWidget* child, bool y)
1439 \obsolete
1440
1441 Sets the visibility of \a child. Equivalent to
1442 QWidget::show() or QWidget::hide().
1443*/
1444
1445/*!
1446 This event filter ensures the scroll bars are updated when a
1447 single contents widget is resized, shown, hidden or destroyed; it
1448 passes mouse events to the Q3ScrollView. The event is in \a e and
1449 the object is in \a obj.
1450*/
1451
1452bool Q3ScrollView::eventFilter(QObject *obj, QEvent *e)
1453{
1454 bool disabled = !(qobject_cast<QWidget*>(obj)->isEnabled());
1455 if (!d)
1456 return false; // we are destructing
1457 if (obj == d->viewport || obj == d->clipped_viewport) {
1458 switch (e->type()) {
1459 /* Forward many events to viewport...() functions */
1460 case QEvent::Paint:
1461 viewportPaintEvent((QPaintEvent*)e);
1462 break;
1463 case QEvent::Resize:
1464 if (!d->clipped_viewport)
1465 viewportResizeEvent((QResizeEvent *)e);
1466 break;
1467 case QEvent::MouseButtonPress:
1468 if (disabled)
1469 return false;
1470 viewportMousePressEvent((QMouseEvent*)e);
1471 if (((QMouseEvent*)e)->isAccepted())
1472 return true;
1473 break;
1474 case QEvent::MouseButtonRelease:
1475 if (disabled)
1476 return false;
1477 viewportMouseReleaseEvent((QMouseEvent*)e);
1478 if (((QMouseEvent*)e)->isAccepted())
1479 return true;
1480 break;
1481 case QEvent::MouseButtonDblClick:
1482 if (disabled)
1483 return false;
1484 viewportMouseDoubleClickEvent((QMouseEvent*)e);
1485 if (((QMouseEvent*)e)->isAccepted())
1486 return true;
1487 break;
1488 case QEvent::MouseMove:
1489 if (disabled)
1490 return false;
1491 viewportMouseMoveEvent((QMouseEvent*)e);
1492 if (((QMouseEvent*)e)->isAccepted())
1493 return true;
1494 break;
1495#ifndef QT_NO_DRAGANDDROP
1496 case QEvent::DragEnter:
1497 if (disabled)
1498 return false;
1499 viewportDragEnterEvent((QDragEnterEvent*)e);
1500 break;
1501 case QEvent::DragMove: {
1502 if (disabled)
1503 return false;
1504 if (d->drag_autoscroll) {
1505 QPoint vp = ((QDragMoveEvent*) e)->pos();
1506 QRect inside_margin(autoscroll_margin, autoscroll_margin,
1507 visibleWidth() - autoscroll_margin * 2,
1508 visibleHeight() - autoscroll_margin * 2);
1509 if (!inside_margin.contains(vp)) {
1510 startDragAutoScroll();
1511 // Keep sending move events
1512 ((QDragMoveEvent*)e)->accept(QRect(0,0,0,0));
1513 }
1514 }
1515 viewportDragMoveEvent((QDragMoveEvent*)e);
1516 } break;
1517 case QEvent::DragLeave:
1518 if (disabled)
1519 return false;
1520 stopDragAutoScroll();
1521 viewportDragLeaveEvent((QDragLeaveEvent*)e);
1522 break;
1523 case QEvent::Drop:
1524 if (disabled)
1525 return false;
1526 stopDragAutoScroll();
1527 viewportDropEvent((QDropEvent*)e);
1528 break;
1529#endif // QT_NO_DRAGANDDROP
1530#ifndef QT_NO_WHEELEVENT
1531 case QEvent::Wheel:
1532 if (disabled)
1533 return false;
1534 break;
1535#endif
1536 case QEvent::ContextMenu:
1537 if (disabled)
1538 return false;
1539 viewportContextMenuEvent((QContextMenuEvent*)e);
1540 if (((QContextMenuEvent*)e)->isAccepted())
1541 return true;
1542 break;
1543 case QEvent::ChildRemoved:
1544 removeChild((QWidget*)((QChildEvent*)e)->child());
1545 break;
1546 case QEvent::LayoutHint:
1547 d->autoResizeHint(this);
1548 break;
1549 default:
1550 break;
1551 }
1552 } else if (d && d->rec((QWidget*)obj)) { // must be a child
1553 if (e->type() == QEvent::Resize)
1554 d->autoResize(this);
1555 else if (e->type() == QEvent::Move)
1556 d->autoMove(this);
1557 }
1558 return Q3Frame::eventFilter(obj, e); // always continue with standard event processing
1559}
1560
1561/*!
1562 This event handler is called whenever the Q3ScrollView receives a
1563 mousePressEvent(): the press position in \a e is translated to be a point
1564 on the contents.
1565*/
1566void Q3ScrollView::contentsMousePressEvent(QMouseEvent* e)
1567{
1568 e->ignore();
1569}
1570
1571/*!
1572 This event handler is called whenever the Q3ScrollView receives a
1573 mouseReleaseEvent(): the release position in \a e is translated to be a
1574 point on the contents.
1575*/
1576void Q3ScrollView::contentsMouseReleaseEvent(QMouseEvent* e)
1577{
1578 e->ignore();
1579}
1580
1581/*!
1582 This event handler is called whenever the Q3ScrollView receives a
1583 mouseDoubleClickEvent(): the click position in \a e is translated to be a
1584 point on the contents.
1585
1586 The default implementation generates a normal mouse press event.
1587*/
1588void Q3ScrollView::contentsMouseDoubleClickEvent(QMouseEvent* e)
1589{
1590 contentsMousePressEvent(e); // try mouse press event
1591}
1592
1593/*!
1594 This event handler is called whenever the Q3ScrollView receives a
1595 mouseMoveEvent(): the mouse position in \a e is translated to be a point
1596 on the contents.
1597*/
1598void Q3ScrollView::contentsMouseMoveEvent(QMouseEvent* e)
1599{
1600 e->ignore();
1601}
1602
1603#ifndef QT_NO_DRAGANDDROP
1604
1605/*!
1606 This event handler is called whenever the Q3ScrollView receives a
1607 dragEnterEvent(): the drag position is translated to be a point
1608 on the contents.
1609
1610 The default implementation does nothing. The \a event parameter is
1611 ignored.
1612*/
1613void Q3ScrollView::contentsDragEnterEvent(QDragEnterEvent * /* event */)
1614{
1615}
1616
1617/*!
1618 This event handler is called whenever the Q3ScrollView receives a
1619 dragMoveEvent(): the drag position is translated to be a point on
1620 the contents.
1621
1622 The default implementation does nothing. The \a event parameter is
1623 ignored.
1624*/
1625void Q3ScrollView::contentsDragMoveEvent(QDragMoveEvent * /* event */)
1626{
1627}
1628
1629/*!
1630 This event handler is called whenever the Q3ScrollView receives a
1631 dragLeaveEvent(): the drag position is translated to be a point
1632 on the contents.
1633
1634 The default implementation does nothing. The \a event parameter is
1635 ignored.
1636*/
1637void Q3ScrollView::contentsDragLeaveEvent(QDragLeaveEvent * /* event */)
1638{
1639}
1640
1641/*!
1642 This event handler is called whenever the Q3ScrollView receives a
1643 dropEvent(): the drop position is translated to be a point on the
1644 contents.
1645
1646 The default implementation does nothing. The \a event parameter is
1647 ignored.
1648*/
1649
1650void Q3ScrollView::contentsDropEvent(QDropEvent * /* event */)
1651{
1652}
1653
1654#endif // QT_NO_DRAGANDDROP
1655
1656/*!
1657 This event handler is called whenever the Q3ScrollView receives a
1658 wheelEvent() in \a{e}: the mouse position is translated to be a
1659 point on the contents.
1660*/
1661#ifndef QT_NO_WHEELEVENT
1662void Q3ScrollView::contentsWheelEvent(QWheelEvent * e)
1663{
1664 e->ignore();
1665}
1666#endif
1667/*!
1668 This event handler is called whenever the Q3ScrollView receives a
1669 contextMenuEvent() in \a{e}: the mouse position is translated to
1670 be a point on the contents.
1671*/
1672void Q3ScrollView::contentsContextMenuEvent(QContextMenuEvent *e)
1673{
1674 e->ignore();
1675}
1676
1677/*!
1678 This is a low-level painting routine that draws the viewport
1679 contents. Reimplement this if drawContents() is too high-level
1680 (for example, if you don't want to open a QPainter on the
1681 viewport). The paint event is passed in \a pe.
1682*/
1683void Q3ScrollView::viewportPaintEvent(QPaintEvent* pe)
1684{
1685 QWidget* vp = viewport();
1686
1687 QPainter p(vp);
1688 QRect r = pe->rect();
1689
1690 if (d->clipped_viewport) {
1691 QRect rr(
1692 -d->clipped_viewport->x(), -d->clipped_viewport->y(),
1693 d->viewport->width(), d->viewport->height()
1694 );
1695 r &= rr;
1696 if (r.isValid()) {
1697 int ex = r.x() + d->clipped_viewport->x() + d->contentsX();
1698 int ey = r.y() + d->clipped_viewport->y() + d->contentsY();
1699 int ew = r.width();
1700 int eh = r.height();
1701 drawContentsOffset(&p,
1702 d->contentsX()+d->clipped_viewport->x(),
1703 d->contentsY()+d->clipped_viewport->y(),
1704 ex, ey, ew, eh);
1705 }
1706 } else {
1707 r &= d->viewport->rect();
1708 int ex = r.x() + d->contentsX();
1709 int ey = r.y() + d->contentsY();
1710 int ew = r.width();
1711 int eh = r.height();
1712 drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh);
1713 }
1714}
1715
1716
1717/*!
1718 To provide simple processing of events on the contents, this
1719 function receives all resize events sent to the viewport.
1720
1721 The default implementation does nothing. The \a event parameter is
1722 ignored.
1723
1724 \sa QWidget::resizeEvent()
1725*/
1726void Q3ScrollView::viewportResizeEvent(QResizeEvent * /* event */)
1727{
1728}
1729
1730/*! \internal
1731
1732 To provide simple processing of events on the contents, this
1733 function receives all mouse press events sent to the viewport,
1734 translates the event and calls contentsMousePressEvent().
1735
1736 \sa contentsMousePressEvent(), QWidget::mousePressEvent()
1737*/
1738void Q3ScrollView::viewportMousePressEvent(QMouseEvent* e)
1739{
1740 QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1741 e->globalPos(), e->button(), e->state());
1742 contentsMousePressEvent(&ce);
1743 if (!ce.isAccepted())
1744 e->ignore();
1745}
1746
1747/*!\internal
1748
1749 To provide simple processing of events on the contents, this function
1750 receives all mouse release events sent to the viewport, translates
1751 the event and calls contentsMouseReleaseEvent().
1752
1753 \sa QWidget::mouseReleaseEvent()
1754*/
1755void Q3ScrollView::viewportMouseReleaseEvent(QMouseEvent* e)
1756{
1757 QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1758 e->globalPos(), e->button(), e->state());
1759 contentsMouseReleaseEvent(&ce);
1760 if (!ce.isAccepted())
1761 e->ignore();
1762}
1763
1764/*!\internal
1765
1766 To provide simple processing of events on the contents, this function
1767 receives all mouse double click events sent to the viewport,
1768 translates the event and calls contentsMouseDoubleClickEvent().
1769
1770 \sa QWidget::mouseDoubleClickEvent()
1771*/
1772void Q3ScrollView::viewportMouseDoubleClickEvent(QMouseEvent* e)
1773{
1774 QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1775 e->globalPos(), e->button(), e->state());
1776 contentsMouseDoubleClickEvent(&ce);
1777 if (!ce.isAccepted())
1778 e->ignore();
1779}
1780
1781/*!\internal
1782
1783 To provide simple processing of events on the contents, this function
1784 receives all mouse move events sent to the viewport, translates the
1785 event and calls contentsMouseMoveEvent().
1786
1787 \sa QWidget::mouseMoveEvent()
1788*/
1789void Q3ScrollView::viewportMouseMoveEvent(QMouseEvent* e)
1790{
1791 QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1792 e->globalPos(), e->button(), e->state());
1793 contentsMouseMoveEvent(&ce);
1794 if (!ce.isAccepted())
1795 e->ignore();
1796}
1797
1798#ifndef QT_NO_DRAGANDDROP
1799
1800/*!\internal
1801
1802 To provide simple processing of events on the contents, this function
1803 receives all drag enter events sent to the viewport, translates the
1804 event and calls contentsDragEnterEvent().
1805
1806 \sa QWidget::dragEnterEvent()
1807*/
1808void Q3ScrollView::viewportDragEnterEvent(QDragEnterEvent* e)
1809{
1810 e->setPoint(viewportToContents(e->pos()));
1811 contentsDragEnterEvent(e);
1812 e->setPoint(contentsToViewport(e->pos()));
1813}
1814
1815/*!\internal
1816
1817 To provide simple processing of events on the contents, this function
1818 receives all drag move events sent to the viewport, translates the
1819 event and calls contentsDragMoveEvent().
1820
1821 \sa QWidget::dragMoveEvent()
1822*/
1823void Q3ScrollView::viewportDragMoveEvent(QDragMoveEvent* e)
1824{
1825 e->setPoint(viewportToContents(e->pos()));
1826 contentsDragMoveEvent(e);
1827 e->setPoint(contentsToViewport(e->pos()));
1828}
1829
1830/*!\internal
1831
1832 To provide simple processing of events on the contents, this function
1833 receives all drag leave events sent to the viewport and calls
1834 contentsDragLeaveEvent().
1835
1836 \sa QWidget::dragLeaveEvent()
1837*/
1838void Q3ScrollView::viewportDragLeaveEvent(QDragLeaveEvent* e)
1839{
1840 contentsDragLeaveEvent(e);
1841}
1842
1843/*!\internal
1844
1845 To provide simple processing of events on the contents, this function
1846 receives all drop events sent to the viewport, translates the event
1847 and calls contentsDropEvent().
1848
1849 \sa QWidget::dropEvent()
1850*/
1851void Q3ScrollView::viewportDropEvent(QDropEvent* e)
1852{
1853 e->setPoint(viewportToContents(e->pos()));
1854 contentsDropEvent(e);
1855 e->setPoint(contentsToViewport(e->pos()));
1856}
1857
1858#endif // QT_NO_DRAGANDDROP
1859
1860/*!\internal
1861
1862 To provide simple processing of events on the contents, this function
1863 receives all wheel events sent to the viewport, translates the
1864 event and calls contentsWheelEvent().
1865
1866 \sa QWidget::wheelEvent()
1867*/
1868#ifndef QT_NO_WHEELEVENT
1869void Q3ScrollView::viewportWheelEvent(QWheelEvent* e)
1870{
1871 /*
1872 Different than standard mouse events, because wheel events might
1873 be sent to the focus widget if the widget-under-mouse doesn't want
1874 the event itself.
1875 */
1876 QWheelEvent ce(viewportToContents(e->pos()),
1877 e->globalPos(), e->delta(), e->state());
1878 contentsWheelEvent(&ce);
1879 if (ce.isAccepted())
1880 e->accept();
1881 else
1882 e->ignore();
1883}
1884#endif
1885
1886/*! \internal
1887
1888 To provide simple processing of events on the contents, this function
1889 receives all context menu events sent to the viewport, translates the
1890 event and calls contentsContextMenuEvent().
1891*/
1892void Q3ScrollView::viewportContextMenuEvent(QContextMenuEvent *e)
1893{
1894 QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state());
1895 contentsContextMenuEvent(&ce);
1896 if (ce.isAccepted())
1897 e->accept();
1898 else
1899 e->ignore();
1900}
1901
1902/*!
1903 Returns the component horizontal scroll bar. It is made available
1904 to allow accelerators, autoscrolling, etc.
1905
1906 It should not be used for other purposes.
1907
1908 This function never returns 0.
1909*/
1910QScrollBar* Q3ScrollView::horizontalScrollBar() const
1911{
1912 return d->hbar;
1913}
1914
1915/*!
1916 Returns the component vertical scroll bar. It is made available to
1917 allow accelerators, autoscrolling, etc.
1918
1919 It should not be used for other purposes.
1920
1921 This function never returns 0.
1922*/
1923QScrollBar* Q3ScrollView::verticalScrollBar() const {
1924 return d->vbar;
1925}
1926
1927
1928/*!
1929 Scrolls the content so that the point (\a x, \a y) is visible with at
1930 least 50-pixel margins (if possible, otherwise centered).
1931*/
1932void Q3ScrollView::ensureVisible(int x, int y)
1933{
1934 ensureVisible(x, y, 50, 50);
1935}
1936
1937/*!
1938 \overload
1939
1940 Scrolls the content so that the point (\a x, \a y) is visible with at
1941 least the \a xmargin and \a ymargin margins (if possible,
1942 otherwise centered).
1943*/
1944void Q3ScrollView::ensureVisible(int x, int y, int xmargin, int ymargin)
1945{
1946 int pw=visibleWidth();
1947 int ph=visibleHeight();
1948
1949 int cx=-d->contentsX();
1950 int cy=-d->contentsY();
1951 int cw=d->contentsWidth();
1952 int ch=contentsHeight();
1953
1954 if (pw < xmargin*2)
1955 xmargin=pw/2;
1956 if (ph < ymargin*2)
1957 ymargin=ph/2;
1958
1959 if (cw <= pw) {
1960 xmargin=0;
1961 cx=0;
1962 }
1963 if (ch <= ph) {
1964 ymargin=0;
1965 cy=0;
1966 }
1967
1968 if (x < -cx+xmargin)
1969 cx = -x+xmargin;
1970 else if (x >= -cx+pw-xmargin)
1971 cx = -x+pw-xmargin;
1972
1973 if (y < -cy+ymargin)
1974 cy = -y+ymargin;
1975 else if (y >= -cy+ph-ymargin)
1976 cy = -y+ph-ymargin;
1977
1978 if (cx > 0)
1979 cx=0;
1980 else if (cx < pw-cw && cw>pw)
1981 cx=pw-cw;
1982
1983 if (cy > 0)
1984 cy=0;
1985 else if (cy < ph-ch && ch>ph)
1986 cy=ph-ch;
1987
1988 setContentsPos(-cx, -cy);
1989}
1990
1991/*!
1992 Scrolls the content so that the point (\a x, \a y) is in the top-left
1993 corner.
1994*/
1995void Q3ScrollView::setContentsPos(int x, int y)
1996{
1997#if 0
1998 // bounds checking...
1999 if (QApplication::reverseLayout())
2000 if (x > d->contentsWidth() - visibleWidth()) x = d->contentsWidth() - visibleWidth();
2001 else
2002#endif
2003 if (x < 0) x = 0;
2004 if (y < 0) y = 0;
2005 // Choke signal handling while we update BOTH sliders.
2006 d->signal_choke=true;
2007 moveContents(-x, -y);
2008 d->vbar->setValue(y);
2009 d->hbar->setValue(x);
2010 d->signal_choke=false;
2011}
2012
2013/*!
2014 Scrolls the content by \a dx to the left and \a dy upwards.
2015*/
2016void Q3ScrollView::scrollBy(int dx, int dy)
2017{
2018 setContentsPos(QMAX(d->contentsX()+dx, 0), QMAX(d->contentsY()+dy, 0));
2019}
2020
2021/*!
2022 Scrolls the content so that the point (\a x, \a y) is in the center
2023 of visible area.
2024*/
2025void Q3ScrollView::center(int x, int y)
2026{
2027 ensureVisible(x, y, 32000, 32000);
2028}
2029
2030/*!
2031 \overload
2032
2033 Scrolls the content so that the point (\a x, \a y) is visible with
2034 the \a xmargin and \a ymargin margins (as fractions of visible
2035 the area).
2036
2037 For example:
2038 \list
2039 \i Margin 0.0 allows (x, y) to be on the edge of the visible area.
2040 \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area.
2041 \i Margin 1.0 ensures that (x, y) is in the center of the the visible area.
2042 \endlist
2043*/
2044void Q3ScrollView::center(int x, int y, float xmargin, float ymargin)
2045{
2046 int pw=visibleWidth();
2047 int ph=visibleHeight();
2048 ensureVisible(x, y, int(xmargin/2.0*pw+0.5), int(ymargin/2.0*ph+0.5));
2049}
2050
2051
2052/*!
2053 \fn void Q3ScrollView::contentsMoving(int x, int y)
2054
2055 This signal is emitted just before the contents are moved to
2056 position (\a x, \a y).
2057
2058 \sa contentsX(), contentsY()
2059*/
2060
2061/*!
2062 Moves the contents by (\a x, \a y).
2063*/
2064void Q3ScrollView::moveContents(int x, int y)
2065{
2066 if (-x+visibleWidth() > d->contentsWidth())
2067#if 0
2068 if(QApplication::reverseLayout())
2069 x=QMAX(0,-d->contentsWidth()+visibleWidth());
2070 else
2071#endif
2072 x=QMIN(0,-d->contentsWidth()+visibleWidth());
2073 if (-y+visibleHeight() > contentsHeight())
2074 y=QMIN(0,-contentsHeight()+visibleHeight());
2075
2076 int dx = x - d->vx;
2077 int dy = y - d->vy;
2078
2079 if (!dx && !dy)
2080 return; // Nothing to do
2081
2082 emit contentsMoving(-x, -y);
2083
2084 d->vx = x;
2085 d->vy = y;
2086
2087 if (d->clipped_viewport || d->static_bg) {
2088 // Cheap move (usually)
2089 d->moveAllBy(dx,dy);
2090 } else if (/*dx && dy ||*/
2091 (QABS(dy) * 5 > visibleHeight() * 4) ||
2092 (QABS(dx) * 5 > visibleWidth() * 4)
2093 )
2094 {
2095 // Big move
2096 if (viewport()->updatesEnabled())
2097 viewport()->update();
2098 d->moveAllBy(dx,dy);
2099 } else if (!d->fake_scroll || d->contentsWidth() > visibleWidth()) {
2100 // Small move
2101 clipper()->scroll(dx,dy);
2102 }
2103 d->hideOrShowAll(this, true);
2104}
2105
2106/*!
2107 \property Q3ScrollView::contentsX
2108 \brief the X coordinate of the contents that are at the left edge of
2109 the viewport.
2110*/
2111int Q3ScrollView::contentsX() const
2112{
2113 return d->contentsX();
2114}
2115
2116/*!
2117 \property Q3ScrollView::contentsY
2118 \brief the Y coordinate of the contents that are at the top edge of
2119 the viewport.
2120*/
2121int Q3ScrollView::contentsY() const
2122{
2123 return d->contentsY();
2124}
2125
2126/*!
2127 \property Q3ScrollView::contentsWidth
2128 \brief the width of the contents area
2129*/
2130int Q3ScrollView::contentsWidth() const
2131{
2132 return d->contentsWidth();
2133}
2134
2135/*!
2136 \property Q3ScrollView::contentsHeight
2137 \brief the height of the contents area
2138*/
2139int Q3ScrollView::contentsHeight() const
2140{
2141 return d->vheight;
2142}
2143
2144/*!
2145 Sets the size of the contents area to \a w pixels wide and \a h
2146 pixels high and updates the viewport accordingly.
2147*/
2148void Q3ScrollView::resizeContents(int w, int h)
2149{
2150 int ow = d->vwidth;
2151 int oh = d->vheight;
2152 d->vwidth = w;
2153 d->vheight = h;
2154
2155 d->scrollbar_timer.start(0, true);
2156
2157 if (d->children.isEmpty() && d->policy == Default)
2158 setResizePolicy(Manual);
2159
2160 if (ow > w) {
2161 // Swap
2162 int t=w;
2163 w=ow;
2164 ow=t;
2165 }
2166 // Refresh area ow..w
2167 if (ow < visibleWidth() && w >= 0) {
2168 if (ow < 0)
2169 ow = 0;
2170 if (w > visibleWidth())
2171 w = visibleWidth();
2172 clipper()->update(d->contentsX()+ow, 0, w-ow, visibleHeight());
2173 }
2174
2175 if (oh > h) {
2176 // Swap
2177 int t=h;
2178 h=oh;
2179 oh=t;
2180 }
2181 // Refresh area oh..h
2182 if (oh < visibleHeight() && h >= 0) {
2183 if (oh < 0)
2184 oh = 0;
2185 if (h > visibleHeight())
2186 h = visibleHeight();
2187 clipper()->update(0, d->contentsY()+oh, visibleWidth(), h-oh);
2188 }
2189}
2190
2191/*!
2192 Calls update() on a rectangle defined by \a x, \a y, \a w, \a h,
2193 translated appropriately. If the rectangle is not visible, nothing
2194 is repainted.
2195
2196 \sa repaintContents()
2197*/
2198void Q3ScrollView::updateContents(int x, int y, int w, int h)
2199{
2200 if (!isVisible() || !updatesEnabled())
2201 return;
2202
2203 QWidget* vp = viewport();
2204
2205 // Translate
2206 x -= d->contentsX();
2207 y -= d->contentsY();
2208
2209 if (x < 0) {
2210 w += x;
2211 x = 0;
2212 }
2213 if (y < 0) {
2214 h += y;
2215 y = 0;
2216 }
2217
2218 if (w < 0 || h < 0)
2219 return;
2220 if (x > visibleWidth() || y > visibleHeight())
2221 return;
2222
2223 if (w > visibleWidth())
2224 w = visibleWidth();
2225 if (h > visibleHeight())
2226 h = visibleHeight();
2227
2228 if (d->clipped_viewport) {
2229 // Translate clipper() to viewport()
2230 x -= d->clipped_viewport->x();
2231 y -= d->clipped_viewport->y();
2232 }
2233
2234 vp->update(x, y, w, h);
2235}
2236
2237/*!
2238 \overload
2239
2240 Updates the contents in rectangle \a r
2241*/
2242void Q3ScrollView::updateContents(const QRect& r)
2243{
2244 updateContents(r.x(), r.y(), r.width(), r.height());
2245}
2246
2247/*!
2248 \overload
2249*/
2250void Q3ScrollView::updateContents()
2251{
2252 updateContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight());
2253}
2254
2255/*!
2256 \overload
2257
2258 Repaints the contents of rectangle \a r. If \a erase is true the
2259 background is cleared using the background color.
2260*/
2261void Q3ScrollView::repaintContents(const QRect& r, bool erase)
2262{
2263 repaintContents(r.x(), r.y(), r.width(), r.height(), erase);
2264}
2265
2266
2267/*!
2268 \overload
2269
2270 Repaints the contents. If \a erase is true the background is
2271 cleared using the background color.
2272*/
2273void Q3ScrollView::repaintContents(bool erase)
2274{
2275 repaintContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase);
2276}
2277
2278
2279/*!
2280 Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h,
2281 translated appropriately. If the rectangle is not visible, nothing
2282 is repainted. If \a erase is true the background is cleared using
2283 the background color.
2284
2285 \sa updateContents()
2286*/
2287void Q3ScrollView::repaintContents(int x, int y, int w, int h, bool /*erase*/)
2288{
2289 if (!isVisible() || !updatesEnabled())
2290 return;
2291
2292 QWidget* vp = viewport();
2293
2294 // Translate logical to clipper()
2295 x -= d->contentsX();
2296 y -= d->contentsY();
2297
2298 if (x < 0) {
2299 w += x;
2300 x = 0;
2301 }
2302 if (y < 0) {
2303 h += y;
2304 y = 0;
2305 }
2306
2307 if (w < 0 || h < 0)
2308 return;
2309 if (w > visibleWidth())
2310 w = visibleWidth();
2311 if (h > visibleHeight())
2312 h = visibleHeight();
2313
2314 if (d->clipped_viewport) {
2315 // Translate clipper() to viewport()
2316 x -= d->clipped_viewport->x();
2317 y -= d->clipped_viewport->y();
2318 }
2319
2320 vp->update(x, y, w, h);
2321}
2322
2323
2324/*!
2325 For backward-compatibility only. It is easier to use
2326 drawContents(QPainter*,int,int,int,int).
2327
2328 The default implementation translates the painter appropriately
2329 and calls drawContents(QPainter*,int,int,int,int). See
2330 drawContents() for an explanation of the parameters \a p, \a
2331 offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph.
2332*/
2333void Q3ScrollView::drawContentsOffset(QPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph)
2334{
2335 p->translate(-offsetx,-offsety);
2336 drawContents(p, clipx, clipy, clipw, cliph);
2337}
2338
2339/*!
2340 \fn void Q3ScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph)
2341
2342 Reimplement this function if you are viewing a drawing area rather
2343 than a widget.
2344
2345 The function should draw the rectangle (\a clipx, \a clipy, \a
2346 clipw, \a cliph) of the contents using painter \a p. The clip
2347 rectangle is in the scrollview's coordinates.
2348
2349 For example:
2350 \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 4
2351
2352 The clip rectangle and translation of the painter \a p is already
2353 set appropriately.
2354*/
2355void Q3ScrollView::drawContents(QPainter*, int, int, int, int)
2356{
2357}
2358
2359
2360/*!
2361 \reimp
2362*/
2363void Q3ScrollView::frameChanged()
2364{
2365 // slight ugle-hack - the listview header needs readjusting when
2366 // changing the frame
2367 if (Q3ListView *lv = qobject_cast<Q3ListView *>(this))
2368 lv->triggerUpdate();
2369 Q3Frame::frameChanged();
2370 updateScrollBars();
2371}
2372
2373
2374/*!
2375 Returns the viewport widget of the scrollview. This is the widget
2376 containing the contents widget or which is the drawing area.
2377*/
2378QWidget* Q3ScrollView::viewport() const
2379{
2380 if (d->clipped_viewport)
2381 return d->clipped_viewport;
2382 return d->viewport;
2383}
2384
2385/*!
2386 Returns the clipper widget. Contents in the scrollview are
2387 ultimately clipped to be inside the clipper widget.
2388
2389 You should not need to use this function.
2390
2391 \sa visibleWidth(), visibleHeight()
2392*/
2393QWidget* Q3ScrollView::clipper() const
2394{
2395 return d->viewport;
2396}
2397
2398/*!
2399 \property Q3ScrollView::visibleWidth
2400 \brief the horizontal amount of the content that is visible
2401*/
2402int Q3ScrollView::visibleWidth() const
2403{
2404 return clipper()->width();
2405}
2406
2407/*!
2408 \property Q3ScrollView::visibleHeight
2409 \brief the vertical amount of the content that is visible
2410*/
2411int Q3ScrollView::visibleHeight() const
2412{
2413 return clipper()->height();
2414}
2415
2416
2417void Q3ScrollView::changeFrameRect(const QRect& r)
2418{
2419 QRect oldr = frameRect();
2420 if (oldr != r) {
2421 QRect cr = contentsRect();
2422 QRegion fr(frameRect());
2423 fr = fr.subtracted(contentsRect());
2424 setFrameRect(r);
2425 if (isVisible()) {
2426 cr = cr.intersected(contentsRect());
2427 fr = fr.united(frameRect());
2428 fr = fr.subtracted(cr);
2429 if (!fr.isEmpty())
2430 update(fr);
2431 }
2432 }
2433}
2434
2435
2436/*!
2437 Sets the margins around the scrolling area to \a left, \a top, \a
2438 right and \a bottom. This is useful for applications such as
2439 spreadsheets with "locked" rows and columns. The marginal space is
2440 \e inside the frameRect() and is left blank; reimplement
2441 drawFrame() or put widgets in the unused area.
2442
2443 By default all margins are zero.
2444
2445 \sa frameChanged()
2446*/
2447void Q3ScrollView::setMargins(int left, int top, int right, int bottom)
2448{
2449 if (left == d->l_marg &&
2450 top == d->t_marg &&
2451 right == d->r_marg &&
2452 bottom == d->b_marg)
2453 return;
2454
2455 d->l_marg = left;
2456 d->t_marg = top;
2457 d->r_marg = right;
2458 d->b_marg = bottom;
2459 updateScrollBars();
2460}
2461
2462
2463/*!
2464 Returns the left margin.
2465
2466 \sa setMargins()
2467*/
2468int Q3ScrollView::leftMargin() const
2469{
2470 return d->l_marg;
2471}
2472
2473
2474/*!
2475 Returns the top margin.
2476
2477 \sa setMargins()
2478*/
2479int Q3ScrollView::topMargin() const
2480{
2481 return d->t_marg;
2482}
2483
2484
2485/*!
2486 Returns the right margin.
2487
2488 \sa setMargins()
2489*/
2490int Q3ScrollView::rightMargin() const
2491{
2492 return d->r_marg;
2493}
2494
2495
2496/*!
2497 Returns the bottom margin.
2498
2499 \sa setMargins()
2500*/
2501int Q3ScrollView::bottomMargin() const
2502{
2503 return d->b_marg;
2504}
2505
2506/*!
2507 \reimp
2508*/
2509bool Q3ScrollView::focusNextPrevChild(bool next)
2510{
2511 // Makes sure that the new focus widget is on-screen, if
2512 // necessary by scrolling the scroll view.
2513 bool retval = Q3Frame::focusNextPrevChild(next);
2514 if (retval) {
2515 QWidget *w = window()->focusWidget();
2516 if (isAncestorOf(w)) {
2517 QSVChildRec *r = d->ancestorRec(w);
2518 if (r && (r->child == w || w->isVisibleTo(r->child))) {
2519 QPoint cp = r->child->mapToGlobal(QPoint(0, 0));
2520 QPoint cr = w->mapToGlobal(QPoint(0, 0)) - cp;
2521 ensureVisible(r->x + cr.x() + w->width()/2, r->y + cr.y() + w->height()/2,
2522 w->width()/2, w->height()/2);
2523 }
2524 }
2525 }
2526 return retval;
2527}
2528
2529
2530
2531/*!
2532 When a large numbers of child widgets are in a scrollview,
2533 especially if they are close together, the scrolling performance
2534 can suffer greatly. If \a y is true the scrollview will use an
2535 extra widget to group child widgets.
2536
2537 Note that you may only call enableClipper() prior to adding
2538 widgets.
2539*/
2540void Q3ScrollView::enableClipper(bool y)
2541{
2542 if (!d->clipped_viewport == !y)
2543 return;
2544 if (d->children.count())
2545 qFatal("May only call Q3ScrollView::enableClipper() before adding widgets");
2546 if (y) {
2547 d->clipped_viewport = new QClipperWidget(clipper(), "qt_clipped_viewport", QFlag(d->flags));
2548 d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2,
2549 coord_limit,coord_limit);
2550 d->clipped_viewport->setBackgroundMode(d->viewport->backgroundMode());
2551 d->viewport->setBackgroundMode(NoBackground); // no exposures for this
2552 d->viewport->removeEventFilter(this);
2553 d->clipped_viewport->installEventFilter(this);
2554 d->clipped_viewport->show();
2555 } else {
2556 delete d->clipped_viewport;
2557 d->clipped_viewport = 0;
2558 }
2559}
2560
2561/*!
2562 Sets the scrollview to have a static background if \a y is true,
2563 or a scrolling background if \a y is false. By default, the
2564 background is scrolling.
2565
2566 Be aware that this mode is quite slow, as a full repaint of the
2567 visible area has to be triggered on every contents move.
2568
2569 \sa hasStaticBackground()
2570*/
2571void Q3ScrollView::setStaticBackground(bool y)
2572{
2573 d->static_bg = y;
2574}
2575
2576/*!
2577 Returns true if Q3ScrollView uses a static background; otherwise
2578 returns false.
2579
2580 \sa setStaticBackground()
2581*/
2582bool Q3ScrollView::hasStaticBackground() const
2583{
2584 return d->static_bg;
2585}
2586
2587/*!
2588 \overload
2589
2590 Returns the point \a p translated to a point on the viewport()
2591 widget.
2592*/
2593QPoint Q3ScrollView::contentsToViewport(const QPoint& p) const
2594{
2595 if (d->clipped_viewport) {
2596 return QPoint(p.x() - d->contentsX() - d->clipped_viewport->x(),
2597 p.y() - d->contentsY() - d->clipped_viewport->y());
2598 } else {
2599 return QPoint(p.x() - d->contentsX(),
2600 p.y() - d->contentsY());
2601 }
2602}
2603
2604/*!
2605 \overload
2606
2607 Returns the point on the viewport \a vp translated to a point in
2608 the contents.
2609*/
2610QPoint Q3ScrollView::viewportToContents(const QPoint& vp) const
2611{
2612 if (d->clipped_viewport) {
2613 return QPoint(vp.x() + d->contentsX() + d->clipped_viewport->x(),
2614 vp.y() + d->contentsY() + d->clipped_viewport->y());
2615 } else {
2616 return QPoint(vp.x() + d->contentsX(),
2617 vp.y() + d->contentsY());
2618 }
2619}
2620
2621
2622/*!
2623 Translates a point (\a x, \a y) in the contents to a point (\a vx,
2624 \a vy) on the viewport() widget.
2625*/
2626void Q3ScrollView::contentsToViewport(int x, int y, int& vx, int& vy) const
2627{
2628 const QPoint v = contentsToViewport(QPoint(x,y));
2629 vx = v.x();
2630 vy = v.y();
2631}
2632
2633/*!
2634 Translates a point (\a vx, \a vy) on the viewport() widget to a
2635 point (\a x, \a y) in the contents.
2636*/
2637void Q3ScrollView::viewportToContents(int vx, int vy, int& x, int& y) const
2638{
2639 const QPoint c = viewportToContents(QPoint(vx,vy));
2640 x = c.x();
2641 y = c.y();
2642}
2643
2644/*!
2645 \reimp
2646*/
2647QSize Q3ScrollView::sizeHint() const
2648{
2649 if (d->use_cached_size_hint && d->cachedSizeHint.isValid())
2650 return d->cachedSizeHint;
2651
2652 constPolish();
2653 int f = 2 * frameWidth();
2654 int h = fontMetrics().height();
2655 QSize sz(f, f);
2656 if (d->policy > Manual) {
2657 QSVChildRec *r = d->children.first();
2658 if (r) {
2659 QSize cs = r->child->sizeHint();
2660 if (cs.isValid())
2661 sz += cs.boundedTo(r->child->maximumSize());
2662 else
2663 sz += r->child->size();
2664 }
2665 } else {
2666 sz += QSize(d->contentsWidth(), contentsHeight());
2667 }
2668 if (d->vMode == AlwaysOn)
2669 sz.setWidth(sz.width() + d->vbar->sizeHint().width());
2670 if (d->hMode == AlwaysOn)
2671 sz.setHeight(sz.height() + d->hbar->sizeHint().height());
2672 return sz.expandedTo(QSize(12 * h, 8 * h))
2673 .boundedTo(QSize(36 * h, 24 * h));
2674}
2675
2676
2677/*!
2678 \reimp
2679*/
2680QSize Q3ScrollView::minimumSizeHint() const
2681{
2682 int h = fontMetrics().height();
2683 if (h < 10)
2684 h = 10;
2685 int f = 2 * frameWidth();
2686 return QSize((6 * h) + f, (4 * h) + f);
2687}
2688
2689
2690/*!
2691 \reimp
2692
2693 (Implemented to get rid of a compiler warning.)
2694*/
2695void Q3ScrollView::drawContents(QPainter *)
2696{
2697}
2698
2699#ifndef QT_NO_DRAGANDDROP
2700
2701/*!
2702 \internal
2703*/
2704void Q3ScrollView::startDragAutoScroll()
2705{
2706 if (!d->autoscroll_timer.isActive()) {
2707 d->autoscroll_time = initialScrollTime;
2708 d->autoscroll_accel = initialScrollAccel;
2709 d->autoscroll_timer.start(d->autoscroll_time);
2710 }
2711}
2712
2713
2714/*!
2715 \internal
2716*/
2717void Q3ScrollView::stopDragAutoScroll()
2718{
2719 d->autoscroll_timer.stop();
2720}
2721
2722
2723/*!
2724 \internal
2725*/
2726void Q3ScrollView::doDragAutoScroll()
2727{
2728 QPoint p = d->viewport->mapFromGlobal(QCursor::pos());
2729
2730 if (d->autoscroll_accel-- <= 0 && d->autoscroll_time) {
2731 d->autoscroll_accel = initialScrollAccel;
2732 d->autoscroll_time--;
2733 d->autoscroll_timer.start(d->autoscroll_time);
2734 }
2735 int l = QMAX(1, (initialScrollTime- d->autoscroll_time));
2736
2737 int dx = 0, dy = 0;
2738 if (p.y() < autoscroll_margin) {
2739 dy = -l;
2740 } else if (p.y() > visibleHeight() - autoscroll_margin) {
2741 dy = +l;
2742 }
2743 if (p.x() < autoscroll_margin) {
2744 dx = -l;
2745 } else if (p.x() > visibleWidth() - autoscroll_margin) {
2746 dx = +l;
2747 }
2748 if (dx || dy) {
2749 scrollBy(dx,dy);
2750 } else {
2751 stopDragAutoScroll();
2752 }
2753}
2754
2755
2756/*!
2757 \property Q3ScrollView::dragAutoScroll
2758 \brief whether autoscrolling in drag move events is enabled
2759
2760 If this property is set to true (the default), the Q3ScrollView
2761 automatically scrolls the contents in drag move events if the user
2762 moves the cursor close to a border of the view. Of course this
2763 works only if the viewport accepts drops. Specifying false
2764 disables this autoscroll feature.
2765*/
2766
2767void Q3ScrollView::setDragAutoScroll(bool b)
2768{
2769 d->drag_autoscroll = b;
2770}
2771
2772bool Q3ScrollView::dragAutoScroll() const
2773{
2774 return d->drag_autoscroll;
2775}
2776
2777#endif // QT_NO_DRAGANDDROP
2778
2779/*!\internal
2780 */
2781void Q3ScrollView::setCachedSizeHint(const QSize &sh) const
2782{
2783 if (isVisible() && !d->cachedSizeHint.isValid())
2784 d->cachedSizeHint = sh;
2785}
2786
2787/*!\internal
2788 */
2789void Q3ScrollView::disableSizeHintCaching()
2790{
2791 d->use_cached_size_hint = false;
2792}
2793
2794/*!\internal
2795 */
2796QSize Q3ScrollView::cachedSizeHint() const
2797{
2798 return d->use_cached_size_hint ? d->cachedSizeHint : QSize();
2799}
2800
2801QT_END_NAMESPACE
2802
2803#endif // QT_NO_SCROLLVIEW
Note: See TracBrowser for help on using the repository browser.