1
/****************************************************************************
4
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
6
** This file is part of the Qt 3 compatibility classes of the Qt Toolkit.
8
** This file may be distributed under the terms of the Q Public License
9
** as defined by Trolltech AS of Norway and appearing in the file
10
** LICENSE.QPL included in the packaging of this file.
12
** This file may be distributed and/or modified under the terms of the
13
** GNU General Public License version 2 as published by the Free Software
14
** Foundation and appearing in the file LICENSE.GPL included in the
15
** packaging of this file.
17
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
18
** information about Qt Commercial License Agreements.
19
** See http://www.trolltech.com/qpl/ for QPL licensing information.
20
** See http://www.trolltech.com/gpl/ for GPL licensing information.
22
** Contact info@trolltech.com if any conditions of this licensing are
25
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28
****************************************************************************/
31
#ifndef QT_NO_SCROLLVIEW
32
#include "qscrollbar.h"
36
#include "q3scrollview.h"
37
#include "q3ptrdict.h"
38
#include "qapplication.h"
41
#include "q3ptrlist.h"
44
# include "private/qt_mac_p.h"
49
static const int coord_limit = 4000;
50
static const int autoscroll_margin = 16;
51
static const int initialScrollTime = 30;
52
static const int initialScrollAccel = 5;
55
QSVChildRec(QWidget* c, int xx, int yy) :
61
void hideOrShow(Q3ScrollView* sv, QWidget* clipped_viewport);
62
void moveTo(Q3ScrollView* sv, int xx, int yy, QWidget* clipped_viewport)
64
if (x != xx || y != yy) {
67
hideOrShow(sv,clipped_viewport);
74
void QSVChildRec::hideOrShow(Q3ScrollView* sv, QWidget* clipped_viewport)
76
if (clipped_viewport) {
77
if (x+child->width() < sv->contentsX()+clipped_viewport->x()
78
|| x > sv->contentsX()+clipped_viewport->width()
79
|| y+child->height() < sv->contentsY()+clipped_viewport->y()
80
|| y > sv->contentsY()+clipped_viewport->height()) {
81
child->move(clipped_viewport->width(),
82
clipped_viewport->height());
84
child->move(x-sv->contentsX()-clipped_viewport->x(),
85
y-sv->contentsY()-clipped_viewport->y());
88
child->move(x-sv->contentsX(), y-sv->contentsY());
92
class QAbstractScrollAreaWidget : public QWidget
97
QAbstractScrollAreaWidget(Q3ScrollView* parent=0, const char* name=0, Qt::WFlags f = 0)
98
: QWidget(parent, name, f) {}
101
class QClipperWidget : public QWidget
106
QClipperWidget(QWidget * parent=0, const char * name=0, Qt::WFlags f=0)
107
: QWidget (parent,name,f) {}
110
#include "q3scrollview.moc"
112
class Q3ScrollViewData {
114
Q3ScrollViewData(Q3ScrollView* parent, int vpwflags) :
115
hbar(new QScrollBar(Qt::Horizontal, parent, "qt_hbar")),
116
vbar(new QScrollBar(Qt::Vertical, parent, "qt_vbar")),
117
viewport(new QAbstractScrollAreaWidget(parent, "qt_viewport", QFlag(vpwflags))),
120
vx(0), vy(0), vwidth(1), vheight(1),
121
#ifndef QT_NO_DRAGANDDROP
122
autoscroll_timer(parent, "scrollview autoscroll timer"),
123
drag_autoscroll(true),
125
scrollbar_timer(parent, "scrollview scrollbar timer"),
126
inresize(false), use_cached_size_hint(true)
128
l_marg = r_marg = t_marg = b_marg = 0;
130
vMode = Q3ScrollView::Auto;
131
hMode = Q3ScrollView::Auto;
133
vbar->setSteps(20, 1/*set later*/);
134
hbar->setSteps(20, 1/*set later*/);
135
policy = Q3ScrollView::Default;
136
signal_choke = false;
144
QSVChildRec* rec(QWidget* w) { return childDict.find(w); }
145
QSVChildRec* ancestorRec(QWidget* w);
146
QSVChildRec* addChildRec(QWidget* w, int x, int y)
148
QSVChildRec *r = new QSVChildRec(w,x,y);
150
childDict.insert(w, r);
153
void deleteChildRec(QSVChildRec* r)
155
childDict.remove(r->child);
156
children.removeRef(r);
160
void hideOrShowAll(Q3ScrollView* sv, bool isScroll = false);
161
void moveAllBy(int dx, int dy);
162
bool anyVisibleChildren();
163
void autoMove(Q3ScrollView* sv);
164
void autoResize(Q3ScrollView* sv);
165
void autoResizeHint(Q3ScrollView* sv);
166
void viewportResized(int w, int h);
172
QAbstractScrollAreaWidget* viewport;
173
QClipperWidget* clipped_viewport;
175
Q3PtrList<QSVChildRec> children;
176
Q3PtrDict<QSVChildRec> childDict;
178
int vx, vy, vwidth, vheight; // for drawContents-style usage
179
int l_marg, r_marg, t_marg, b_marg;
180
Q3ScrollView::ResizePolicy policy;
181
Q3ScrollView::ScrollBarMode vMode;
182
Q3ScrollView::ScrollBarMode hMode;
183
#ifndef QT_NO_DRAGANDDROP
185
QTimer autoscroll_timer;
187
int autoscroll_accel;
188
bool drag_autoscroll;
190
QTimer scrollbar_timer;
193
uint fake_scroll : 1;
195
// This variable allows ensureVisible to move the contents then
196
// update both the sliders. Otherwise, updating the sliders would
197
// cause two image scrolls, creating ugly flashing.
199
uint signal_choke : 1;
201
// This variables indicates in updateScrollBars() that we are
202
// in a resizeEvent() and thus don't want to flash scrollbars
204
uint use_cached_size_hint : 1;
205
QSize cachedSizeHint;
207
inline int contentsX() const { return -vx; }
208
inline int contentsY() const { return -vy; }
209
inline int contentsWidth() const { return vwidth; }
212
inline Q3ScrollViewData::~Q3ScrollViewData()
214
children.setAutoDelete(true);
217
QSVChildRec* Q3ScrollViewData::ancestorRec(QWidget* w)
219
if (clipped_viewport) {
220
while (w->parentWidget() != clipped_viewport) {
221
w = w->parentWidget();
225
while (w->parentWidget() != viewport) {
226
w = w->parentWidget();
233
void Q3ScrollViewData::hideOrShowAll(Q3ScrollView* sv, bool isScroll)
235
if (!clipped_viewport)
237
if (clipped_viewport->x() <= 0
238
&& clipped_viewport->y() <= 0
239
&& clipped_viewport->width()+clipped_viewport->x() >=
241
&& clipped_viewport->height()+clipped_viewport->y() >=
242
viewport->height()) {
243
// clipped_viewport still covers viewport
245
clipped_viewport->repaint(true);
246
else if ((!isScroll && !clipped_viewport->testAttribute(Qt::WA_StaticContents)) || static_bg)
247
clipped_viewport->update();
250
int nx = (viewport->width() - clipped_viewport->width()) / 2;
251
int ny = (viewport->height() - clipped_viewport->height()) / 2;
252
clipped_viewport->move(nx,ny);
253
// no need to update, we'll receive a paintevent after move
254
// (with the safe assumption that the newly exposed area
255
// covers the entire viewport)
257
for (QSVChildRec *r = children.first(); r; r=children.next()) {
258
r->hideOrShow(sv, clipped_viewport);
262
void Q3ScrollViewData::moveAllBy(int dx, int dy)
264
if (clipped_viewport && !static_bg) {
265
clipped_viewport->move(clipped_viewport->x()+dx,
266
clipped_viewport->y()+dy);
268
for (QSVChildRec *r = children.first(); r; r=children.next()) {
269
r->child->move(r->child->x()+dx,r->child->y()+dy);
272
viewport->repaint(true);
276
bool Q3ScrollViewData::anyVisibleChildren()
278
for (QSVChildRec *r = children.first(); r; r=children.next()) {
279
if (r->child->isVisible()) return true;
284
void Q3ScrollViewData::autoMove(Q3ScrollView* sv)
286
if (policy == Q3ScrollView::AutoOne) {
287
QSVChildRec* r = children.first();
289
sv->setContentsPos(-r->child->x(),-r->child->y());
293
void Q3ScrollViewData::autoResize(Q3ScrollView* sv)
295
if (policy == Q3ScrollView::AutoOne) {
296
QSVChildRec* r = children.first();
298
sv->resizeContents(r->child->width(),r->child->height());
302
void Q3ScrollViewData::autoResizeHint(Q3ScrollView* sv)
304
if (policy == Q3ScrollView::AutoOne) {
305
QSVChildRec* r = children.first();
307
QSize s = r->child->sizeHint();
311
} else if (policy == Q3ScrollView::AutoOneFit) {
312
QSVChildRec* r = children.first();
314
QSize sh = r->child->sizeHint();
315
sh = sh.boundedTo(r->child->maximumSize());
316
sv->resizeContents(sh.width(), sh.height());
321
void Q3ScrollViewData::viewportResized(int w, int h)
323
if (policy == Q3ScrollView::AutoOneFit) {
324
QSVChildRec* r = children.first();
326
QSize sh = r->child->sizeHint();
327
sh = sh.boundedTo(r->child->maximumSize());
328
r->child->resize(QMAX(w,sh.width()), QMAX(h,sh.height()));
336
\class Q3ScrollView qscrollview.h
337
\brief The Q3ScrollView widget provides a scrolling area with on-demand scroll bars.
341
The Q3ScrollView is a large canvas - potentially larger than the
342
coordinate system normally supported by the underlying window
343
system. This is important because it is quite easy to go beyond
344
these limitations (e.g. many web pages are more than 32000 pixels
345
high). Additionally, the Q3ScrollView can have QWidgets positioned
346
on it that scroll around with the drawn content. These sub-widgets
347
can also have positions outside the normal coordinate range (but
348
they are still limited in size).
350
To provide content for the widget, inherit from Q3ScrollView,
351
reimplement drawContents() and use resizeContents() to set the
352
size of the viewed area. Use addChild() and moveChild() to
353
position widgets on the view.
355
To use Q3ScrollView effectively it is important to understand its
356
widget structure in the three styles of use: a single large child
357
widget, a large panning area with some widgets and a large panning
358
area with many widgets.
360
\section1 Using One Big Widget
362
\img qscrollview-vp2.png
364
The first, simplest usage of Q3ScrollView (depicted above), is
365
appropriate for scrolling areas that are never more than about
366
4000 pixels in either dimension (this is about the maximum
367
reliable size on X11 servers). In this usage, you just make one
368
large child in the Q3ScrollView. The child should be a child of the
369
viewport() of the scrollview and be added with addChild():
371
Q3ScrollView* sv = new Q3ScrollView(...);
372
QVBoxWidget* big_box = new QVBoxWidget(sv->viewport());
373
sv->addChild(big_box);
375
You can go on to add arbitrary child widgets to the single child
376
in the scrollview as you would with any widget:
378
QLabel* child1 = new QLabel("CHILD", big_box);
379
QLabel* child2 = new QLabel("CHILD", big_box);
380
QLabel* child3 = new QLabel("CHILD", big_box);
384
Here the Q3ScrollView has four children: the viewport(), the
385
verticalScrollBar(), the horizontalScrollBar() and a small
386
cornerWidget(). The viewport() has one child: the big QVBoxWidget. The
387
QVBoxWidget has the three QLabel objects as child widgets. When the view
388
is scrolled, the QVBoxWidget is moved; its children move with it as
389
child widgets normally do.
391
\section1 Using a Very Big View with Some Widgets
393
\img qscrollview-vp.png
395
The second usage of Q3ScrollView (depicted above) is appropriate
396
when few, if any, widgets are on a very large scrolling area that
397
is potentially larger than 4000 pixels in either dimension. In
398
this usage you call resizeContents() to set the size of the area
399
and reimplement drawContents() to paint the contents. You may also
400
add some widgets by making them children of the viewport() and
401
adding them with addChild() (this is the same as the process for
402
the single large widget in the previous example):
404
Q3ScrollView* sv = new Q3ScrollView(...);
405
QLabel* child1 = new QLabel("CHILD", sv->viewport());
406
sv->addChild(child1);
407
QLabel* child2 = new QLabel("CHILD", sv->viewport());
408
sv->addChild(child2);
409
QLabel* child3 = new QLabel("CHILD", sv->viewport());
410
sv->addChild(child3);
412
Here, the Q3ScrollView has the same four children: the viewport(),
413
the verticalScrollBar(), the horizontalScrollBar() and a small
414
cornerWidget(). The viewport() has the three QLabel objects as
415
child widgets. When the view is scrolled, the scrollview moves the
416
child widgets individually.
418
\section1 Using a Very Big View with Many Widgets
420
\img qscrollview-cl.png
422
The final usage of Q3ScrollView (depicted above) is appropriate
423
when many widgets are on a very large scrolling area that is
424
potentially larger than 4000 pixels in either dimension. In this
425
usage you call resizeContents() to set the size of the area and
426
reimplement drawContents() to paint the contents. You then call
427
enableClipper(true) and add widgets, again by making them children
428
of the viewport(), and adding them with addChild():
430
Q3ScrollView* sv = new Q3ScrollView(...);
431
sv->enableClipper(true);
432
QLabel* child1 = new QLabel("CHILD", sv->viewport());
433
sv->addChild(child1);
434
QLabel* child2 = new QLabel("CHILD", sv->viewport());
435
sv->addChild(child2);
436
QLabel* child3 = new QLabel("CHILD", sv->viewport());
437
sv->addChild(child3);
440
Here, the Q3ScrollView has four children: the clipper() (not the
441
viewport() this time), the verticalScrollBar(), the
442
horizontalScrollBar() and a small cornerWidget(). The clipper()
443
has one child: the viewport(). The viewport() has the same three
444
labels as child widgets. When the view is scrolled the viewport()
445
is moved; its children move with it as child widgets normally do.
448
\section1 Details Relevant for All Views
450
Normally you will use the first or third method if you want any
451
child widgets in the view.
453
Note that the widget you see in the scrolled area is the
454
viewport() widget, not the Q3ScrollView itself. So to turn mouse
455
tracking on, for example, use viewport()->setMouseTracking(true).
457
To enable drag-and-drop, you would setAcceptDrops(true) on the
458
Q3ScrollView (because drag-and-drop events propagate to the
459
parent). But to work out the logical position in the view, you
460
would need to map the drop co-ordinate from being relative to the
461
Q3ScrollView to being relative to the contents; use the function
462
viewportToContents() for this.
464
To handle mouse events on the scrolling area, subclass scrollview
465
as you would subclass other widgets, but rather than
466
reimplementing mousePressEvent(), reimplement
467
contentsMousePressEvent() instead. The contents specific event
468
handlers provide translated events in the coordinate system of the
469
scrollview. If you reimplement mousePressEvent(), you'll get
470
called only when part of the Q3ScrollView is clicked: and the only
471
such part is the "corner" (if you don't set a cornerWidget()) and
472
the frame; everything else is covered up by the viewport, clipper
475
When you construct a Q3ScrollView, some of the window flags apply
476
to the viewport() instead of being sent to the QWidget constructor
477
for the Q3ScrollView.
481
\i An image-manipulation widget would use \c
482
WNoAutoErase|WStaticContents because the widget draws all pixels
483
itself, and when its size increases, it only needs a paint event
484
for the new part because the old part remains unchanged.
486
\i A scrolling game widget in which the background scrolls as the
487
characters move might use \c WNoAutoErase (in addition to \c
488
WStaticContents) so that the window system background does not
489
flash in and out during scrolling.
491
\i A word processing widget might use \c WNoAutoErase and repaint
492
itself line by line to get a less-flickery resizing. If the widget
493
is in a mode in which no text justification can take place, it
494
might use \c WStaticContents too, so that it would only get a
495
repaint for the newly visible parts.
499
Child widgets may be moved using addChild() or moveChild(). Use
500
childX() and childY() to get the position of a child widget.
502
A widget may be placed in the corner between the vertical and
503
horizontal scrollbars with setCornerWidget(). You can get access
504
to the scrollbars using horizontalScrollBar() and
505
verticalScrollBar(), and to the viewport with viewport(). The
506
scroll view can be scrolled using scrollBy(), ensureVisible(),
507
setContentsPos() or center().
509
The visible area is given by visibleWidth() and visibleHeight(),
510
and the contents area by contentsWidth() and contentsHeight(). The
511
contents may be repainted using one of the repaintContents() or
512
updateContents() functions.
514
Coordinate conversion is provided by contentsToViewport() and
515
viewportToContents().
517
The contentsMoving() signal is emitted just before the contents
518
are moved to a new position.
520
\warning Q3ScrollView currently does not erase the background when
521
resized, i.e. you must always clear the background manually in
522
scrollview subclasses. This will change in a future version of Qt
523
and we recommend specifying the WNoAutoErase flag explicitly.
528
\enum Q3ScrollView::ResizePolicy
530
This enum type is used to control a Q3ScrollView's reaction to
533
\value Default the Q3ScrollView selects one of the other settings
534
automatically when it has to. In this version of Qt, Q3ScrollView
535
changes to \c Manual if you resize the contents with
536
resizeContents() and to \c AutoOne if a child is added.
538
\value Manual the contents stays the size set by resizeContents().
540
\value AutoOne if there is only one child widget the contents stays
541
the size of that widget. Otherwise the behavior is undefined.
543
\value AutoOneFit if there is only one child widget the contents stays
544
the size of that widget's sizeHint(). If the scrollview is resized
545
larger than the child's sizeHint(), the child will be resized to
546
fit. If there is more than one child, the behavior is undefined.
549
//#### The widget will be resized to its sizeHint() when a LayoutHint event
553
Constructs a Q3ScrollView called \a name with parent \a parent and
556
The widget flags \c WStaticContents, \c WNoAutoErase and \c
557
WPaintClever are propagated to the viewport() widget. The other
558
widget flags are propagated to the parent constructor as usual.
561
Q3ScrollView::Q3ScrollView(QWidget *parent, const char *name, Qt::WFlags f) :
562
Q3Frame(parent, name, f & (~WStaticContents) & (~WNoAutoErase) & (~WResizeNoErase))
564
WFlags flags = WResizeNoErase | (f&WPaintClever) | (f&WRepaintNoErase) | (f&WStaticContents);
565
d = new Q3ScrollViewData(this, flags);
567
#ifndef QT_NO_DRAGANDDROP
568
connect(&d->autoscroll_timer, SIGNAL(timeout()),
569
this, SLOT(doDragAutoScroll()));
572
connect(d->hbar, SIGNAL(valueChanged(int)),
573
this, SLOT(hslide(int)));
574
connect(d->vbar, SIGNAL(valueChanged(int)),
575
this, SLOT(vslide(int)));
577
connect(d->hbar, SIGNAL(sliderPressed()), this, SLOT(hbarIsPressed()));
578
connect(d->hbar, SIGNAL(sliderReleased()), this, SLOT(hbarIsReleased()));
579
connect(d->vbar, SIGNAL(sliderPressed()), this, SLOT(vbarIsPressed()));
580
connect(d->vbar, SIGNAL(sliderReleased()), this, SLOT(vbarIsReleased()));
583
d->viewport->installEventFilter(this);
585
connect(&d->scrollbar_timer, SIGNAL(timeout()),
586
this, SLOT(updateScrollBars()));
588
setFrameStyle(Q3Frame::StyledPanel | Q3Frame::Sunken);
589
setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
590
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
595
Destroys the Q3ScrollView. Any children added with addChild() will
598
Q3ScrollView::~Q3ScrollView()
600
// Be careful not to get all those useless events...
601
if (d->clipped_viewport)
602
d->clipped_viewport->removeEventFilter(this);
604
d->viewport->removeEventFilter(this);
606
// order is important
607
// ~QWidget may cause a WM_ERASEBKGND on Windows
619
\fn void Q3ScrollView::horizontalSliderPressed()
621
This signal is emitted whenever the user presses the horizontal slider.
624
\fn void Q3ScrollView::horizontalSliderReleased()
626
This signal is emitted whenever the user releases the horizontal slider.
629
\fn void Q3ScrollView::verticalSliderPressed()
631
This signal is emitted whenever the user presses the vertical slider.
634
\fn void Q3ScrollView::verticalSliderReleased()
636
This signal is emitted whenever the user releases the vertical slider.
638
void Q3ScrollView::hbarIsPressed()
640
d->hbarPressed = true;
641
emit(horizontalSliderPressed());
644
void Q3ScrollView::hbarIsReleased()
646
d->hbarPressed = false;
647
emit(horizontalSliderReleased());
651
Returns true if horizontal slider is pressed by user; otherwise returns false.
653
bool Q3ScrollView::isHorizontalSliderPressed()
655
return d->hbarPressed;
658
void Q3ScrollView::vbarIsPressed()
660
d->vbarPressed = true;
661
emit(verticalSliderPressed());
664
void Q3ScrollView::vbarIsReleased()
666
d->vbarPressed = false;
667
emit(verticalSliderReleased());
671
Returns true if vertical slider is pressed by user; otherwise returns false.
673
bool Q3ScrollView::isVerticalSliderPressed()
675
return d->vbarPressed;
681
void Q3ScrollView::styleChange(QStyle& old)
683
QWidget::styleChange(old);
685
d->cachedSizeHint = QSize();
691
void Q3ScrollView::fontChange(const QFont &old)
693
QWidget::fontChange(old);
695
d->cachedSizeHint = QSize();
698
void Q3ScrollView::hslide(int pos)
700
if (!d->signal_choke) {
701
moveContents(-pos, -d->contentsY());
702
QApplication::syncX();
706
void Q3ScrollView::vslide(int pos)
708
if (!d->signal_choke) {
709
moveContents(-d->contentsX(), -pos);
710
QApplication::syncX();
715
Called when the horizontal scroll bar geometry changes. This is
716
provided as a protected function so that subclasses can do
717
interesting things such as providing extra buttons in some of the
718
space normally used by the scroll bars.
720
The default implementation simply gives all the space to \a hbar.
721
The new geometry is given by \a x, \a y, \a w and \a h.
723
\sa setVBarGeometry()
725
void Q3ScrollView::setHBarGeometry(QScrollBar& hbar,
726
int x, int y, int w, int h)
728
hbar.setGeometry(x, y, w, h);
732
Called when the vertical scroll bar geometry changes. This is
733
provided as a protected function so that subclasses can do
734
interesting things such as providing extra buttons in some of the
735
space normally used by the scroll bars.
737
The default implementation simply gives all the space to \a vbar.
738
The new geometry is given by \a x, \a y, \a w and \a h.
740
\sa setHBarGeometry()
742
void Q3ScrollView::setVBarGeometry(QScrollBar& vbar,
743
int x, int y, int w, int h)
745
vbar.setGeometry(x, y, w, h);
750
Returns the viewport size for size (\a x, \a y).
752
The viewport size depends on (\a x, \a y) (the size of the contents),
753
the size of this widget and the modes of the horizontal and
754
vertical scroll bars.
756
This function permits widgets that can trade vertical and
757
horizontal space for each other to control scroll bar appearance
758
better. For example, a word processor or web browser can control
759
the width of the right margin accurately, whether or not there
760
needs to be a vertical scroll bar.
763
QSize Q3ScrollView::viewportSize(int x, int y) const
765
int fw = frameWidth();
766
int lmarg = fw+d->l_marg;
767
int rmarg = fw+d->r_marg;
768
int tmarg = fw+d->t_marg;
769
int bmarg = fw+d->b_marg;
776
int hsbExt = horizontalScrollBar()->sizeHint().height();
777
int vsbExt = verticalScrollBar()->sizeHint().width();
779
if (d->policy != AutoOne || d->anyVisibleChildren()) {
780
// Do we definitely need the scrollbar?
781
needh = w-lmarg-rmarg < x;
782
needv = h-tmarg-bmarg < y;
784
// Do we intend to show the scrollbar?
785
if (d->hMode == AlwaysOn)
787
else if (d->hMode == AlwaysOff)
792
if (d->vMode == AlwaysOn)
794
else if (d->vMode == AlwaysOff)
799
// Given other scrollbar will be shown, NOW do we need one?
800
if (showh && h-vsbExt-tmarg-bmarg < y) {
801
if (d->vMode == Auto)
804
if (showv && w-hsbExt-lmarg-rmarg < x) {
805
if (d->hMode == Auto)
809
// Scrollbars not needed, only show scrollbar that are always on.
810
showh = d->hMode == AlwaysOn;
811
showv = d->vMode == AlwaysOn;
814
return QSize(w-lmarg-rmarg - (showv ? vsbExt : 0),
815
h-tmarg-bmarg - (showh ? hsbExt : 0));
820
Updates scroll bars: all possibilities are considered. You should
821
never need to call this in your code.
823
void Q3ScrollView::updateScrollBars()
825
if(!horizontalScrollBar() && !verticalScrollBar())
828
// I support this should use viewportSize()... but it needs
829
// so many of the temporary variables from viewportSize. hm.
830
int fw = frameWidth();
831
int lmarg = fw+d->l_marg;
832
int rmarg = fw+d->r_marg;
833
int tmarg = fw+d->t_marg;
834
int bmarg = fw+d->b_marg;
847
int hsbExt = horizontalScrollBar()->sizeHint().height();
848
int vsbExt = verticalScrollBar()->sizeHint().width();
850
QSize oldVisibleSize(visibleWidth(), visibleHeight());
852
if (d->policy != AutoOne || d->anyVisibleChildren()) {
853
// Do we definitely need the scrollbar?
854
needh = w-lmarg-rmarg < d->contentsWidth();
856
needh = !horizontalScrollBar()->isHidden();
857
needv = h-tmarg-bmarg < contentsHeight();
859
// Do we intend to show the scrollbar?
860
if (d->hMode == AlwaysOn)
862
else if (d->hMode == AlwaysOff)
867
if (d->vMode == AlwaysOn)
869
else if (d->vMode == AlwaysOff)
875
bool mac_need_scroll = false;
876
if(!parentWidget()) {
877
mac_need_scroll = true;
879
QWidget *tlw = window();
880
QPoint tlw_br = QPoint(tlw->width(), tlw->height()),
881
my_br = qt_mac_posInWindow(this) + QPoint(w, h);
882
if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3)
883
mac_need_scroll = true;
885
if(mac_need_scroll) {
886
WindowAttributes attr;
887
GetWindowAttributes((WindowPtr)handle(), &attr);
888
mac_need_scroll = (attr & kWindowResizableAttribute);
890
if(mac_need_scroll) {
899
// Given other scrollbar will be shown, NOW do we need one?
900
if (showh && h-vsbExt-tmarg-bmarg < contentsHeight()) {
902
if (d->vMode == Auto)
905
if (showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth()) {
907
if (d->hMode == Auto)
911
// Scrollbars not needed, only show scrollbar that are always on.
912
needh = needv = false;
913
showh = d->hMode == AlwaysOn;
914
showv = d->vMode == AlwaysOn;
917
bool sc = d->signal_choke;
918
d->signal_choke=true;
920
// Hide unneeded scrollbar, calculate viewport size
922
porth=h-hsbExt-tmarg-bmarg;
925
d->hbar->setValue(0);
930
portw=w-vsbExt-lmarg-rmarg;
933
d->vbar->setValue(0);
938
// Configure scrollbars that we will show
940
d->vbar->setRange(0, contentsHeight()-porth);
941
d->vbar->setSteps(Q3ScrollView::d->vbar->lineStep(), porth);
943
d->vbar->setRange(0, 0);
946
d->hbar->setRange(0, QMAX(0, d->contentsWidth()-portw));
947
d->hbar->setSteps(Q3ScrollView::d->hbar->lineStep(), portw);
949
d->hbar->setRange(0, 0);
952
// Position the scrollbars, viewport and corner widget.
954
bool reverse = QApplication::reverseLayout();
955
int xoffset = (reverse && (showv || cornerWidget())) ? vsbExt : 0;
956
int xpos = reverse ? 0 : w - vsbExt;
957
bool frameContentsOnly =
958
style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
960
if(! frameContentsOnly) {
967
int right = (showc || showv || cornerWidget()) ? w-vsbExt : w;
968
if (! frameContentsOnly)
969
setHBarGeometry(*d->hbar, fw + xoffset, h-hsbExt-fw,
970
right-fw-fw, hsbExt);
972
setHBarGeometry(*d->hbar, 0 + xoffset, h-hsbExt, right,
979
clipper()->setGeometry(lmarg + xoffset, tmarg,
980
w-vsbExt-lmarg-rmarg,
982
d->viewportResized(w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg);
983
if (! frameContentsOnly)
984
changeFrameRect(QRect(0, 0, w, h));
986
changeFrameRect(QRect(xoffset, 0, w-vsbExt, bottom));
987
if (showc || cornerWidget()) {
988
if (! frameContentsOnly)
989
setVBarGeometry(*d->vbar, xpos,
993
setVBarGeometry(*d->vbar, xpos, 0,
998
if (! frameContentsOnly)
999
setVBarGeometry(*d->vbar, xpos,
1003
setVBarGeometry(*d->vbar, xpos, 0,
1007
if (! frameContentsOnly)
1008
changeFrameRect(QRect(0, 0, w, h));
1010
changeFrameRect(QRect(0, 0, w, bottom));
1011
clipper()->setGeometry(lmarg, tmarg,
1012
w-lmarg-rmarg, bottom-tmarg-bmarg);
1013
d->viewportResized(w-lmarg-rmarg, bottom-tmarg-bmarg);
1016
QWidget *corner = d->corner;
1018
if (! frameContentsOnly)
1019
corner->setGeometry(xpos,
1024
corner->setGeometry(xpos,
1032
if (d->contentsX()+visibleWidth() > d->contentsWidth()) {
1036
x =QMIN(0,d->contentsWidth()-visibleWidth());
1039
x =QMAX(0,d->contentsWidth()-visibleWidth());
1040
d->hbar->setValue(x);
1041
// Do it even if it is recursive
1042
moveContents(-x, -d->contentsY());
1044
if (d->contentsY()+visibleHeight() > contentsHeight()) {
1045
int y=QMAX(0,contentsHeight()-visibleHeight());
1046
d->vbar->setValue(y);
1047
// Do it even if it is recursive
1048
moveContents(-d->contentsX(), -y);
1051
// Finally, show the scroll bars
1052
if (showh && (d->hbar->isHidden() || !d->hbar->isVisible()))
1054
if (showv && (d->vbar->isHidden() || !d->vbar->isVisible()))
1057
d->signal_choke=true;
1058
d->vbar->setValue(d->contentsY());
1059
d->hbar->setValue(d->contentsX());
1060
d->signal_choke=false;
1062
QSize newVisibleSize(visibleWidth(), visibleHeight());
1063
if (d->clipped_viewport && oldVisibleSize != newVisibleSize) {
1064
QResizeEvent e(newVisibleSize, oldVisibleSize);
1065
viewportResizeEvent(&e);
1073
void Q3ScrollView::setVisible(bool visible)
1075
if (visible && !isVisible()) {
1076
QWidget::setVisible(visible);
1078
d->hideOrShowAll(this);
1080
QWidget::setVisible(visible);
1087
void Q3ScrollView::resize(int w, int h)
1089
QWidget::resize(w, h);
1095
void Q3ScrollView::resize(const QSize& s)
1097
resize(s.width(), s.height());
1103
void Q3ScrollView::resizeEvent(QResizeEvent* event)
1105
Q3Frame::resizeEvent(event);
1108
if (QApplication::reverseLayout()) {
1109
d->fake_scroll = true;
1110
scrollBy(-event->size().width() + event->oldSize().width(), 0);
1111
d->fake_scroll = false;
1115
bool inresize = d->inresize;
1118
d->inresize = inresize;
1119
d->scrollbar_timer.start(0, true);
1121
d->hideOrShowAll(this);
1129
void Q3ScrollView::mousePressEvent(QMouseEvent * e) //#### remove for 4.0
1137
void Q3ScrollView::mouseReleaseEvent(QMouseEvent *e) //#### remove for 4.0
1146
void Q3ScrollView::mouseDoubleClickEvent(QMouseEvent *e) //#### remove for 4.0
1154
void Q3ScrollView::mouseMoveEvent(QMouseEvent *e) //#### remove for 4.0
1162
#ifndef QT_NO_WHEELEVENT
1163
void Q3ScrollView::wheelEvent(QWheelEvent *e)
1165
QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()),
1166
e->globalPos(), e->delta(), e->state());
1167
viewportWheelEvent(&ce);
1168
if (!ce.isAccepted()) {
1169
if (e->orientation() == Horizontal && horizontalScrollBar())
1170
QApplication::sendEvent(horizontalScrollBar(), e);
1171
else if (e->orientation() == Vertical && verticalScrollBar())
1172
QApplication::sendEvent(verticalScrollBar(), e);
1182
void Q3ScrollView::contextMenuEvent(QContextMenuEvent *e)
1184
if (e->reason() != QContextMenuEvent::Keyboard) {
1189
QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()),
1190
e->globalPos(), e->state());
1191
viewportContextMenuEvent(&ce);
1192
if (ce.isAccepted())
1198
Q3ScrollView::ScrollBarMode Q3ScrollView::vScrollBarMode() const
1205
\enum Q3ScrollView::ScrollBarMode
1207
This enum type describes the various modes of Q3ScrollView's scroll
1210
\value Auto Q3ScrollView shows a scroll bar when the content is
1211
too large to fit and not otherwise. This is the default.
1213
\value AlwaysOff Q3ScrollView never shows a scroll bar.
1215
\value AlwaysOn Q3ScrollView always shows a scroll bar.
1217
(The modes for the horizontal and vertical scroll bars are
1223
\property Q3ScrollView::vScrollBarMode
1224
\brief the mode for the vertical scroll bar
1226
The default mode is \c Q3ScrollView::Auto.
1230
void Q3ScrollView::setVScrollBarMode(ScrollBarMode mode)
1232
if (d->vMode != mode) {
1240
\property Q3ScrollView::hScrollBarMode
1241
\brief the mode for the horizontal scroll bar
1243
The default mode is \c Q3ScrollView::Auto.
1247
Q3ScrollView::ScrollBarMode Q3ScrollView::hScrollBarMode() const
1252
void Q3ScrollView::setHScrollBarMode(ScrollBarMode mode)
1254
if (d->hMode != mode) {
1262
Returns the widget in the corner between the two scroll bars.
1264
By default, no corner widget is present.
1266
QWidget* Q3ScrollView::cornerWidget() const
1272
Sets the widget in the \a corner between the two scroll bars.
1274
You will probably also want to set at least one of the scroll bar
1275
modes to \c AlwaysOn.
1277
Passing 0 shows no widget in the corner.
1279
Any previous \a corner widget is hidden.
1281
You may call setCornerWidget() with the same widget at different
1284
All widgets set here will be deleted by the Q3ScrollView when it is
1285
destroyed unless you separately reparent the widget after setting
1286
some other corner widget (or 0).
1288
Any \e newly set widget should have no current parent.
1290
By default, no corner widget is present.
1292
\sa setVScrollBarMode(), setHScrollBarMode()
1294
void Q3ScrollView::setCornerWidget(QWidget* corner)
1296
QWidget* oldcorner = d->corner;
1297
if (oldcorner != corner) {
1298
if (oldcorner) oldcorner->hide();
1300
corner->setParent(this);
1302
if (corner) corner->show();
1307
void Q3ScrollView::setResizePolicy(ResizePolicy r)
1313
\property Q3ScrollView::resizePolicy
1314
\brief the resize policy
1316
The default is \c Default.
1320
Q3ScrollView::ResizePolicy Q3ScrollView::resizePolicy() const
1328
void Q3ScrollView::setEnabled(bool enable)
1330
Q3Frame::setEnabled(enable);
1334
Removes the \a child widget from the scrolled area. Note that this
1335
happens automatically if the \a child is deleted.
1337
void Q3ScrollView::removeChild(QWidget* child)
1339
if (!d || !child) // First check in case we are destructing
1342
QSVChildRec *r = d->rec(child);
1343
if (r) d->deleteChildRec(r);
1349
void Q3ScrollView::removeChild(QObject* child)
1351
Q3Frame::removeChild(child);
1355
Inserts the widget, \a child, into the scrolled area positioned at
1356
(\a x, \a y). The position defaults to (0, 0). If the child is
1357
already in the view, it is just moved.
1359
You may want to call enableClipper(true) if you add a large number
1362
void Q3ScrollView::addChild(QWidget* child, int x, int y)
1365
#if defined(QT_CHECK_NULL)
1366
qWarning("Q3ScrollView::addChild(): Cannot add null child");
1371
child->setBackgroundOrigin(WidgetOrigin);
1373
if (child->parentWidget() == viewport()) {
1374
// May already be there
1375
QSVChildRec *r = d->rec(child);
1377
r->moveTo(this,x,y,d->clipped_viewport);
1378
if (d->policy > Manual) {
1379
d->autoResizeHint(this);
1380
d->autoResize(this); // #### better to just deal with this one widget!
1386
if (d->children.isEmpty() && d->policy != Manual) {
1387
if (d->policy == Default)
1388
setResizePolicy(AutoOne);
1389
child->installEventFilter(this);
1390
} else if (d->policy == AutoOne) {
1391
child->removeEventFilter(this); //#### ?????
1392
setResizePolicy(Manual);
1394
if (child->parentWidget() != viewport()) {
1395
child->reparent(viewport(), 0, QPoint(0,0), false);
1397
d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport);
1399
if (d->policy > Manual) {
1400
d->autoResizeHint(this);
1401
d->autoResize(this); // #### better to just deal with this one widget!
1406
Repositions the \a child widget to (\a x, \a y). This function is
1407
the same as addChild().
1409
void Q3ScrollView::moveChild(QWidget* child, int x, int y)
1411
addChild(child,x,y);
1415
Returns the X position of the given \a child widget. Use this
1416
rather than QWidget::x() for widgets added to the view.
1418
This function returns 0 if \a child has not been added to the view.
1420
int Q3ScrollView::childX(QWidget* child)
1422
QSVChildRec *r = d->rec(child);
1423
return r ? r->x : 0;
1427
Returns the Y position of the given \a child widget. Use this
1428
rather than QWidget::y() for widgets added to the view.
1430
This function returns 0 if \a child has not been added to the view.
1432
int Q3ScrollView::childY(QWidget* child)
1434
QSVChildRec *r = d->rec(child);
1435
return r ? r->y : 0;
1438
/*! \fn bool Q3ScrollView::childIsVisible(QWidget*)
1441
Returns true if \a child is visible. This is equivalent
1442
to child->isVisible().
1445
/*! \fn void Q3ScrollView::showChild(QWidget* child, bool y)
1448
Sets the visibility of \a child. Equivalent to
1449
QWidget::show() or QWidget::hide().
1453
This event filter ensures the scroll bars are updated when a
1454
single contents widget is resized, shown, hidden or destroyed; it
1455
passes mouse events to the Q3ScrollView. The event is in \a e and
1456
the object is in \a obj.
1459
bool Q3ScrollView::eventFilter(QObject *obj, QEvent *e)
1462
return false; // we are destructing
1463
if (obj == d->viewport || obj == d->clipped_viewport) {
1464
switch (e->type()) {
1465
/* Forward many events to viewport...() functions */
1467
viewportPaintEvent((QPaintEvent*)e);
1469
case QEvent::Resize:
1470
if (!d->clipped_viewport)
1471
viewportResizeEvent((QResizeEvent *)e);
1473
case QEvent::MouseButtonPress:
1474
viewportMousePressEvent((QMouseEvent*)e);
1475
if (((QMouseEvent*)e)->isAccepted())
1478
case QEvent::MouseButtonRelease:
1479
viewportMouseReleaseEvent((QMouseEvent*)e);
1480
if (((QMouseEvent*)e)->isAccepted())
1483
case QEvent::MouseButtonDblClick:
1484
viewportMouseDoubleClickEvent((QMouseEvent*)e);
1485
if (((QMouseEvent*)e)->isAccepted())
1488
case QEvent::MouseMove:
1489
viewportMouseMoveEvent((QMouseEvent*)e);
1490
if (((QMouseEvent*)e)->isAccepted())
1493
#ifndef QT_NO_DRAGANDDROP
1494
case QEvent::DragEnter:
1495
viewportDragEnterEvent((QDragEnterEvent*)e);
1497
case QEvent::DragMove: {
1498
if (d->drag_autoscroll) {
1499
QPoint vp = ((QDragMoveEvent*) e)->pos();
1500
QRect inside_margin(autoscroll_margin, autoscroll_margin,
1501
visibleWidth() - autoscroll_margin * 2,
1502
visibleHeight() - autoscroll_margin * 2);
1503
if (!inside_margin.contains(vp)) {
1504
startDragAutoScroll();
1505
// Keep sending move events
1506
((QDragMoveEvent*)e)->accept(QRect(0,0,0,0));
1509
viewportDragMoveEvent((QDragMoveEvent*)e);
1511
case QEvent::DragLeave:
1512
stopDragAutoScroll();
1513
viewportDragLeaveEvent((QDragLeaveEvent*)e);
1516
stopDragAutoScroll();
1517
viewportDropEvent((QDropEvent*)e);
1519
#endif // QT_NO_DRAGANDDROP
1520
case QEvent::ContextMenu:
1521
viewportContextMenuEvent((QContextMenuEvent*)e);
1522
if (((QContextMenuEvent*)e)->isAccepted())
1525
case QEvent::ChildRemoved:
1526
removeChild((QWidget*)((QChildEvent*)e)->child());
1528
case QEvent::LayoutHint:
1529
d->autoResizeHint(this);
1534
} else if (d && d->rec((QWidget*)obj)) { // must be a child
1535
if (e->type() == QEvent::Resize)
1536
d->autoResize(this);
1537
else if (e->type() == QEvent::Move)
1540
return Q3Frame::eventFilter(obj, e); // always continue with standard event processing
1544
This event handler is called whenever the Q3ScrollView receives a
1545
mousePressEvent(): the press position in \a e is translated to be a point
1548
void Q3ScrollView::contentsMousePressEvent(QMouseEvent* e)
1554
This event handler is called whenever the Q3ScrollView receives a
1555
mouseReleaseEvent(): the release position in \a e is translated to be a
1556
point on the contents.
1558
void Q3ScrollView::contentsMouseReleaseEvent(QMouseEvent* e)
1564
This event handler is called whenever the Q3ScrollView receives a
1565
mouseDoubleClickEvent(): the click position in \a e is translated to be a
1566
point on the contents.
1568
The default implementation generates a normal mouse press event.
1570
void Q3ScrollView::contentsMouseDoubleClickEvent(QMouseEvent* e)
1572
contentsMousePressEvent(e); // try mouse press event
1576
This event handler is called whenever the Q3ScrollView receives a
1577
mouseMoveEvent(): the mouse position in \a e is translated to be a point
1580
void Q3ScrollView::contentsMouseMoveEvent(QMouseEvent* e)
1585
#ifndef QT_NO_DRAGANDDROP
1588
This event handler is called whenever the Q3ScrollView receives a
1589
dragEnterEvent(): the drag position is translated to be a point
1592
The default implementation does nothing. The \a event parameter is
1595
void Q3ScrollView::contentsDragEnterEvent(QDragEnterEvent * /* event */)
1600
This event handler is called whenever the Q3ScrollView receives a
1601
dragMoveEvent(): the drag position is translated to be a point on
1604
The default implementation does nothing. The \a event parameter is
1607
void Q3ScrollView::contentsDragMoveEvent(QDragMoveEvent * /* event */)
1612
This event handler is called whenever the Q3ScrollView receives a
1613
dragLeaveEvent(): the drag position is translated to be a point
1616
The default implementation does nothing. The \a event parameter is
1619
void Q3ScrollView::contentsDragLeaveEvent(QDragLeaveEvent * /* event */)
1624
This event handler is called whenever the Q3ScrollView receives a
1625
dropEvent(): the drop position is translated to be a point on the
1628
The default implementation does nothing. The \a event parameter is
1632
void Q3ScrollView::contentsDropEvent(QDropEvent * /* event */)
1636
#endif // QT_NO_DRAGANDDROP
1639
This event handler is called whenever the Q3ScrollView receives a
1640
wheelEvent() in \a{e}: the mouse position is translated to be a
1641
point on the contents.
1643
#ifndef QT_NO_WHEELEVENT
1644
void Q3ScrollView::contentsWheelEvent(QWheelEvent * e)
1650
This event handler is called whenever the Q3ScrollView receives a
1651
contextMenuEvent() in \a{e}: the mouse position is translated to
1652
be a point on the contents.
1654
void Q3ScrollView::contentsContextMenuEvent(QContextMenuEvent *e)
1660
This is a low-level painting routine that draws the viewport
1661
contents. Reimplement this if drawContents() is too high-level
1662
(for example, if you don't want to open a QPainter on the
1663
viewport). The paint event is passed in \a pe.
1665
void Q3ScrollView::viewportPaintEvent(QPaintEvent* pe)
1667
QWidget* vp = viewport();
1670
QRect r = pe->rect();
1672
if (d->clipped_viewport) {
1674
-d->clipped_viewport->x(), -d->clipped_viewport->y(),
1675
d->viewport->width(), d->viewport->height()
1679
int ex = r.x() + d->clipped_viewport->x() + d->contentsX();
1680
int ey = r.y() + d->clipped_viewport->y() + d->contentsY();
1682
int eh = r.height();
1683
drawContentsOffset(&p,
1684
d->contentsX()+d->clipped_viewport->x(),
1685
d->contentsY()+d->clipped_viewport->y(),
1689
r &= d->viewport->rect();
1690
int ex = r.x() + d->contentsX();
1691
int ey = r.y() + d->contentsY();
1693
int eh = r.height();
1694
drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh);
1700
To provide simple processing of events on the contents, this
1701
function receives all resize events sent to the viewport.
1703
The default implementation does nothing. The \a event parameter is
1706
\sa QWidget::resizeEvent()
1708
void Q3ScrollView::viewportResizeEvent(QResizeEvent * /* event */)
1714
To provide simple processing of events on the contents, this
1715
function receives all mouse press events sent to the viewport,
1716
translates the event and calls contentsMousePressEvent().
1718
\sa contentsMousePressEvent(), QWidget::mousePressEvent()
1720
void Q3ScrollView::viewportMousePressEvent(QMouseEvent* e)
1722
QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1723
e->globalPos(), e->button(), e->state());
1724
contentsMousePressEvent(&ce);
1725
if (!ce.isAccepted())
1731
To provide simple processing of events on the contents, this function
1732
receives all mouse release events sent to the viewport, translates
1733
the event and calls contentsMouseReleaseEvent().
1735
\sa QWidget::mouseReleaseEvent()
1737
void Q3ScrollView::viewportMouseReleaseEvent(QMouseEvent* e)
1739
QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1740
e->globalPos(), e->button(), e->state());
1741
contentsMouseReleaseEvent(&ce);
1742
if (!ce.isAccepted())
1748
To provide simple processing of events on the contents, this function
1749
receives all mouse double click events sent to the viewport,
1750
translates the event and calls contentsMouseDoubleClickEvent().
1752
\sa QWidget::mouseDoubleClickEvent()
1754
void Q3ScrollView::viewportMouseDoubleClickEvent(QMouseEvent* e)
1756
QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1757
e->globalPos(), e->button(), e->state());
1758
contentsMouseDoubleClickEvent(&ce);
1759
if (!ce.isAccepted())
1765
To provide simple processing of events on the contents, this function
1766
receives all mouse move events sent to the viewport, translates the
1767
event and calls contentsMouseMoveEvent().
1769
\sa QWidget::mouseMoveEvent()
1771
void Q3ScrollView::viewportMouseMoveEvent(QMouseEvent* e)
1773
QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1774
e->globalPos(), e->button(), e->state());
1775
contentsMouseMoveEvent(&ce);
1776
if (!ce.isAccepted())
1780
#ifndef QT_NO_DRAGANDDROP
1784
To provide simple processing of events on the contents, this function
1785
receives all drag enter events sent to the viewport, translates the
1786
event and calls contentsDragEnterEvent().
1788
\sa QWidget::dragEnterEvent()
1790
void Q3ScrollView::viewportDragEnterEvent(QDragEnterEvent* e)
1792
e->setPoint(viewportToContents(e->pos()));
1793
contentsDragEnterEvent(e);
1794
e->setPoint(contentsToViewport(e->pos()));
1799
To provide simple processing of events on the contents, this function
1800
receives all drag move events sent to the viewport, translates the
1801
event and calls contentsDragMoveEvent().
1803
\sa QWidget::dragMoveEvent()
1805
void Q3ScrollView::viewportDragMoveEvent(QDragMoveEvent* e)
1807
e->setPoint(viewportToContents(e->pos()));
1808
contentsDragMoveEvent(e);
1809
e->setPoint(contentsToViewport(e->pos()));
1814
To provide simple processing of events on the contents, this function
1815
receives all drag leave events sent to the viewport and calls
1816
contentsDragLeaveEvent().
1818
\sa QWidget::dragLeaveEvent()
1820
void Q3ScrollView::viewportDragLeaveEvent(QDragLeaveEvent* e)
1822
contentsDragLeaveEvent(e);
1827
To provide simple processing of events on the contents, this function
1828
receives all drop events sent to the viewport, translates the event
1829
and calls contentsDropEvent().
1831
\sa QWidget::dropEvent()
1833
void Q3ScrollView::viewportDropEvent(QDropEvent* e)
1835
e->setPoint(viewportToContents(e->pos()));
1836
contentsDropEvent(e);
1837
e->setPoint(contentsToViewport(e->pos()));
1840
#endif // QT_NO_DRAGANDDROP
1844
To provide simple processing of events on the contents, this function
1845
receives all wheel events sent to the viewport, translates the
1846
event and calls contentsWheelEvent().
1848
\sa QWidget::wheelEvent()
1850
#ifndef QT_NO_WHEELEVENT
1851
void Q3ScrollView::viewportWheelEvent(QWheelEvent* e)
1854
Different than standard mouse events, because wheel events might
1855
be sent to the focus widget if the widget-under-mouse doesn't want
1858
QWheelEvent ce(viewportToContents(e->pos()),
1859
e->globalPos(), e->delta(), e->state());
1860
contentsWheelEvent(&ce);
1861
if (ce.isAccepted())
1870
To provide simple processing of events on the contents, this function
1871
receives all context menu events sent to the viewport, translates the
1872
event and calls contentsContextMenuEvent().
1874
void Q3ScrollView::viewportContextMenuEvent(QContextMenuEvent *e)
1876
QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state());
1877
contentsContextMenuEvent(&ce);
1878
if (ce.isAccepted())
1885
Returns the component horizontal scroll bar. It is made available
1886
to allow accelerators, autoscrolling, etc.
1888
It should not be used for other purposes.
1890
This function never returns 0.
1892
QScrollBar* Q3ScrollView::horizontalScrollBar() const
1898
Returns the component vertical scroll bar. It is made available to
1899
allow accelerators, autoscrolling, etc.
1901
It should not be used for other purposes.
1903
This function never returns 0.
1905
QScrollBar* Q3ScrollView::verticalScrollBar() const {
1911
Scrolls the content so that the point (\a x, \a y) is visible with at
1912
least 50-pixel margins (if possible, otherwise centered).
1914
void Q3ScrollView::ensureVisible(int x, int y)
1916
ensureVisible(x, y, 50, 50);
1922
Scrolls the content so that the point (\a x, \a y) is visible with at
1923
least the \a xmargin and \a ymargin margins (if possible,
1924
otherwise centered).
1926
void Q3ScrollView::ensureVisible(int x, int y, int xmargin, int ymargin)
1928
int pw=visibleWidth();
1929
int ph=visibleHeight();
1931
int cx=-d->contentsX();
1932
int cy=-d->contentsY();
1933
int cw=d->contentsWidth();
1934
int ch=contentsHeight();
1950
if (x < -cx+xmargin)
1952
else if (x >= -cx+pw-xmargin)
1955
if (y < -cy+ymargin)
1957
else if (y >= -cy+ph-ymargin)
1962
else if (cx < pw-cw && cw>pw)
1967
else if (cy < ph-ch && ch>ph)
1970
setContentsPos(-cx, -cy);
1974
Scrolls the content so that the point (\a x, \a y) is in the top-left
1977
void Q3ScrollView::setContentsPos(int x, int y)
1980
// bounds checking...
1981
if (QApplication::reverseLayout())
1982
if (x > d->contentsWidth() - visibleWidth()) x = d->contentsWidth() - visibleWidth();
1987
// Choke signal handling while we update BOTH sliders.
1988
d->signal_choke=true;
1989
moveContents(-x, -y);
1990
d->vbar->setValue(y);
1991
d->hbar->setValue(x);
1992
d->signal_choke=false;
1996
Scrolls the content by \a dx to the left and \a dy upwards.
1998
void Q3ScrollView::scrollBy(int dx, int dy)
2000
setContentsPos(QMAX(d->contentsX()+dx, 0), QMAX(d->contentsY()+dy, 0));
2004
Scrolls the content so that the point (\a x, \a y) is in the center
2007
void Q3ScrollView::center(int x, int y)
2009
ensureVisible(x, y, 32000, 32000);
2015
Scrolls the content so that the point (\a x, \a y) is visible with
2016
the \a xmargin and \a ymargin margins (as fractions of visible
2021
\i Margin 0.0 allows (x, y) to be on the edge of the visible area.
2022
\i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area.
2023
\i Margin 1.0 ensures that (x, y) is in the center of the the visible area.
2026
void Q3ScrollView::center(int x, int y, float xmargin, float ymargin)
2028
int pw=visibleWidth();
2029
int ph=visibleHeight();
2030
ensureVisible(x, y, int(xmargin/2.0*pw+0.5), int(ymargin/2.0*ph+0.5));
2035
\fn void Q3ScrollView::contentsMoving(int x, int y)
2037
This signal is emitted just before the contents are moved to
2038
position (\a x, \a y).
2040
\sa contentsX(), contentsY()
2044
Moves the contents by (\a x, \a y).
2046
void Q3ScrollView::moveContents(int x, int y)
2048
if (-x+visibleWidth() > d->contentsWidth())
2050
if(QApplication::reverseLayout())
2051
x=QMAX(0,-d->contentsWidth()+visibleWidth());
2054
x=QMIN(0,-d->contentsWidth()+visibleWidth());
2055
if (-y+visibleHeight() > contentsHeight())
2056
y=QMIN(0,-contentsHeight()+visibleHeight());
2062
return; // Nothing to do
2064
emit contentsMoving(-x, -y);
2069
if (d->clipped_viewport || d->static_bg) {
2070
// Cheap move (usually)
2071
d->moveAllBy(dx,dy);
2072
} else if (/*dx && dy ||*/
2073
(QABS(dy) * 5 > visibleHeight() * 4) ||
2074
(QABS(dx) * 5 > visibleWidth() * 4)
2078
if (viewport()->updatesEnabled())
2079
viewport()->update();
2080
d->moveAllBy(dx,dy);
2081
} else if (!d->fake_scroll || d->contentsWidth() > visibleWidth()) {
2083
clipper()->scroll(dx,dy);
2085
d->hideOrShowAll(this, true);
2089
\property Q3ScrollView::contentsX
2090
\brief the X coordinate of the contents that are at the left edge of
2093
int Q3ScrollView::contentsX() const
2095
return d->contentsX();
2099
\property Q3ScrollView::contentsY
2100
\brief the Y coordinate of the contents that are at the top edge of
2103
int Q3ScrollView::contentsY() const
2105
return d->contentsY();
2109
\property Q3ScrollView::contentsWidth
2110
\brief the width of the contents area
2112
int Q3ScrollView::contentsWidth() const
2114
return d->contentsWidth();
2118
\property Q3ScrollView::contentsHeight
2119
\brief the height of the contents area
2121
int Q3ScrollView::contentsHeight() const
2127
Sets the size of the contents area to \a w pixels wide and \a h
2128
pixels high and updates the viewport accordingly.
2130
void Q3ScrollView::resizeContents(int w, int h)
2133
int oh = d->vheight;
2137
d->scrollbar_timer.start(0, true);
2139
if (d->children.isEmpty() && d->policy == Default)
2140
setResizePolicy(Manual);
2148
// Refresh area ow..w
2149
if (ow < visibleWidth() && w >= 0) {
2152
if (w > visibleWidth())
2154
clipper()->update(d->contentsX()+ow, 0, w-ow, visibleHeight());
2163
// Refresh area oh..h
2164
if (oh < visibleHeight() && h >= 0) {
2167
if (h > visibleHeight())
2168
h = visibleHeight();
2169
clipper()->update(0, d->contentsY()+oh, visibleWidth(), h-oh);
2174
Calls update() on a rectangle defined by \a x, \a y, \a w, \a h,
2175
translated appropriately. If the rectangle is not visible, nothing
2178
\sa repaintContents()
2180
void Q3ScrollView::updateContents(int x, int y, int w, int h)
2182
if (!isVisible() || !updatesEnabled())
2185
QWidget* vp = viewport();
2188
x -= d->contentsX();
2189
y -= d->contentsY();
2202
if (x > visibleWidth() || y > visibleHeight())
2205
if (w > visibleWidth())
2207
if (h > visibleHeight())
2208
h = visibleHeight();
2210
if (d->clipped_viewport) {
2211
// Translate clipper() to viewport()
2212
x -= d->clipped_viewport->x();
2213
y -= d->clipped_viewport->y();
2216
vp->update(x, y, w, h);
2222
Updates the contents in rectangle \a r
2224
void Q3ScrollView::updateContents(const QRect& r)
2226
updateContents(r.x(), r.y(), r.width(), r.height());
2232
void Q3ScrollView::updateContents()
2234
updateContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight());
2240
Repaints the contents of rectangle \a r. If \a erase is true the
2241
background is cleared using the background color.
2243
void Q3ScrollView::repaintContents(const QRect& r, bool erase)
2245
repaintContents(r.x(), r.y(), r.width(), r.height(), erase);
2252
Repaints the contents. If \a erase is true the background is
2253
cleared using the background color.
2255
void Q3ScrollView::repaintContents(bool erase)
2257
repaintContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase);
2262
Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h,
2263
translated appropriately. If the rectangle is not visible, nothing
2264
is repainted. If \a erase is true the background is cleared using
2265
the background color.
2267
\sa updateContents()
2269
void Q3ScrollView::repaintContents(int x, int y, int w, int h, bool erase)
2271
if (!isVisible() || !updatesEnabled())
2274
QWidget* vp = viewport();
2276
// Translate logical to clipper()
2277
x -= d->contentsX();
2278
y -= d->contentsY();
2291
if (w > visibleWidth())
2293
if (h > visibleHeight())
2294
h = visibleHeight();
2296
if (d->clipped_viewport) {
2297
// Translate clipper() to viewport()
2298
x -= d->clipped_viewport->x();
2299
y -= d->clipped_viewport->y();
2302
vp->repaint(x, y, w, h, erase);
2307
For backward-compatibility only. It is easier to use
2308
drawContents(QPainter*,int,int,int,int).
2310
The default implementation translates the painter appropriately
2311
and calls drawContents(QPainter*,int,int,int,int). See
2312
drawContents() for an explanation of the parameters \a p, \a
2313
offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph.
2315
void Q3ScrollView::drawContentsOffset(QPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph)
2317
p->translate(-offsetx,-offsety);
2318
drawContents(p, clipx, clipy, clipw, cliph);
2322
\fn void Q3ScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph)
2324
Reimplement this function if you are viewing a drawing area rather
2327
The function should draw the rectangle (\a clipx, \a clipy, \a
2328
clipw, \a cliph) of the contents using painter \a p. The clip
2329
rectangle is in the scrollview's coordinates.
2334
// Fill a 40000 by 50000 rectangle at (100000,150000)
2336
// Calculate the coordinates...
2337
int x1 = 100000, y1 = 150000;
2338
int x2 = x1+40000-1, y2 = y1+50000-1;
2340
// Clip the coordinates so X/Windows will not have problems...
2341
if (x1 < clipx) x1=clipx;
2342
if (y1 < clipy) y1=clipy;
2343
if (x2 > clipx+clipw-1) x2=clipx+clipw-1;
2344
if (y2 > clipy+cliph-1) y2=clipy+cliph-1;
2346
// Paint using the small coordinates...
2347
if (x2 >= x1 && y2 >= y1)
2348
p->fillRect(x1, y1, x2-x1+1, y2-y1+1, red);
2352
The clip rectangle and translation of the painter \a p is already
2355
void Q3ScrollView::drawContents(QPainter*, int, int, int, int)
2363
void Q3ScrollView::frameChanged()
2370
Returns the viewport widget of the scrollview. This is the widget
2371
containing the contents widget or which is the drawing area.
2373
QWidget* Q3ScrollView::viewport() const
2375
if (d->clipped_viewport)
2376
return d->clipped_viewport;
2381
Returns the clipper widget. Contents in the scrollview are
2382
ultimately clipped to be inside the clipper widget.
2384
You should not need to use this function.
2386
\sa visibleWidth(), visibleHeight()
2388
QWidget* Q3ScrollView::clipper() const
2394
\property Q3ScrollView::visibleWidth
2395
\brief the horizontal amount of the content that is visible
2397
int Q3ScrollView::visibleWidth() const
2399
return clipper()->width();
2403
\property Q3ScrollView::visibleHeight
2404
\brief the vertical amount of the content that is visible
2406
int Q3ScrollView::visibleHeight() const
2408
return clipper()->height();
2412
void Q3ScrollView::changeFrameRect(const QRect& r)
2414
QRect oldr = frameRect();
2416
QRect cr = contentsRect();
2417
QRegion fr(frameRect());
2418
fr = fr.subtract(contentsRect());
2421
cr = cr.intersect(contentsRect());
2422
fr = fr.unite(frameRect());
2423
fr = fr.subtract(cr);
2432
Sets the margins around the scrolling area to \a left, \a top, \a
2433
right and \a bottom. This is useful for applications such as
2434
spreadsheets with "locked" rows and columns. The marginal space is
2435
\e inside the frameRect() and is left blank; reimplement
2436
drawFrame() or put widgets in the unused area.
2438
By default all margins are zero.
2442
void Q3ScrollView::setMargins(int left, int top, int right, int bottom)
2444
if (left == d->l_marg &&
2446
right == d->r_marg &&
2447
bottom == d->b_marg)
2459
Returns the left margin.
2463
int Q3ScrollView::leftMargin() const
2470
Returns the top margin.
2474
int Q3ScrollView::topMargin() const
2481
Returns the right margin.
2485
int Q3ScrollView::rightMargin() const
2492
Returns the bottom margin.
2496
int Q3ScrollView::bottomMargin() const
2504
bool Q3ScrollView::focusNextPrevChild(bool next)
2506
// Makes sure that the new focus widget is on-screen, if
2507
// necessary by scrolling the scroll view.
2508
bool retval = Q3Frame::focusNextPrevChild(next);
2510
QWidget *w = window()->focusWidget();
2511
if (isAncestorOf(w)) {
2512
QSVChildRec *r = d->ancestorRec(w);
2513
if (r && (r->child == w || w->isVisibleTo(r->child))) {
2514
QPoint cp = r->child->mapToGlobal(QPoint(0, 0));
2515
QPoint cr = w->mapToGlobal(QPoint(0, 0)) - cp;
2516
ensureVisible(r->x + cr.x() + w->width()/2, r->y + cr.y() + w->height()/2,
2517
w->width()/2, w->height()/2);
2527
When a large numbers of child widgets are in a scrollview,
2528
especially if they are close together, the scrolling performance
2529
can suffer greatly. If \a y is true the scrollview will use an
2530
extra widget to group child widgets.
2532
Note that you may only call enableClipper() prior to adding
2535
void Q3ScrollView::enableClipper(bool y)
2537
if (!d->clipped_viewport == !y)
2539
if (d->children.count())
2540
qFatal("May only call Q3ScrollView::enableClipper() before adding widgets");
2542
d->clipped_viewport = new QClipperWidget(clipper(), "qt_clipped_viewport", QFlag(d->flags));
2543
d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2,
2544
coord_limit,coord_limit);
2545
d->clipped_viewport->setBackgroundMode(d->viewport->backgroundMode());
2546
d->viewport->setBackgroundMode(NoBackground); // no exposures for this
2547
d->viewport->removeEventFilter(this);
2548
d->clipped_viewport->installEventFilter(this);
2549
d->clipped_viewport->show();
2551
delete d->clipped_viewport;
2552
d->clipped_viewport = 0;
2557
Sets the scrollview to have a static background if \a y is true,
2558
or a scrolling background if \a y is false. By default, the
2559
background is scrolling.
2561
Be aware that this mode is quite slow, as a full repaint of the
2562
visible area has to be triggered on every contents move.
2564
\sa hasStaticBackground()
2566
void Q3ScrollView::setStaticBackground(bool y)
2572
Returns true if Q3ScrollView uses a static background; otherwise
2575
\sa setStaticBackground()
2577
bool Q3ScrollView::hasStaticBackground() const
2579
return d->static_bg;
2585
Returns the point \a p translated to a point on the viewport()
2588
QPoint Q3ScrollView::contentsToViewport(const QPoint& p) const
2590
if (d->clipped_viewport) {
2591
return QPoint(p.x() - d->contentsX() - d->clipped_viewport->x(),
2592
p.y() - d->contentsY() - d->clipped_viewport->y());
2594
return QPoint(p.x() - d->contentsX(),
2595
p.y() - d->contentsY());
2602
Returns the point on the viewport \a vp translated to a point in
2605
QPoint Q3ScrollView::viewportToContents(const QPoint& vp) const
2607
if (d->clipped_viewport) {
2608
return QPoint(vp.x() + d->contentsX() + d->clipped_viewport->x(),
2609
vp.y() + d->contentsY() + d->clipped_viewport->y());
2611
return QPoint(vp.x() + d->contentsX(),
2612
vp.y() + d->contentsY());
2618
Translates a point (\a x, \a y) in the contents to a point (\a vx,
2619
\a vy) on the viewport() widget.
2621
void Q3ScrollView::contentsToViewport(int x, int y, int& vx, int& vy) const
2623
const QPoint v = contentsToViewport(QPoint(x,y));
2629
Translates a point (\a vx, \a vy) on the viewport() widget to a
2630
point (\a x, \a y) in the contents.
2632
void Q3ScrollView::viewportToContents(int vx, int vy, int& x, int& y) const
2634
const QPoint c = viewportToContents(QPoint(vx,vy));
2642
QSize Q3ScrollView::sizeHint() const
2644
if (d->use_cached_size_hint && d->cachedSizeHint.isValid())
2645
return d->cachedSizeHint;
2648
int f = 2 * frameWidth();
2649
int h = fontMetrics().height();
2651
if (d->policy > Manual) {
2652
QSVChildRec *r = d->children.first();
2654
QSize cs = r->child->sizeHint();
2656
sz += cs.boundedTo(r->child->maximumSize());
2658
sz += r->child->size();
2661
sz += QSize(d->contentsWidth(), contentsHeight());
2663
if (d->hMode == AlwaysOn)
2664
sz.setWidth(sz.width() + d->hbar->sizeHint().width());
2665
if (d->vMode == AlwaysOn)
2666
sz.setHeight(sz.height() + d->hbar->sizeHint().height());
2667
return sz.expandedTo(QSize(12 * h, 8 * h))
2668
.boundedTo(QSize(36 * h, 24 * h));
2675
QSize Q3ScrollView::minimumSizeHint() const
2677
int h = fontMetrics().height();
2680
int f = 2 * frameWidth();
2681
return QSize((6 * h) + f, (4 * h) + f);
2688
(Implemented to get rid of a compiler warning.)
2690
void Q3ScrollView::drawContents(QPainter *)
2694
#ifndef QT_NO_DRAGANDDROP
2699
void Q3ScrollView::startDragAutoScroll()
2701
if (!d->autoscroll_timer.isActive()) {
2702
d->autoscroll_time = initialScrollTime;
2703
d->autoscroll_accel = initialScrollAccel;
2704
d->autoscroll_timer.start(d->autoscroll_time);
2712
void Q3ScrollView::stopDragAutoScroll()
2714
d->autoscroll_timer.stop();
2721
void Q3ScrollView::doDragAutoScroll()
2723
QPoint p = d->viewport->mapFromGlobal(QCursor::pos());
2725
if (d->autoscroll_accel-- <= 0 && d->autoscroll_time) {
2726
d->autoscroll_accel = initialScrollAccel;
2727
d->autoscroll_time--;
2728
d->autoscroll_timer.start(d->autoscroll_time);
2730
int l = QMAX(1, (initialScrollTime- d->autoscroll_time));
2733
if (p.y() < autoscroll_margin) {
2735
} else if (p.y() > visibleHeight() - autoscroll_margin) {
2738
if (p.x() < autoscroll_margin) {
2740
} else if (p.x() > visibleWidth() - autoscroll_margin) {
2746
stopDragAutoScroll();
2752
\property Q3ScrollView::dragAutoScroll
2753
\brief whether autoscrolling in drag move events is enabled
2755
If this property is set to true (the default), the Q3ScrollView
2756
automatically scrolls the contents in drag move events if the user
2757
moves the cursor close to a border of the view. Of course this
2758
works only if the viewport accepts drops. Specifying false
2759
disables this autoscroll feature.
2762
void Q3ScrollView::setDragAutoScroll(bool b)
2764
d->drag_autoscroll = b;
2767
bool Q3ScrollView::dragAutoScroll() const
2769
return d->drag_autoscroll;
2772
#endif // QT_NO_DRAGANDDROP
2776
void Q3ScrollView::setCachedSizeHint(const QSize &sh) const
2778
if (isVisible() && !d->cachedSizeHint.isValid())
2779
d->cachedSizeHint = sh;
2784
void Q3ScrollView::disableSizeHintCaching()
2786
d->use_cached_size_hint = false;
2791
QSize Q3ScrollView::cachedSizeHint() const
2793
return d->use_cached_size_hint ? d->cachedSizeHint : QSize();
2796
#endif // QT_NO_SCROLLVIEW