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