summaryrefslogtreecommitdiffstats
path: root/src/qt3support/widgets/q3scrollview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt3support/widgets/q3scrollview.cpp')
-rw-r--r--src/qt3support/widgets/q3scrollview.cpp2807
1 files changed, 2807 insertions, 0 deletions
diff --git a/src/qt3support/widgets/q3scrollview.cpp b/src/qt3support/widgets/q3scrollview.cpp
new file mode 100644
index 0000000..ea45d6f
--- /dev/null
+++ b/src/qt3support/widgets/q3scrollview.cpp
@@ -0,0 +1,2807 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidget.h"
+#ifndef QT_NO_SCROLLVIEW
+#include "qscrollbar.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qcursor.h"
+#include "q3scrollview.h"
+#include "q3ptrdict.h"
+#include "qapplication.h"
+#include "qtimer.h"
+#include "qstyle.h"
+#include "q3ptrlist.h"
+#include "qevent.h"
+#include "q3listview.h"
+#ifdef Q_WS_MAC
+# include "private/qt_mac_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt;
+
+static const int coord_limit = 4000;
+static const int autoscroll_margin = 16;
+static const int initialScrollTime = 30;
+static const int initialScrollAccel = 5;
+
+struct QSVChildRec {
+ QSVChildRec(QWidget* c, int xx, int yy) :
+ child(c),
+ x(xx), y(yy)
+ {
+ }
+
+ void hideOrShow(Q3ScrollView* sv, QWidget* clipped_viewport);
+ void moveTo(Q3ScrollView* sv, int xx, int yy, QWidget* clipped_viewport)
+ {
+ if (x != xx || y != yy) {
+ x = xx;
+ y = yy;
+ hideOrShow(sv,clipped_viewport);
+ }
+ }
+ QWidget* child;
+ int x, y;
+};
+
+void QSVChildRec::hideOrShow(Q3ScrollView* sv, QWidget* clipped_viewport)
+{
+ if (clipped_viewport) {
+ if (x+child->width() < sv->contentsX()+clipped_viewport->x()
+ || x > sv->contentsX()+clipped_viewport->width()
+ || y+child->height() < sv->contentsY()+clipped_viewport->y()
+ || y > sv->contentsY()+clipped_viewport->height()) {
+ child->move(clipped_viewport->width(),
+ clipped_viewport->height());
+ } else {
+ child->move(x-sv->contentsX()-clipped_viewport->x(),
+ y-sv->contentsY()-clipped_viewport->y());
+ }
+ } else {
+ child->move(x-sv->contentsX(), y-sv->contentsY());
+ }
+}
+
+class QAbstractScrollAreaWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QAbstractScrollAreaWidget(Q3ScrollView* parent=0, const char* name=0, Qt::WindowFlags f = 0)
+ : QWidget(parent, name, f)
+ {
+ setAutoFillBackground(true);
+ }
+};
+
+class QClipperWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QClipperWidget(QWidget * parent=0, const char * name=0, Qt::WindowFlags f=0)
+ : QWidget (parent,name,f) {}
+};
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "q3scrollview.moc"
+QT_END_INCLUDE_NAMESPACE
+
+class Q3ScrollViewData {
+public:
+ Q3ScrollViewData(Q3ScrollView* parent, int vpwflags) :
+ hbar(new QScrollBar(Qt::Horizontal, parent, "qt_hbar")),
+ vbar(new QScrollBar(Qt::Vertical, parent, "qt_vbar")),
+ viewport(new QAbstractScrollAreaWidget(parent, "qt_viewport", QFlag(vpwflags))),
+ clipped_viewport(0),
+ flags(vpwflags),
+ vx(0), vy(0), vwidth(1), vheight(1),
+#ifndef QT_NO_DRAGANDDROP
+ autoscroll_timer(parent, "scrollview autoscroll timer"),
+ drag_autoscroll(true),
+#endif
+ scrollbar_timer(parent, "scrollview scrollbar timer"),
+ inresize(false), use_cached_size_hint(true)
+ {
+ l_marg = r_marg = t_marg = b_marg = 0;
+ viewport->polish();
+ vMode = Q3ScrollView::Auto;
+ hMode = Q3ScrollView::Auto;
+ corner = 0;
+ vbar->setSteps(20, 1/*set later*/);
+ hbar->setSteps(20, 1/*set later*/);
+ policy = Q3ScrollView::Default;
+ signal_choke = false;
+ static_bg = false;
+ fake_scroll = false;
+ hbarPressed = false;
+ vbarPressed = false;
+ hbar->setLayoutDirection(Qt::LeftToRight);
+ }
+ ~Q3ScrollViewData();
+
+ QSVChildRec* rec(QWidget* w) { return childDict.find(w); }
+ QSVChildRec* ancestorRec(QWidget* w);
+ QSVChildRec* addChildRec(QWidget* w, int x, int y)
+ {
+ QSVChildRec *r = new QSVChildRec(w,x,y);
+ children.append(r);
+ childDict.insert(w, r);
+ return r;
+ }
+ void deleteChildRec(QSVChildRec* r)
+ {
+ childDict.remove(r->child);
+ children.removeRef(r);
+ delete r;
+ }
+
+ void hideOrShowAll(Q3ScrollView* sv, bool isScroll = false);
+ void moveAllBy(int dx, int dy);
+ bool anyVisibleChildren();
+ void autoMove(Q3ScrollView* sv);
+ void autoResize(Q3ScrollView* sv);
+ void autoResizeHint(Q3ScrollView* sv);
+ void viewportResized(int w, int h);
+
+ QScrollBar* hbar;
+ QScrollBar* vbar;
+ bool hbarPressed;
+ bool vbarPressed;
+ QAbstractScrollAreaWidget* viewport;
+ QClipperWidget* clipped_viewport;
+ int flags;
+ Q3PtrList<QSVChildRec> children;
+ Q3PtrDict<QSVChildRec> childDict;
+ QWidget* corner;
+ int vx, vy, vwidth, vheight; // for drawContents-style usage
+ int l_marg, r_marg, t_marg, b_marg;
+ Q3ScrollView::ResizePolicy policy;
+ Q3ScrollView::ScrollBarMode vMode;
+ Q3ScrollView::ScrollBarMode hMode;
+#ifndef QT_NO_DRAGANDDROP
+ QPoint cpDragStart;
+ QTimer autoscroll_timer;
+ int autoscroll_time;
+ int autoscroll_accel;
+ bool drag_autoscroll;
+#endif
+ QTimer scrollbar_timer;
+
+ uint static_bg : 1;
+ uint fake_scroll : 1;
+
+ // This variable allows ensureVisible to move the contents then
+ // update both the sliders. Otherwise, updating the sliders would
+ // cause two image scrolls, creating ugly flashing.
+ //
+ uint signal_choke : 1;
+
+ // This variables indicates in updateScrollBars() that we are
+ // in a resizeEvent() and thus don't want to flash scroll bars
+ uint inresize : 1;
+ uint use_cached_size_hint : 1;
+ QSize cachedSizeHint;
+
+ inline int contentsX() const { return -vx; }
+ inline int contentsY() const { return -vy; }
+ inline int contentsWidth() const { return vwidth; }
+};
+
+inline Q3ScrollViewData::~Q3ScrollViewData()
+{
+ children.setAutoDelete(true);
+}
+
+QSVChildRec* Q3ScrollViewData::ancestorRec(QWidget* w)
+{
+ if (clipped_viewport) {
+ while (w->parentWidget() != clipped_viewport) {
+ w = w->parentWidget();
+ if (!w) return 0;
+ }
+ } else {
+ while (w->parentWidget() != viewport) {
+ w = w->parentWidget();
+ if (!w) return 0;
+ }
+ }
+ return rec(w);
+}
+
+void Q3ScrollViewData::hideOrShowAll(Q3ScrollView* sv, bool isScroll)
+{
+ if (!clipped_viewport)
+ return;
+ if (clipped_viewport->x() <= 0
+ && clipped_viewport->y() <= 0
+ && clipped_viewport->width()+clipped_viewport->x() >=
+ viewport->width()
+ && clipped_viewport->height()+clipped_viewport->y() >=
+ viewport->height()) {
+ // clipped_viewport still covers viewport
+ if(static_bg)
+ clipped_viewport->repaint(true);
+ else if ((!isScroll && !clipped_viewport->testAttribute(Qt::WA_StaticContents)) || static_bg)
+ clipped_viewport->update();
+ } else {
+ // Re-center
+ int nx = (viewport->width() - clipped_viewport->width()) / 2;
+ int ny = (viewport->height() - clipped_viewport->height()) / 2;
+ clipped_viewport->move(nx,ny);
+ clipped_viewport->update();
+ }
+ for (QSVChildRec *r = children.first(); r; r=children.next()) {
+ r->hideOrShow(sv, clipped_viewport);
+ }
+}
+
+void Q3ScrollViewData::moveAllBy(int dx, int dy)
+{
+ if (clipped_viewport && !static_bg) {
+ clipped_viewport->move(clipped_viewport->x()+dx,
+ clipped_viewport->y()+dy);
+ } else {
+ for (QSVChildRec *r = children.first(); r; r=children.next()) {
+ r->child->move(r->child->x()+dx,r->child->y()+dy);
+ }
+ if (static_bg)
+ viewport->repaint(true);
+ }
+}
+
+bool Q3ScrollViewData::anyVisibleChildren()
+{
+ for (QSVChildRec *r = children.first(); r; r=children.next()) {
+ if (r->child->isVisible()) return true;
+ }
+ return false;
+}
+
+void Q3ScrollViewData::autoMove(Q3ScrollView* sv)
+{
+ if (policy == Q3ScrollView::AutoOne) {
+ QSVChildRec* r = children.first();
+ if (r)
+ sv->setContentsPos(-r->child->x(),-r->child->y());
+ }
+}
+
+void Q3ScrollViewData::autoResize(Q3ScrollView* sv)
+{
+ if (policy == Q3ScrollView::AutoOne) {
+ QSVChildRec* r = children.first();
+ if (r)
+ sv->resizeContents(r->child->width(),r->child->height());
+ }
+}
+
+void Q3ScrollViewData::autoResizeHint(Q3ScrollView* sv)
+{
+ if (policy == Q3ScrollView::AutoOne) {
+ QSVChildRec* r = children.first();
+ if (r) {
+ QSize s = r->child->sizeHint();
+ if (s.isValid())
+ r->child->resize(s);
+ }
+ } else if (policy == Q3ScrollView::AutoOneFit) {
+ QSVChildRec* r = children.first();
+ if (r) {
+ QSize sh = r->child->sizeHint();
+ sh = sh.boundedTo(r->child->maximumSize());
+ sv->resizeContents(sh.width(), sh.height());
+ }
+ }
+}
+
+void Q3ScrollViewData::viewportResized(int w, int h)
+{
+ if (policy == Q3ScrollView::AutoOneFit) {
+ QSVChildRec* r = children.first();
+ if (r) {
+ QSize sh = r->child->sizeHint();
+ sh = sh.boundedTo(r->child->maximumSize());
+ r->child->resize(QMAX(w,sh.width()), QMAX(h,sh.height()));
+ }
+
+ }
+}
+
+
+/*!
+ \class Q3ScrollView
+ \brief The Q3ScrollView widget provides a scrolling area with on-demand scroll bars.
+
+ \compat
+
+ The Q3ScrollView is a large canvas - potentially larger than the
+ coordinate system normally supported by the underlying window
+ system. This is important because it is quite easy to go beyond
+ these limitations (e.g. many web pages are more than 32000 pixels
+ high). Additionally, the Q3ScrollView can have QWidgets positioned
+ on it that scroll around with the drawn content. These sub-widgets
+ can also have positions outside the normal coordinate range (but
+ they are still limited in size).
+
+ To provide content for the widget, inherit from Q3ScrollView,
+ reimplement drawContents() and use resizeContents() to set the
+ size of the viewed area. Use addChild() and moveChild() to
+ position widgets on the view.
+
+ To use Q3ScrollView effectively it is important to understand its
+ widget structure in the three styles of use: a single large child
+ widget, a large panning area with some widgets and a large panning
+ area with many widgets.
+
+ \section1 Using One Big Widget
+
+ \img qscrollview-vp2.png
+
+ The first, simplest usage of Q3ScrollView (depicted above), is
+ appropriate for scrolling areas that are never more than about
+ 4000 pixels in either dimension (this is about the maximum
+ reliable size on X11 servers). In this usage, you just make one
+ large child in the Q3ScrollView. The child should be a child of the
+ viewport() of the scrollview and be added with addChild():
+ \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 0
+ You can go on to add arbitrary child widgets to the single child
+ in the scrollview as you would with any widget:
+ \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 1
+
+ Here the Q3ScrollView has four children: the viewport(), the
+ verticalScrollBar(), the horizontalScrollBar() and a small
+ cornerWidget(). The viewport() has one child: the QWidget. The
+ QWidget has the three QLabel objects as child widgets. When the view
+ is scrolled, the QWidget is moved; its children move with it as
+ child widgets normally do.
+
+ \section1 Using a Very Big View with Some Widgets
+
+ \img qscrollview-vp.png
+
+ The second usage of Q3ScrollView (depicted above) is appropriate
+ when few, if any, widgets are on a very large scrolling area that
+ is potentially larger than 4000 pixels in either dimension. In
+ this usage you call resizeContents() to set the size of the area
+ and reimplement drawContents() to paint the contents. You may also
+ add some widgets by making them children of the viewport() and
+ adding them with addChild() (this is the same as the process for
+ the single large widget in the previous example):
+ \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 2
+ Here, the Q3ScrollView has the same four children: the viewport(),
+ the verticalScrollBar(), the horizontalScrollBar() and a small
+ cornerWidget(). The viewport() has the three QLabel objects as
+ child widgets. When the view is scrolled, the scrollview moves the
+ child widgets individually.
+
+ \section1 Using a Very Big View with Many Widgets
+
+ \img qscrollview-cl.png
+
+ The final usage of Q3ScrollView (depicted above) is appropriate
+ when many widgets are on a very large scrolling area that is
+ potentially larger than 4000 pixels in either dimension. In this
+ usage you call resizeContents() to set the size of the area and
+ reimplement drawContents() to paint the contents. You then call
+ enableClipper(true) and add widgets, again by making them children
+ of the viewport(), and adding them with addChild():
+ \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 3
+
+ Here, the Q3ScrollView has four children: the clipper() (not the
+ viewport() this time), the verticalScrollBar(), the
+ horizontalScrollBar() and a small cornerWidget(). The clipper()
+ has one child: the viewport(). The viewport() has the same three
+ labels as child widgets. When the view is scrolled the viewport()
+ is moved; its children move with it as child widgets normally do.
+
+ \target allviews
+ \section1 Details Relevant for All Views
+
+ Normally you will use the first or third method if you want any
+ child widgets in the view.
+
+ Note that the widget you see in the scrolled area is the
+ viewport() widget, not the Q3ScrollView itself. So to turn mouse
+ tracking on, for example, use viewport()->setMouseTracking(true).
+
+ To enable drag-and-drop, you would setAcceptDrops(true) on the
+ Q3ScrollView (because drag-and-drop events propagate to the
+ parent). But to work out the logical position in the view, you
+ would need to map the drop co-ordinate from being relative to the
+ Q3ScrollView to being relative to the contents; use the function
+ viewportToContents() for this.
+
+ To handle mouse events on the scrolling area, subclass scrollview
+ as you would subclass other widgets, but rather than
+ reimplementing mousePressEvent(), reimplement
+ contentsMousePressEvent() instead. The contents specific event
+ handlers provide translated events in the coordinate system of the
+ scrollview. If you reimplement mousePressEvent(), you'll get
+ called only when part of the Q3ScrollView is clicked: and the only
+ such part is the "corner" (if you don't set a cornerWidget()) and
+ the frame; everything else is covered up by the viewport, clipper
+ or scroll bars.
+
+ When you construct a Q3ScrollView, some of the window flags apply
+ to the viewport() instead of being sent to the QWidget constructor
+ for the Q3ScrollView.
+
+ \list
+
+ \i An image-manipulation widget would use \c
+ WNoAutoErase|WStaticContents because the widget draws all pixels
+ itself, and when its size increases, it only needs a paint event
+ for the new part because the old part remains unchanged.
+
+ \i A scrolling game widget in which the background scrolls as the
+ characters move might use \c WNoAutoErase (in addition to \c
+ WStaticContents) so that the window system background does not
+ flash in and out during scrolling.
+
+ \i A word processing widget might use \c WNoAutoErase and repaint
+ itself line by line to get a less-flickery resizing. If the widget
+ is in a mode in which no text justification can take place, it
+ might use \c WStaticContents too, so that it would only get a
+ repaint for the newly visible parts.
+
+ \endlist
+
+ Child widgets may be moved using addChild() or moveChild(). Use
+ childX() and childY() to get the position of a child widget.
+
+ A widget may be placed in the corner between the vertical and
+ horizontal scroll bars with setCornerWidget(). You can get access
+ to the scroll bars using horizontalScrollBar() and
+ verticalScrollBar(), and to the viewport with viewport(). The
+ scroll view can be scrolled using scrollBy(), ensureVisible(),
+ setContentsPos() or center().
+
+ The visible area is given by visibleWidth() and visibleHeight(),
+ and the contents area by contentsWidth() and contentsHeight(). The
+ contents may be repainted using one of the repaintContents() or
+ updateContents() functions.
+
+ Coordinate conversion is provided by contentsToViewport() and
+ viewportToContents().
+
+ The contentsMoving() signal is emitted just before the contents
+ are moved to a new position.
+
+ \warning Q3ScrollView currently does not erase the background when
+ resized, i.e. you must always clear the background manually in
+ scrollview subclasses. This will change in a future version of Qt
+ and we recommend specifying the \c WNoAutoErase flag explicitly.
+*/
+
+
+/*!
+ \enum Q3ScrollView::ResizePolicy
+
+ This enum type is used to control a Q3ScrollView's reaction to
+ resize events.
+
+ \value Default the Q3ScrollView selects one of the other settings
+ automatically when it has to. In this version of Qt, Q3ScrollView
+ changes to \c Manual if you resize the contents with
+ resizeContents() and to \c AutoOne if a child is added.
+
+ \value Manual the contents stays the size set by resizeContents().
+
+ \value AutoOne if there is only one child widget the contents stays
+ the size of that widget. Otherwise the behavior is undefined.
+
+ \value AutoOneFit if there is only one child widget the contents stays
+ the size of that widget's sizeHint(). If the scrollview is resized
+ larger than the child's sizeHint(), the child will be resized to
+ fit. If there is more than one child, the behavior is undefined.
+
+*/
+//#### The widget will be resized to its sizeHint() when a LayoutHint event
+//#### is received
+
+/*!
+ Constructs a Q3ScrollView called \a name with parent \a parent and
+ widget flags \a f.
+
+ The widget flags \c WStaticContents, \c WNoAutoErase and \c
+ WPaintClever are propagated to the viewport() widget. The other
+ widget flags are propagated to the parent constructor as usual.
+*/
+
+Q3ScrollView::Q3ScrollView(QWidget *parent, const char *name, Qt::WindowFlags f) :
+ Q3Frame(parent, name, f & (~WStaticContents) & (~WNoAutoErase) & (~WResizeNoErase))
+{
+ WindowFlags flags = WResizeNoErase | (f&WPaintClever) | (f&WRepaintNoErase) | (f&WStaticContents);
+ d = new Q3ScrollViewData(this, flags);
+
+#ifndef QT_NO_DRAGANDDROP
+ connect(&d->autoscroll_timer, SIGNAL(timeout()),
+ this, SLOT(doDragAutoScroll()));
+#endif
+
+ connect(d->hbar, SIGNAL(valueChanged(int)),
+ this, SLOT(hslide(int)));
+ connect(d->vbar, SIGNAL(valueChanged(int)),
+ this, SLOT(vslide(int)));
+
+ connect(d->hbar, SIGNAL(sliderPressed()), this, SLOT(hbarIsPressed()));
+ connect(d->hbar, SIGNAL(sliderReleased()), this, SLOT(hbarIsReleased()));
+ connect(d->vbar, SIGNAL(sliderPressed()), this, SLOT(vbarIsPressed()));
+ connect(d->vbar, SIGNAL(sliderReleased()), this, SLOT(vbarIsReleased()));
+
+
+ d->viewport->installEventFilter(this);
+
+ connect(&d->scrollbar_timer, SIGNAL(timeout()),
+ this, SLOT(updateScrollBars()));
+
+ setFrameStyle(Q3Frame::StyledPanel | Q3Frame::Sunken);
+ setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+}
+
+
+/*!
+ Destroys the Q3ScrollView. Any children added with addChild() will
+ be deleted.
+*/
+Q3ScrollView::~Q3ScrollView()
+{
+ // Be careful not to get all those useless events...
+ if (d->clipped_viewport)
+ d->clipped_viewport->removeEventFilter(this);
+ else
+ d->viewport->removeEventFilter(this);
+
+ // order is important
+ // ~QWidget may cause a WM_ERASEBKGND on Windows
+ delete d->vbar;
+ d->vbar = 0;
+ delete d->hbar;
+ d->hbar = 0;
+ delete d->viewport;
+ d->viewport = 0;
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn void Q3ScrollView::horizontalSliderPressed()
+
+ This signal is emitted whenever the user presses the horizontal slider.
+*/
+/*!
+ \fn void Q3ScrollView::horizontalSliderReleased()
+
+ This signal is emitted whenever the user releases the horizontal slider.
+*/
+/*!
+ \fn void Q3ScrollView::verticalSliderPressed()
+
+ This signal is emitted whenever the user presses the vertical slider.
+*/
+/*!
+ \fn void Q3ScrollView::verticalSliderReleased()
+
+ This signal is emitted whenever the user releases the vertical slider.
+*/
+void Q3ScrollView::hbarIsPressed()
+{
+ d->hbarPressed = true;
+ emit(horizontalSliderPressed());
+}
+
+void Q3ScrollView::hbarIsReleased()
+{
+ d->hbarPressed = false;
+ emit(horizontalSliderReleased());
+}
+
+/*!
+ Returns true if horizontal slider is pressed by user; otherwise returns false.
+*/
+bool Q3ScrollView::isHorizontalSliderPressed()
+{
+ return d->hbarPressed;
+}
+
+void Q3ScrollView::vbarIsPressed()
+{
+ d->vbarPressed = true;
+ emit(verticalSliderPressed());
+}
+
+void Q3ScrollView::vbarIsReleased()
+{
+ d->vbarPressed = false;
+ emit(verticalSliderReleased());
+}
+
+/*!
+ Returns true if vertical slider is pressed by user; otherwise returns false.
+*/
+bool Q3ScrollView::isVerticalSliderPressed()
+{
+ return d->vbarPressed;
+}
+
+/*!
+ \internal
+*/
+void Q3ScrollView::styleChange(QStyle& old)
+{
+ QWidget::styleChange(old);
+ updateScrollBars();
+ d->cachedSizeHint = QSize();
+}
+
+/*!
+ \internal
+*/
+void Q3ScrollView::fontChange(const QFont &old)
+{
+ QWidget::fontChange(old);
+ updateScrollBars();
+ d->cachedSizeHint = QSize();
+}
+
+void Q3ScrollView::hslide(int pos)
+{
+ if (!d->signal_choke) {
+ moveContents(-pos, -d->contentsY());
+ QApplication::syncX();
+ }
+}
+
+void Q3ScrollView::vslide(int pos)
+{
+ if (!d->signal_choke) {
+ moveContents(-d->contentsX(), -pos);
+ QApplication::syncX();
+ }
+}
+
+/*!
+ Called when the horizontal scroll bar geometry changes. This is
+ provided as a protected function so that subclasses can do
+ interesting things such as providing extra buttons in some of the
+ space normally used by the scroll bars.
+
+ The default implementation simply gives all the space to \a hbar.
+ The new geometry is given by \a x, \a y, \a w and \a h.
+
+ \sa setVBarGeometry()
+*/
+void Q3ScrollView::setHBarGeometry(QScrollBar& hbar,
+ int x, int y, int w, int h)
+{
+ hbar.setGeometry(x, y, w, h);
+}
+
+/*!
+ Called when the vertical scroll bar geometry changes. This is
+ provided as a protected function so that subclasses can do
+ interesting things such as providing extra buttons in some of the
+ space normally used by the scroll bars.
+
+ The default implementation simply gives all the space to \a vbar.
+ The new geometry is given by \a x, \a y, \a w and \a h.
+
+ \sa setHBarGeometry()
+*/
+void Q3ScrollView::setVBarGeometry(QScrollBar& vbar,
+ int x, int y, int w, int h)
+{
+ vbar.setGeometry(x, y, w, h);
+}
+
+
+/*!
+ Returns the viewport size for size (\a x, \a y).
+
+ The viewport size depends on (\a x, \a y) (the size of the contents),
+ the size of this widget and the modes of the horizontal and
+ vertical scroll bars.
+
+ This function permits widgets that can trade vertical and
+ horizontal space for each other to control scroll bar appearance
+ better. For example, a word processor or web browser can control
+ the width of the right margin accurately, whether or not there
+ needs to be a vertical scroll bar.
+*/
+
+QSize Q3ScrollView::viewportSize(int x, int y) const
+{
+ int fw = frameWidth();
+ int lmarg = fw+d->l_marg;
+ int rmarg = fw+d->r_marg;
+ int tmarg = fw+d->t_marg;
+ int bmarg = fw+d->b_marg;
+
+ int w = width();
+ int h = height();
+
+ bool needh, needv;
+ bool showh, showv;
+ int hsbExt = horizontalScrollBar()->sizeHint().height();
+ int vsbExt = verticalScrollBar()->sizeHint().width();
+
+ if (d->policy != AutoOne || d->anyVisibleChildren()) {
+ // Do we definitely need the scroll bar?
+ needh = w-lmarg-rmarg < x;
+ needv = h-tmarg-bmarg < y;
+
+ // Do we intend to show the scroll bar?
+ if (d->hMode == AlwaysOn)
+ showh = true;
+ else if (d->hMode == AlwaysOff)
+ showh = false;
+ else
+ showh = needh;
+
+ if (d->vMode == AlwaysOn)
+ showv = true;
+ else if (d->vMode == AlwaysOff)
+ showv = false;
+ else
+ showv = needv;
+
+ // Given other scroll bar will be shown, NOW do we need one?
+ if (showh && h-vsbExt-tmarg-bmarg < y) {
+ if (d->vMode == Auto)
+ showv=true;
+ }
+ if (showv && w-hsbExt-lmarg-rmarg < x) {
+ if (d->hMode == Auto)
+ showh=true;
+ }
+ } else {
+ // Scroll bars not needed, only show scroll bar that are always on.
+ showh = d->hMode == AlwaysOn;
+ showv = d->vMode == AlwaysOn;
+ }
+
+ return QSize(w-lmarg-rmarg - (showv ? vsbExt : 0),
+ h-tmarg-bmarg - (showh ? hsbExt : 0));
+}
+
+
+/*!
+ Updates scroll bars: all possibilities are considered. You should
+ never need to call this in your code.
+*/
+void Q3ScrollView::updateScrollBars()
+{
+ if(!horizontalScrollBar() && !verticalScrollBar())
+ return;
+
+ // I support this should use viewportSize()... but it needs
+ // so many of the temporary variables from viewportSize. hm.
+ int fw = frameWidth();
+ int lmarg = fw+d->l_marg;
+ int rmarg = fw+d->r_marg;
+ int tmarg = fw+d->t_marg;
+ int bmarg = fw+d->b_marg;
+
+ int w = width();
+ int h = height();
+
+ int portw, porth;
+
+ bool needh;
+ bool needv;
+ bool showh;
+ bool showv;
+ bool showc = false;
+
+ int hsbExt = horizontalScrollBar()->sizeHint().height();
+ int vsbExt = verticalScrollBar()->sizeHint().width();
+
+ QSize oldVisibleSize(visibleWidth(), visibleHeight());
+
+ if (d->policy != AutoOne || d->anyVisibleChildren()) {
+ // Do we definitely need the scroll bar?
+ needh = w-lmarg-rmarg < d->contentsWidth();
+ if (d->inresize)
+ needh = !horizontalScrollBar()->isHidden();
+ needv = h-tmarg-bmarg < contentsHeight();
+
+ // Do we intend to show the scroll bar?
+ if (d->hMode == AlwaysOn)
+ showh = true;
+ else if (d->hMode == AlwaysOff)
+ showh = false;
+ else
+ showh = needh;
+
+ if (d->vMode == AlwaysOn)
+ showv = true;
+ else if (d->vMode == AlwaysOff)
+ showv = false;
+ else
+ showv = needv;
+
+#ifdef Q_WS_MAC
+ bool mac_need_scroll = false;
+ if(!parentWidget()) {
+ mac_need_scroll = true;
+ } else {
+ QWidget *tlw = window();
+#ifndef QT_MAC_USE_COCOA
+ QPoint tlw_br = QPoint(tlw->width(), tlw->height()),
+ my_br = qt_mac_posInWindow(this) + QPoint(w, h);
+ if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3)
+#endif
+ mac_need_scroll = true;
+ }
+ if(mac_need_scroll) {
+#ifndef QT_MAC_USE_COCOA
+ WindowAttributes attr;
+ GetWindowAttributes((WindowPtr)handle(), &attr);
+ mac_need_scroll = (attr & kWindowResizableAttribute);
+#endif
+ }
+ if(mac_need_scroll) {
+ showc = true;
+ if(d->vMode == Auto)
+ showv = true;
+ if(d->hMode == Auto)
+ showh = true;
+ }
+#endif
+
+ // Given other scroll bar will be shown, NOW do we need one?
+ if (showh && h-vsbExt-tmarg-bmarg < contentsHeight()) {
+ needv=true;
+ if (d->vMode == Auto)
+ showv=true;
+ }
+ if (showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth()) {
+ needh=true;
+ if (d->hMode == Auto)
+ showh=true;
+ }
+ } else {
+ // Scrollbars not needed, only show scroll bar that are always on.
+ needh = needv = false;
+ showh = d->hMode == AlwaysOn;
+ showv = d->vMode == AlwaysOn;
+ }
+
+ bool sc = d->signal_choke;
+ d->signal_choke=true;
+
+ // Hide unneeded scroll bar, calculate viewport size
+ if (showh) {
+ porth=h-hsbExt-tmarg-bmarg;
+ } else {
+ if (!needh)
+ d->hbar->setValue(0);
+ d->hbar->hide();
+ porth=h-tmarg-bmarg;
+ }
+ if (showv) {
+ portw=w-vsbExt-lmarg-rmarg;
+ } else {
+ if (!needv)
+ d->vbar->setValue(0);
+ d->vbar->hide();
+ portw=w-lmarg-rmarg;
+ }
+
+ // Configure scroll bars that we will show
+ if (needv) {
+ d->vbar->setRange(0, contentsHeight()-porth);
+ d->vbar->setSteps(Q3ScrollView::d->vbar->lineStep(), porth);
+ } else {
+ d->vbar->setRange(0, 0);
+ }
+ if (needh) {
+ d->hbar->setRange(0, QMAX(0, d->contentsWidth()-portw));
+ d->hbar->setSteps(Q3ScrollView::d->hbar->lineStep(), portw);
+ } else {
+ d->hbar->setRange(0, 0);
+ }
+
+ // Position the scroll bars, viewport and corner widget.
+ int bottom;
+ bool reverse = QApplication::reverseLayout();
+ int xoffset = (reverse && (showv || cornerWidget())) ? vsbExt : 0;
+ int xpos = reverse ? 0 : w - vsbExt;
+ bool frameContentsOnly =
+ style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
+
+ if(! frameContentsOnly) {
+ if (reverse)
+ xpos += fw;
+ else
+ xpos -= fw;
+ }
+ if (showh) {
+ int right = (showc || showv || cornerWidget()) ? w-vsbExt : w;
+ if (! frameContentsOnly)
+ setHBarGeometry(*d->hbar, fw + xoffset, h-hsbExt-fw,
+ right-fw-fw, hsbExt);
+ else
+ setHBarGeometry(*d->hbar, 0 + xoffset, h-hsbExt, right,
+ hsbExt);
+ bottom=h-hsbExt;
+ } else {
+ bottom=h;
+ }
+ if (showv) {
+ clipper()->setGeometry(lmarg + xoffset, tmarg,
+ w-vsbExt-lmarg-rmarg,
+ bottom-tmarg-bmarg);
+ d->viewportResized(w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg);
+ if (! frameContentsOnly)
+ changeFrameRect(QRect(0, 0, w, h));
+ else
+ changeFrameRect(QRect(xoffset, 0, w-vsbExt, bottom));
+ if (showc || cornerWidget()) {
+ if (! frameContentsOnly)
+ setVBarGeometry(*d->vbar, xpos,
+ fw, vsbExt,
+ h-hsbExt-fw-fw);
+ else
+ setVBarGeometry(*d->vbar, xpos, 0,
+ vsbExt,
+ h-hsbExt);
+ }
+ else {
+ if (! frameContentsOnly)
+ setVBarGeometry(*d->vbar, xpos,
+ fw, vsbExt,
+ bottom-fw-fw);
+ else
+ setVBarGeometry(*d->vbar, xpos, 0,
+ vsbExt, bottom);
+ }
+ } else {
+ if (! frameContentsOnly)
+ changeFrameRect(QRect(0, 0, w, h));
+ else
+ changeFrameRect(QRect(0, 0, w, bottom));
+ clipper()->setGeometry(lmarg, tmarg,
+ w-lmarg-rmarg, bottom-tmarg-bmarg);
+ d->viewportResized(w-lmarg-rmarg, bottom-tmarg-bmarg);
+ }
+
+ QWidget *corner = d->corner;
+ if (d->corner) {
+ if (! frameContentsOnly)
+ corner->setGeometry(xpos,
+ h-hsbExt-fw,
+ vsbExt,
+ hsbExt);
+ else
+ corner->setGeometry(xpos,
+ h-hsbExt,
+ vsbExt,
+ hsbExt);
+ }
+
+ d->signal_choke=sc;
+
+ if (d->contentsX()+visibleWidth() > d->contentsWidth()) {
+ int x;
+#if 0
+ if (reverse)
+ x =QMIN(0,d->contentsWidth()-visibleWidth());
+ else
+#endif
+ x =QMAX(0,d->contentsWidth()-visibleWidth());
+ d->hbar->setValue(x);
+ // Do it even if it is recursive
+ moveContents(-x, -d->contentsY());
+ }
+ if (d->contentsY()+visibleHeight() > contentsHeight()) {
+ int y=QMAX(0,contentsHeight()-visibleHeight());
+ d->vbar->setValue(y);
+ // Do it even if it is recursive
+ moveContents(-d->contentsX(), -y);
+ }
+
+ // Finally, show the scroll bars
+ if (showh && (d->hbar->isHidden() || !d->hbar->isVisible()))
+ d->hbar->show();
+ if (showv && (d->vbar->isHidden() || !d->vbar->isVisible()))
+ d->vbar->show();
+
+ d->signal_choke=true;
+ d->vbar->setValue(d->contentsY());
+ d->hbar->setValue(d->contentsX());
+ d->signal_choke=false;
+
+ QSize newVisibleSize(visibleWidth(), visibleHeight());
+ if (d->clipped_viewport && oldVisibleSize != newVisibleSize) {
+ QResizeEvent e(newVisibleSize, oldVisibleSize);
+ viewportResizeEvent(&e);
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void Q3ScrollView::setVisible(bool visible)
+{
+ if (visible && !isVisible()) {
+ QWidget::setVisible(visible);
+ updateScrollBars();
+ d->hideOrShowAll(this);
+ } else {
+ QWidget::setVisible(visible);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3ScrollView::resize(int w, int h)
+{
+ QWidget::resize(w, h);
+}
+
+/*!
+ \internal
+*/
+void Q3ScrollView::resize(const QSize& s)
+{
+ resize(s.width(), s.height());
+}
+
+/*!
+ \reimp
+*/
+void Q3ScrollView::resizeEvent(QResizeEvent* event)
+{
+ Q3Frame::resizeEvent(event);
+
+#if 0
+ if (QApplication::reverseLayout()) {
+ d->fake_scroll = true;
+ scrollBy(-event->size().width() + event->oldSize().width(), 0);
+ d->fake_scroll = false;
+ }
+#endif
+
+ bool inresize = d->inresize;
+ d->inresize = true;
+ updateScrollBars();
+ d->inresize = inresize;
+ d->scrollbar_timer.start(0, true);
+
+ d->hideOrShowAll(this);
+}
+
+
+
+/*!
+ \reimp
+*/
+void Q3ScrollView::mousePressEvent(QMouseEvent * e)
+{
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+void Q3ScrollView::mouseReleaseEvent(QMouseEvent *e)
+{
+ e->ignore();
+}
+
+
+/*!
+ \reimp
+*/
+void Q3ScrollView::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+void Q3ScrollView::mouseMoveEvent(QMouseEvent *e)
+{
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void Q3ScrollView::wheelEvent(QWheelEvent *e)
+{
+ QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()),
+ e->globalPos(), e->delta(), e->state());
+ viewportWheelEvent(&ce);
+ if (!ce.isAccepted()) {
+ if (e->orientation() == Horizontal && horizontalScrollBar())
+ horizontalScrollBar()->event(e);
+ else if (e->orientation() == Vertical && verticalScrollBar())
+ verticalScrollBar()->event(e);
+ } else {
+ e->accept();
+ }
+}
+#endif
+
+/*!
+ \reimp
+*/
+void Q3ScrollView::contextMenuEvent(QContextMenuEvent *e)
+{
+ if (e->reason() != QContextMenuEvent::Keyboard) {
+ e->ignore();
+ return;
+ }
+
+ QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()),
+ e->globalPos(), e->state());
+ viewportContextMenuEvent(&ce);
+ if (ce.isAccepted())
+ e->accept();
+ else
+ e->ignore();
+}
+
+Q3ScrollView::ScrollBarMode Q3ScrollView::vScrollBarMode() const
+{
+ return d->vMode;
+}
+
+
+/*!
+ \enum Q3ScrollView::ScrollBarMode
+
+ This enum type describes the various modes of Q3ScrollView's scroll
+ bars.
+
+ \value Auto Q3ScrollView shows a scroll bar when the content is
+ too large to fit and not otherwise. This is the default.
+
+ \value AlwaysOff Q3ScrollView never shows a scroll bar.
+
+ \value AlwaysOn Q3ScrollView always shows a scroll bar.
+
+ (The modes for the horizontal and vertical scroll bars are
+ independent.)
+*/
+
+
+/*!
+ \property Q3ScrollView::vScrollBarMode
+ \brief the mode for the vertical scroll bar
+
+ The default mode is Q3ScrollView::Auto.
+
+ \sa hScrollBarMode
+*/
+void Q3ScrollView::setVScrollBarMode(ScrollBarMode mode)
+{
+ if (d->vMode != mode) {
+ d->vMode = mode;
+ updateScrollBars();
+ }
+}
+
+
+/*!
+ \property Q3ScrollView::hScrollBarMode
+ \brief the mode for the horizontal scroll bar
+
+ The default mode is Q3ScrollView::Auto.
+
+ \sa vScrollBarMode
+*/
+Q3ScrollView::ScrollBarMode Q3ScrollView::hScrollBarMode() const
+{
+ return d->hMode;
+}
+
+void Q3ScrollView::setHScrollBarMode(ScrollBarMode mode)
+{
+ if (d->hMode != mode) {
+ d->hMode = mode;
+ updateScrollBars();
+ }
+}
+
+
+/*!
+ Returns the widget in the corner between the two scroll bars.
+
+ By default, no corner widget is present.
+*/
+QWidget* Q3ScrollView::cornerWidget() const
+{
+ return d->corner;
+}
+
+/*!
+ Sets the widget in the \a corner between the two scroll bars.
+
+ You will probably also want to set at least one of the scroll bar
+ modes to \c AlwaysOn.
+
+ Passing 0 shows no widget in the corner.
+
+ Any previous \a corner widget is hidden.
+
+ You may call setCornerWidget() with the same widget at different
+ times.
+
+ All widgets set here will be deleted by the Q3ScrollView when it is
+ destroyed unless you separately reparent the widget after setting
+ some other corner widget (or 0).
+
+ Any \e newly set widget should have no current parent.
+
+ By default, no corner widget is present.
+
+ \sa setVScrollBarMode(), setHScrollBarMode()
+*/
+void Q3ScrollView::setCornerWidget(QWidget* corner)
+{
+ QWidget* oldcorner = d->corner;
+ if (oldcorner != corner) {
+ if (oldcorner) oldcorner->hide();
+ d->corner = corner;
+ if (corner) corner->setParent(this);
+ updateScrollBars();
+ if (corner) corner->show();
+ }
+}
+
+
+void Q3ScrollView::setResizePolicy(ResizePolicy r)
+{
+ d->policy = r;
+}
+
+/*!
+ \property Q3ScrollView::resizePolicy
+ \brief the resize policy
+
+ The default is \c Default.
+
+ \sa ResizePolicy
+*/
+Q3ScrollView::ResizePolicy Q3ScrollView::resizePolicy() const
+{
+ return d->policy;
+}
+
+/*!
+ \internal
+*/
+void Q3ScrollView::setEnabled(bool enable)
+{
+ Q3Frame::setEnabled(enable);
+}
+
+/*!
+ Removes the \a child widget from the scrolled area. Note that this
+ happens automatically if the \a child is deleted.
+*/
+void Q3ScrollView::removeChild(QWidget* child)
+{
+ if (!d || !child) // First check in case we are destructing
+ return;
+
+ QSVChildRec *r = d->rec(child);
+ if (r) d->deleteChildRec(r);
+}
+
+/*!
+ \internal
+*/
+void Q3ScrollView::removeChild(QObject* child)
+{
+ Q3Frame::removeChild(child);
+}
+
+/*!
+ Inserts the widget, \a child, into the scrolled area positioned at
+ (\a x, \a y). The position defaults to (0, 0). If the child is
+ already in the view, it is just moved.
+
+ You may want to call enableClipper(true) if you add a large number
+ of widgets.
+*/
+void Q3ScrollView::addChild(QWidget* child, int x, int y)
+{
+ if (!child) {
+#if defined(QT_CHECK_NULL)
+ qWarning("Q3ScrollView::addChild(): Cannot add null child");
+#endif
+ return;
+ }
+ child->polish();
+ child->setBackgroundOrigin(WidgetOrigin);
+
+ if (child->parentWidget() == viewport()) {
+ // May already be there
+ QSVChildRec *r = d->rec(child);
+ if (r) {
+ r->moveTo(this,x,y,d->clipped_viewport);
+ if (d->policy > Manual) {
+ d->autoResizeHint(this);
+ d->autoResize(this); // #### better to just deal with this one widget!
+ }
+ return;
+ }
+ }
+
+ if (d->children.isEmpty() && d->policy != Manual) {
+ if (d->policy == Default)
+ setResizePolicy(AutoOne);
+ child->installEventFilter(this);
+ } else if (d->policy == AutoOne) {
+ child->removeEventFilter(this); //#### ?????
+ setResizePolicy(Manual);
+ }
+ if (child->parentWidget() != viewport()) {
+ child->reparent(viewport(), 0, QPoint(0,0), false);
+ }
+ d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport);
+
+ if (d->policy > Manual) {
+ d->autoResizeHint(this);
+ d->autoResize(this); // #### better to just deal with this one widget!
+ }
+}
+
+/*!
+ Repositions the \a child widget to (\a x, \a y). This function is
+ the same as addChild().
+*/
+void Q3ScrollView::moveChild(QWidget* child, int x, int y)
+{
+ addChild(child,x,y);
+}
+
+/*!
+ Returns the X position of the given \a child widget. Use this
+ rather than QWidget::x() for widgets added to the view.
+
+ This function returns 0 if \a child has not been added to the view.
+*/
+int Q3ScrollView::childX(QWidget* child)
+{
+ QSVChildRec *r = d->rec(child);
+ return r ? r->x : 0;
+}
+
+/*!
+ Returns the Y position of the given \a child widget. Use this
+ rather than QWidget::y() for widgets added to the view.
+
+ This function returns 0 if \a child has not been added to the view.
+*/
+int Q3ScrollView::childY(QWidget* child)
+{
+ QSVChildRec *r = d->rec(child);
+ return r ? r->y : 0;
+}
+
+/*! \fn bool Q3ScrollView::childIsVisible(QWidget*)
+ \obsolete
+
+ Returns true if \a child is visible. This is equivalent
+ to child->isVisible().
+*/
+
+/*! \fn void Q3ScrollView::showChild(QWidget* child, bool y)
+ \obsolete
+
+ Sets the visibility of \a child. Equivalent to
+ QWidget::show() or QWidget::hide().
+*/
+
+/*!
+ This event filter ensures the scroll bars are updated when a
+ single contents widget is resized, shown, hidden or destroyed; it
+ passes mouse events to the Q3ScrollView. The event is in \a e and
+ the object is in \a obj.
+*/
+
+bool Q3ScrollView::eventFilter(QObject *obj, QEvent *e)
+{
+ bool disabled = !(qobject_cast<QWidget*>(obj)->isEnabled());
+ if (!d)
+ return false; // we are destructing
+ if (obj == d->viewport || obj == d->clipped_viewport) {
+ switch (e->type()) {
+ /* Forward many events to viewport...() functions */
+ case QEvent::Paint:
+ viewportPaintEvent((QPaintEvent*)e);
+ break;
+ case QEvent::Resize:
+ if (!d->clipped_viewport)
+ viewportResizeEvent((QResizeEvent *)e);
+ break;
+ case QEvent::MouseButtonPress:
+ if (disabled)
+ return false;
+ viewportMousePressEvent((QMouseEvent*)e);
+ if (((QMouseEvent*)e)->isAccepted())
+ return true;
+ break;
+ case QEvent::MouseButtonRelease:
+ if (disabled)
+ return false;
+ viewportMouseReleaseEvent((QMouseEvent*)e);
+ if (((QMouseEvent*)e)->isAccepted())
+ return true;
+ break;
+ case QEvent::MouseButtonDblClick:
+ if (disabled)
+ return false;
+ viewportMouseDoubleClickEvent((QMouseEvent*)e);
+ if (((QMouseEvent*)e)->isAccepted())
+ return true;
+ break;
+ case QEvent::MouseMove:
+ if (disabled)
+ return false;
+ viewportMouseMoveEvent((QMouseEvent*)e);
+ if (((QMouseEvent*)e)->isAccepted())
+ return true;
+ break;
+#ifndef QT_NO_DRAGANDDROP
+ case QEvent::DragEnter:
+ if (disabled)
+ return false;
+ viewportDragEnterEvent((QDragEnterEvent*)e);
+ break;
+ case QEvent::DragMove: {
+ if (disabled)
+ return false;
+ if (d->drag_autoscroll) {
+ QPoint vp = ((QDragMoveEvent*) e)->pos();
+ QRect inside_margin(autoscroll_margin, autoscroll_margin,
+ visibleWidth() - autoscroll_margin * 2,
+ visibleHeight() - autoscroll_margin * 2);
+ if (!inside_margin.contains(vp)) {
+ startDragAutoScroll();
+ // Keep sending move events
+ ((QDragMoveEvent*)e)->accept(QRect(0,0,0,0));
+ }
+ }
+ viewportDragMoveEvent((QDragMoveEvent*)e);
+ } break;
+ case QEvent::DragLeave:
+ if (disabled)
+ return false;
+ stopDragAutoScroll();
+ viewportDragLeaveEvent((QDragLeaveEvent*)e);
+ break;
+ case QEvent::Drop:
+ if (disabled)
+ return false;
+ stopDragAutoScroll();
+ viewportDropEvent((QDropEvent*)e);
+ break;
+#endif // QT_NO_DRAGANDDROP
+#ifndef QT_NO_WHEELEVENT
+ case QEvent::Wheel:
+ if (disabled)
+ return false;
+ break;
+#endif
+ case QEvent::ContextMenu:
+ if (disabled)
+ return false;
+ viewportContextMenuEvent((QContextMenuEvent*)e);
+ if (((QContextMenuEvent*)e)->isAccepted())
+ return true;
+ break;
+ case QEvent::ChildRemoved:
+ removeChild((QWidget*)((QChildEvent*)e)->child());
+ break;
+ case QEvent::LayoutHint:
+ d->autoResizeHint(this);
+ break;
+ default:
+ break;
+ }
+ } else if (d && d->rec((QWidget*)obj)) { // must be a child
+ if (e->type() == QEvent::Resize)
+ d->autoResize(this);
+ else if (e->type() == QEvent::Move)
+ d->autoMove(this);
+ }
+ return Q3Frame::eventFilter(obj, e); // always continue with standard event processing
+}
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ mousePressEvent(): the press position in \a e is translated to be a point
+ on the contents.
+*/
+void Q3ScrollView::contentsMousePressEvent(QMouseEvent* e)
+{
+ e->ignore();
+}
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ mouseReleaseEvent(): the release position in \a e is translated to be a
+ point on the contents.
+*/
+void Q3ScrollView::contentsMouseReleaseEvent(QMouseEvent* e)
+{
+ e->ignore();
+}
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ mouseDoubleClickEvent(): the click position in \a e is translated to be a
+ point on the contents.
+
+ The default implementation generates a normal mouse press event.
+*/
+void Q3ScrollView::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+ contentsMousePressEvent(e); // try mouse press event
+}
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ mouseMoveEvent(): the mouse position in \a e is translated to be a point
+ on the contents.
+*/
+void Q3ScrollView::contentsMouseMoveEvent(QMouseEvent* e)
+{
+ e->ignore();
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ dragEnterEvent(): the drag position is translated to be a point
+ on the contents.
+
+ The default implementation does nothing. The \a event parameter is
+ ignored.
+*/
+void Q3ScrollView::contentsDragEnterEvent(QDragEnterEvent * /* event */)
+{
+}
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ dragMoveEvent(): the drag position is translated to be a point on
+ the contents.
+
+ The default implementation does nothing. The \a event parameter is
+ ignored.
+*/
+void Q3ScrollView::contentsDragMoveEvent(QDragMoveEvent * /* event */)
+{
+}
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ dragLeaveEvent(): the drag position is translated to be a point
+ on the contents.
+
+ The default implementation does nothing. The \a event parameter is
+ ignored.
+*/
+void Q3ScrollView::contentsDragLeaveEvent(QDragLeaveEvent * /* event */)
+{
+}
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ dropEvent(): the drop position is translated to be a point on the
+ contents.
+
+ The default implementation does nothing. The \a event parameter is
+ ignored.
+*/
+
+void Q3ScrollView::contentsDropEvent(QDropEvent * /* event */)
+{
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ wheelEvent() in \a{e}: the mouse position is translated to be a
+ point on the contents.
+*/
+#ifndef QT_NO_WHEELEVENT
+void Q3ScrollView::contentsWheelEvent(QWheelEvent * e)
+{
+ e->ignore();
+}
+#endif
+/*!
+ This event handler is called whenever the Q3ScrollView receives a
+ contextMenuEvent() in \a{e}: the mouse position is translated to
+ be a point on the contents.
+*/
+void Q3ScrollView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+ e->ignore();
+}
+
+/*!
+ This is a low-level painting routine that draws the viewport
+ contents. Reimplement this if drawContents() is too high-level
+ (for example, if you don't want to open a QPainter on the
+ viewport). The paint event is passed in \a pe.
+*/
+void Q3ScrollView::viewportPaintEvent(QPaintEvent* pe)
+{
+ QWidget* vp = viewport();
+
+ QPainter p(vp);
+ QRect r = pe->rect();
+
+ if (d->clipped_viewport) {
+ QRect rr(
+ -d->clipped_viewport->x(), -d->clipped_viewport->y(),
+ d->viewport->width(), d->viewport->height()
+ );
+ r &= rr;
+ if (r.isValid()) {
+ int ex = r.x() + d->clipped_viewport->x() + d->contentsX();
+ int ey = r.y() + d->clipped_viewport->y() + d->contentsY();
+ int ew = r.width();
+ int eh = r.height();
+ drawContentsOffset(&p,
+ d->contentsX()+d->clipped_viewport->x(),
+ d->contentsY()+d->clipped_viewport->y(),
+ ex, ey, ew, eh);
+ }
+ } else {
+ r &= d->viewport->rect();
+ int ex = r.x() + d->contentsX();
+ int ey = r.y() + d->contentsY();
+ int ew = r.width();
+ int eh = r.height();
+ drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh);
+ }
+}
+
+
+/*!
+ To provide simple processing of events on the contents, this
+ function receives all resize events sent to the viewport.
+
+ The default implementation does nothing. The \a event parameter is
+ ignored.
+
+ \sa QWidget::resizeEvent()
+*/
+void Q3ScrollView::viewportResizeEvent(QResizeEvent * /* event */)
+{
+}
+
+/*! \internal
+
+ To provide simple processing of events on the contents, this
+ function receives all mouse press events sent to the viewport,
+ translates the event and calls contentsMousePressEvent().
+
+ \sa contentsMousePressEvent(), QWidget::mousePressEvent()
+*/
+void Q3ScrollView::viewportMousePressEvent(QMouseEvent* e)
+{
+ QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+ e->globalPos(), e->button(), e->state());
+ contentsMousePressEvent(&ce);
+ if (!ce.isAccepted())
+ e->ignore();
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all mouse release events sent to the viewport, translates
+ the event and calls contentsMouseReleaseEvent().
+
+ \sa QWidget::mouseReleaseEvent()
+*/
+void Q3ScrollView::viewportMouseReleaseEvent(QMouseEvent* e)
+{
+ QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+ e->globalPos(), e->button(), e->state());
+ contentsMouseReleaseEvent(&ce);
+ if (!ce.isAccepted())
+ e->ignore();
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all mouse double click events sent to the viewport,
+ translates the event and calls contentsMouseDoubleClickEvent().
+
+ \sa QWidget::mouseDoubleClickEvent()
+*/
+void Q3ScrollView::viewportMouseDoubleClickEvent(QMouseEvent* e)
+{
+ QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+ e->globalPos(), e->button(), e->state());
+ contentsMouseDoubleClickEvent(&ce);
+ if (!ce.isAccepted())
+ e->ignore();
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all mouse move events sent to the viewport, translates the
+ event and calls contentsMouseMoveEvent().
+
+ \sa QWidget::mouseMoveEvent()
+*/
+void Q3ScrollView::viewportMouseMoveEvent(QMouseEvent* e)
+{
+ QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+ e->globalPos(), e->button(), e->state());
+ contentsMouseMoveEvent(&ce);
+ if (!ce.isAccepted())
+ e->ignore();
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all drag enter events sent to the viewport, translates the
+ event and calls contentsDragEnterEvent().
+
+ \sa QWidget::dragEnterEvent()
+*/
+void Q3ScrollView::viewportDragEnterEvent(QDragEnterEvent* e)
+{
+ e->setPoint(viewportToContents(e->pos()));
+ contentsDragEnterEvent(e);
+ e->setPoint(contentsToViewport(e->pos()));
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all drag move events sent to the viewport, translates the
+ event and calls contentsDragMoveEvent().
+
+ \sa QWidget::dragMoveEvent()
+*/
+void Q3ScrollView::viewportDragMoveEvent(QDragMoveEvent* e)
+{
+ e->setPoint(viewportToContents(e->pos()));
+ contentsDragMoveEvent(e);
+ e->setPoint(contentsToViewport(e->pos()));
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all drag leave events sent to the viewport and calls
+ contentsDragLeaveEvent().
+
+ \sa QWidget::dragLeaveEvent()
+*/
+void Q3ScrollView::viewportDragLeaveEvent(QDragLeaveEvent* e)
+{
+ contentsDragLeaveEvent(e);
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all drop events sent to the viewport, translates the event
+ and calls contentsDropEvent().
+
+ \sa QWidget::dropEvent()
+*/
+void Q3ScrollView::viewportDropEvent(QDropEvent* e)
+{
+ e->setPoint(viewportToContents(e->pos()));
+ contentsDropEvent(e);
+ e->setPoint(contentsToViewport(e->pos()));
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all wheel events sent to the viewport, translates the
+ event and calls contentsWheelEvent().
+
+ \sa QWidget::wheelEvent()
+*/
+#ifndef QT_NO_WHEELEVENT
+void Q3ScrollView::viewportWheelEvent(QWheelEvent* e)
+{
+ /*
+ Different than standard mouse events, because wheel events might
+ be sent to the focus widget if the widget-under-mouse doesn't want
+ the event itself.
+ */
+ QWheelEvent ce(viewportToContents(e->pos()),
+ e->globalPos(), e->delta(), e->state());
+ contentsWheelEvent(&ce);
+ if (ce.isAccepted())
+ e->accept();
+ else
+ e->ignore();
+}
+#endif
+
+/*! \internal
+
+ To provide simple processing of events on the contents, this function
+ receives all context menu events sent to the viewport, translates the
+ event and calls contentsContextMenuEvent().
+*/
+void Q3ScrollView::viewportContextMenuEvent(QContextMenuEvent *e)
+{
+ QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state());
+ contentsContextMenuEvent(&ce);
+ if (ce.isAccepted())
+ e->accept();
+ else
+ e->ignore();
+}
+
+/*!
+ Returns the component horizontal scroll bar. It is made available
+ to allow accelerators, autoscrolling, etc.
+
+ It should not be used for other purposes.
+
+ This function never returns 0.
+*/
+QScrollBar* Q3ScrollView::horizontalScrollBar() const
+{
+ return d->hbar;
+}
+
+/*!
+ Returns the component vertical scroll bar. It is made available to
+ allow accelerators, autoscrolling, etc.
+
+ It should not be used for other purposes.
+
+ This function never returns 0.
+*/
+QScrollBar* Q3ScrollView::verticalScrollBar() const {
+ return d->vbar;
+}
+
+
+/*!
+ Scrolls the content so that the point (\a x, \a y) is visible with at
+ least 50-pixel margins (if possible, otherwise centered).
+*/
+void Q3ScrollView::ensureVisible(int x, int y)
+{
+ ensureVisible(x, y, 50, 50);
+}
+
+/*!
+ \overload
+
+ Scrolls the content so that the point (\a x, \a y) is visible with at
+ least the \a xmargin and \a ymargin margins (if possible,
+ otherwise centered).
+*/
+void Q3ScrollView::ensureVisible(int x, int y, int xmargin, int ymargin)
+{
+ int pw=visibleWidth();
+ int ph=visibleHeight();
+
+ int cx=-d->contentsX();
+ int cy=-d->contentsY();
+ int cw=d->contentsWidth();
+ int ch=contentsHeight();
+
+ if (pw < xmargin*2)
+ xmargin=pw/2;
+ if (ph < ymargin*2)
+ ymargin=ph/2;
+
+ if (cw <= pw) {
+ xmargin=0;
+ cx=0;
+ }
+ if (ch <= ph) {
+ ymargin=0;
+ cy=0;
+ }
+
+ if (x < -cx+xmargin)
+ cx = -x+xmargin;
+ else if (x >= -cx+pw-xmargin)
+ cx = -x+pw-xmargin;
+
+ if (y < -cy+ymargin)
+ cy = -y+ymargin;
+ else if (y >= -cy+ph-ymargin)
+ cy = -y+ph-ymargin;
+
+ if (cx > 0)
+ cx=0;
+ else if (cx < pw-cw && cw>pw)
+ cx=pw-cw;
+
+ if (cy > 0)
+ cy=0;
+ else if (cy < ph-ch && ch>ph)
+ cy=ph-ch;
+
+ setContentsPos(-cx, -cy);
+}
+
+/*!
+ Scrolls the content so that the point (\a x, \a y) is in the top-left
+ corner.
+*/
+void Q3ScrollView::setContentsPos(int x, int y)
+{
+#if 0
+ // bounds checking...
+ if (QApplication::reverseLayout())
+ if (x > d->contentsWidth() - visibleWidth()) x = d->contentsWidth() - visibleWidth();
+ else
+#endif
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ // Choke signal handling while we update BOTH sliders.
+ d->signal_choke=true;
+ moveContents(-x, -y);
+ d->vbar->setValue(y);
+ d->hbar->setValue(x);
+ d->signal_choke=false;
+}
+
+/*!
+ Scrolls the content by \a dx to the left and \a dy upwards.
+*/
+void Q3ScrollView::scrollBy(int dx, int dy)
+{
+ setContentsPos(QMAX(d->contentsX()+dx, 0), QMAX(d->contentsY()+dy, 0));
+}
+
+/*!
+ Scrolls the content so that the point (\a x, \a y) is in the center
+ of visible area.
+*/
+void Q3ScrollView::center(int x, int y)
+{
+ ensureVisible(x, y, 32000, 32000);
+}
+
+/*!
+ \overload
+
+ Scrolls the content so that the point (\a x, \a y) is visible with
+ the \a xmargin and \a ymargin margins (as fractions of visible
+ the area).
+
+ For example:
+ \list
+ \i Margin 0.0 allows (x, y) to be on the edge of the visible area.
+ \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area.
+ \i Margin 1.0 ensures that (x, y) is in the center of the visible area.
+ \endlist
+*/
+void Q3ScrollView::center(int x, int y, float xmargin, float ymargin)
+{
+ int pw=visibleWidth();
+ int ph=visibleHeight();
+ ensureVisible(x, y, int(xmargin/2.0*pw+0.5), int(ymargin/2.0*ph+0.5));
+}
+
+
+/*!
+ \fn void Q3ScrollView::contentsMoving(int x, int y)
+
+ This signal is emitted just before the contents are moved to
+ position (\a x, \a y).
+
+ \sa contentsX(), contentsY()
+*/
+
+/*!
+ Moves the contents by (\a x, \a y).
+*/
+void Q3ScrollView::moveContents(int x, int y)
+{
+ if (-x+visibleWidth() > d->contentsWidth())
+#if 0
+ if(QApplication::reverseLayout())
+ x=QMAX(0,-d->contentsWidth()+visibleWidth());
+ else
+#endif
+ x=QMIN(0,-d->contentsWidth()+visibleWidth());
+ if (-y+visibleHeight() > contentsHeight())
+ y=QMIN(0,-contentsHeight()+visibleHeight());
+
+ int dx = x - d->vx;
+ int dy = y - d->vy;
+
+ if (!dx && !dy)
+ return; // Nothing to do
+
+ emit contentsMoving(-x, -y);
+
+ d->vx = x;
+ d->vy = y;
+
+ if (d->clipped_viewport || d->static_bg) {
+ // Cheap move (usually)
+ d->moveAllBy(dx,dy);
+ } else if (/*dx && dy ||*/
+ (QABS(dy) * 5 > visibleHeight() * 4) ||
+ (QABS(dx) * 5 > visibleWidth() * 4)
+ )
+ {
+ // Big move
+ if (viewport()->updatesEnabled())
+ viewport()->update();
+ d->moveAllBy(dx,dy);
+ } else if (!d->fake_scroll || d->contentsWidth() > visibleWidth()) {
+ // Small move
+ clipper()->scroll(dx,dy);
+ }
+ d->hideOrShowAll(this, true);
+}
+
+/*!
+ \property Q3ScrollView::contentsX
+ \brief the X coordinate of the contents that are at the left edge of
+ the viewport.
+*/
+int Q3ScrollView::contentsX() const
+{
+ return d->contentsX();
+}
+
+/*!
+ \property Q3ScrollView::contentsY
+ \brief the Y coordinate of the contents that are at the top edge of
+ the viewport.
+*/
+int Q3ScrollView::contentsY() const
+{
+ return d->contentsY();
+}
+
+/*!
+ \property Q3ScrollView::contentsWidth
+ \brief the width of the contents area
+*/
+int Q3ScrollView::contentsWidth() const
+{
+ return d->contentsWidth();
+}
+
+/*!
+ \property Q3ScrollView::contentsHeight
+ \brief the height of the contents area
+*/
+int Q3ScrollView::contentsHeight() const
+{
+ return d->vheight;
+}
+
+/*!
+ Sets the size of the contents area to \a w pixels wide and \a h
+ pixels high and updates the viewport accordingly.
+*/
+void Q3ScrollView::resizeContents(int w, int h)
+{
+ int ow = d->vwidth;
+ int oh = d->vheight;
+ d->vwidth = w;
+ d->vheight = h;
+
+ d->scrollbar_timer.start(0, true);
+
+ if (d->children.isEmpty() && d->policy == Default)
+ setResizePolicy(Manual);
+
+ if (ow > w) {
+ // Swap
+ int t=w;
+ w=ow;
+ ow=t;
+ }
+ // Refresh area ow..w
+ if (ow < visibleWidth() && w >= 0) {
+ if (ow < 0)
+ ow = 0;
+ if (w > visibleWidth())
+ w = visibleWidth();
+ clipper()->update(d->contentsX()+ow, 0, w-ow, visibleHeight());
+ }
+
+ if (oh > h) {
+ // Swap
+ int t=h;
+ h=oh;
+ oh=t;
+ }
+ // Refresh area oh..h
+ if (oh < visibleHeight() && h >= 0) {
+ if (oh < 0)
+ oh = 0;
+ if (h > visibleHeight())
+ h = visibleHeight();
+ clipper()->update(0, d->contentsY()+oh, visibleWidth(), h-oh);
+ }
+}
+
+/*!
+ Calls update() on a rectangle defined by \a x, \a y, \a w, \a h,
+ translated appropriately. If the rectangle is not visible, nothing
+ is repainted.
+
+ \sa repaintContents()
+*/
+void Q3ScrollView::updateContents(int x, int y, int w, int h)
+{
+ if (!isVisible() || !updatesEnabled())
+ return;
+
+ QWidget* vp = viewport();
+
+ // Translate
+ x -= d->contentsX();
+ y -= d->contentsY();
+
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+ if (y < 0) {
+ h += y;
+ y = 0;
+ }
+
+ if (w < 0 || h < 0)
+ return;
+ if (x > visibleWidth() || y > visibleHeight())
+ return;
+
+ if (w > visibleWidth())
+ w = visibleWidth();
+ if (h > visibleHeight())
+ h = visibleHeight();
+
+ if (d->clipped_viewport) {
+ // Translate clipper() to viewport()
+ x -= d->clipped_viewport->x();
+ y -= d->clipped_viewport->y();
+ }
+
+ vp->update(x, y, w, h);
+}
+
+/*!
+ \overload
+
+ Updates the contents in rectangle \a r
+*/
+void Q3ScrollView::updateContents(const QRect& r)
+{
+ updateContents(r.x(), r.y(), r.width(), r.height());
+}
+
+/*!
+ \overload
+*/
+void Q3ScrollView::updateContents()
+{
+ updateContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight());
+}
+
+/*!
+ \overload
+
+ Repaints the contents of rectangle \a r. If \a erase is true the
+ background is cleared using the background color.
+*/
+void Q3ScrollView::repaintContents(const QRect& r, bool erase)
+{
+ repaintContents(r.x(), r.y(), r.width(), r.height(), erase);
+}
+
+
+/*!
+ \overload
+
+ Repaints the contents. If \a erase is true the background is
+ cleared using the background color.
+*/
+void Q3ScrollView::repaintContents(bool erase)
+{
+ repaintContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase);
+}
+
+
+/*!
+ Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h,
+ translated appropriately. If the rectangle is not visible, nothing
+ is repainted. If \a erase is true the background is cleared using
+ the background color.
+
+ \sa updateContents()
+*/
+void Q3ScrollView::repaintContents(int x, int y, int w, int h, bool /*erase*/)
+{
+ if (!isVisible() || !updatesEnabled())
+ return;
+
+ QWidget* vp = viewport();
+
+ // Translate logical to clipper()
+ x -= d->contentsX();
+ y -= d->contentsY();
+
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+ if (y < 0) {
+ h += y;
+ y = 0;
+ }
+
+ if (w < 0 || h < 0)
+ return;
+ if (w > visibleWidth())
+ w = visibleWidth();
+ if (h > visibleHeight())
+ h = visibleHeight();
+
+ if (d->clipped_viewport) {
+ // Translate clipper() to viewport()
+ x -= d->clipped_viewport->x();
+ y -= d->clipped_viewport->y();
+ }
+
+ vp->update(x, y, w, h);
+}
+
+
+/*!
+ For backward-compatibility only. It is easier to use
+ drawContents(QPainter*,int,int,int,int).
+
+ The default implementation translates the painter appropriately
+ and calls drawContents(QPainter*,int,int,int,int). See
+ drawContents() for an explanation of the parameters \a p, \a
+ offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph.
+*/
+void Q3ScrollView::drawContentsOffset(QPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph)
+{
+ p->translate(-offsetx,-offsety);
+ drawContents(p, clipx, clipy, clipw, cliph);
+}
+
+/*!
+ \fn void Q3ScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph)
+
+ Reimplement this function if you are viewing a drawing area rather
+ than a widget.
+
+ The function should draw the rectangle (\a clipx, \a clipy, \a
+ clipw, \a cliph) of the contents using painter \a p. The clip
+ rectangle is in the scrollview's coordinates.
+
+ For example:
+ \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 4
+
+ The clip rectangle and translation of the painter \a p is already
+ set appropriately.
+*/
+void Q3ScrollView::drawContents(QPainter*, int, int, int, int)
+{
+}
+
+
+/*!
+ \reimp
+*/
+void Q3ScrollView::frameChanged()
+{
+ // slight ugle-hack - the listview header needs readjusting when
+ // changing the frame
+ if (Q3ListView *lv = qobject_cast<Q3ListView *>(this))
+ lv->triggerUpdate();
+ Q3Frame::frameChanged();
+ updateScrollBars();
+}
+
+
+/*!
+ Returns the viewport widget of the scrollview. This is the widget
+ containing the contents widget or which is the drawing area.
+*/
+QWidget* Q3ScrollView::viewport() const
+{
+ if (d->clipped_viewport)
+ return d->clipped_viewport;
+ return d->viewport;
+}
+
+/*!
+ Returns the clipper widget. Contents in the scrollview are
+ ultimately clipped to be inside the clipper widget.
+
+ You should not need to use this function.
+
+ \sa visibleWidth(), visibleHeight()
+*/
+QWidget* Q3ScrollView::clipper() const
+{
+ return d->viewport;
+}
+
+/*!
+ \property Q3ScrollView::visibleWidth
+ \brief the horizontal amount of the content that is visible
+*/
+int Q3ScrollView::visibleWidth() const
+{
+ return clipper()->width();
+}
+
+/*!
+ \property Q3ScrollView::visibleHeight
+ \brief the vertical amount of the content that is visible
+*/
+int Q3ScrollView::visibleHeight() const
+{
+ return clipper()->height();
+}
+
+
+void Q3ScrollView::changeFrameRect(const QRect& r)
+{
+ QRect oldr = frameRect();
+ if (oldr != r) {
+ QRect cr = contentsRect();
+ QRegion fr(frameRect());
+ fr = fr.subtracted(contentsRect());
+ setFrameRect(r);
+ if (isVisible()) {
+ cr = cr.intersected(contentsRect());
+ fr = fr.united(frameRect());
+ fr = fr.subtracted(cr);
+ if (!fr.isEmpty())
+ update(fr);
+ }
+ }
+}
+
+
+/*!
+ Sets the margins around the scrolling area to \a left, \a top, \a
+ right and \a bottom. This is useful for applications such as
+ spreadsheets with "locked" rows and columns. The marginal space is
+ \e inside the frameRect() and is left blank; reimplement
+ drawFrame() or put widgets in the unused area.
+
+ By default all margins are zero.
+
+ \sa frameChanged()
+*/
+void Q3ScrollView::setMargins(int left, int top, int right, int bottom)
+{
+ if (left == d->l_marg &&
+ top == d->t_marg &&
+ right == d->r_marg &&
+ bottom == d->b_marg)
+ return;
+
+ d->l_marg = left;
+ d->t_marg = top;
+ d->r_marg = right;
+ d->b_marg = bottom;
+ updateScrollBars();
+}
+
+
+/*!
+ Returns the left margin.
+
+ \sa setMargins()
+*/
+int Q3ScrollView::leftMargin() const
+{
+ return d->l_marg;
+}
+
+
+/*!
+ Returns the top margin.
+
+ \sa setMargins()
+*/
+int Q3ScrollView::topMargin() const
+{
+ return d->t_marg;
+}
+
+
+/*!
+ Returns the right margin.
+
+ \sa setMargins()
+*/
+int Q3ScrollView::rightMargin() const
+{
+ return d->r_marg;
+}
+
+
+/*!
+ Returns the bottom margin.
+
+ \sa setMargins()
+*/
+int Q3ScrollView::bottomMargin() const
+{
+ return d->b_marg;
+}
+
+/*!
+ \reimp
+*/
+bool Q3ScrollView::focusNextPrevChild(bool next)
+{
+ // Makes sure that the new focus widget is on-screen, if
+ // necessary by scrolling the scroll view.
+ bool retval = Q3Frame::focusNextPrevChild(next);
+ if (retval) {
+ QWidget *w = window()->focusWidget();
+ if (isAncestorOf(w)) {
+ QSVChildRec *r = d->ancestorRec(w);
+ if (r && (r->child == w || w->isVisibleTo(r->child))) {
+ QPoint cp = r->child->mapToGlobal(QPoint(0, 0));
+ QPoint cr = w->mapToGlobal(QPoint(0, 0)) - cp;
+ ensureVisible(r->x + cr.x() + w->width()/2, r->y + cr.y() + w->height()/2,
+ w->width()/2, w->height()/2);
+ }
+ }
+ }
+ return retval;
+}
+
+
+
+/*!
+ When a large numbers of child widgets are in a scrollview,
+ especially if they are close together, the scrolling performance
+ can suffer greatly. If \a y is true the scrollview will use an
+ extra widget to group child widgets.
+
+ Note that you may only call enableClipper() prior to adding
+ widgets.
+*/
+void Q3ScrollView::enableClipper(bool y)
+{
+ if (!d->clipped_viewport == !y)
+ return;
+ if (d->children.count())
+ qFatal("May only call Q3ScrollView::enableClipper() before adding widgets");
+ if (y) {
+ d->clipped_viewport = new QClipperWidget(clipper(), "qt_clipped_viewport", QFlag(d->flags));
+ d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2,
+ coord_limit,coord_limit);
+ d->clipped_viewport->setBackgroundMode(d->viewport->backgroundMode());
+ d->viewport->setBackgroundMode(NoBackground); // no exposures for this
+ d->viewport->removeEventFilter(this);
+ d->clipped_viewport->installEventFilter(this);
+ d->clipped_viewport->show();
+ } else {
+ delete d->clipped_viewport;
+ d->clipped_viewport = 0;
+ }
+}
+
+/*!
+ Sets the scrollview to have a static background if \a y is true,
+ or a scrolling background if \a y is false. By default, the
+ background is scrolling.
+
+ Be aware that this mode is quite slow, as a full repaint of the
+ visible area has to be triggered on every contents move.
+
+ \sa hasStaticBackground()
+*/
+void Q3ScrollView::setStaticBackground(bool y)
+{
+ d->static_bg = y;
+}
+
+/*!
+ Returns true if Q3ScrollView uses a static background; otherwise
+ returns false.
+
+ \sa setStaticBackground()
+*/
+bool Q3ScrollView::hasStaticBackground() const
+{
+ return d->static_bg;
+}
+
+/*!
+ \overload
+
+ Returns the point \a p translated to a point on the viewport()
+ widget.
+*/
+QPoint Q3ScrollView::contentsToViewport(const QPoint& p) const
+{
+ if (d->clipped_viewport) {
+ return QPoint(p.x() - d->contentsX() - d->clipped_viewport->x(),
+ p.y() - d->contentsY() - d->clipped_viewport->y());
+ } else {
+ return QPoint(p.x() - d->contentsX(),
+ p.y() - d->contentsY());
+ }
+}
+
+/*!
+ \overload
+
+ Returns the point on the viewport \a vp translated to a point in
+ the contents.
+*/
+QPoint Q3ScrollView::viewportToContents(const QPoint& vp) const
+{
+ if (d->clipped_viewport) {
+ return QPoint(vp.x() + d->contentsX() + d->clipped_viewport->x(),
+ vp.y() + d->contentsY() + d->clipped_viewport->y());
+ } else {
+ return QPoint(vp.x() + d->contentsX(),
+ vp.y() + d->contentsY());
+ }
+}
+
+
+/*!
+ Translates a point (\a x, \a y) in the contents to a point (\a vx,
+ \a vy) on the viewport() widget.
+*/
+void Q3ScrollView::contentsToViewport(int x, int y, int& vx, int& vy) const
+{
+ const QPoint v = contentsToViewport(QPoint(x,y));
+ vx = v.x();
+ vy = v.y();
+}
+
+/*!
+ Translates a point (\a vx, \a vy) on the viewport() widget to a
+ point (\a x, \a y) in the contents.
+*/
+void Q3ScrollView::viewportToContents(int vx, int vy, int& x, int& y) const
+{
+ const QPoint c = viewportToContents(QPoint(vx,vy));
+ x = c.x();
+ y = c.y();
+}
+
+/*!
+ \reimp
+*/
+QSize Q3ScrollView::sizeHint() const
+{
+ if (d->use_cached_size_hint && d->cachedSizeHint.isValid())
+ return d->cachedSizeHint;
+
+ constPolish();
+ int f = 2 * frameWidth();
+ int h = fontMetrics().height();
+ QSize sz(f, f);
+ if (d->policy > Manual) {
+ QSVChildRec *r = d->children.first();
+ if (r) {
+ QSize cs = r->child->sizeHint();
+ if (cs.isValid())
+ sz += cs.boundedTo(r->child->maximumSize());
+ else
+ sz += r->child->size();
+ }
+ } else {
+ sz += QSize(d->contentsWidth(), contentsHeight());
+ }
+ if (d->vMode == AlwaysOn)
+ sz.setWidth(sz.width() + d->vbar->sizeHint().width());
+ if (d->hMode == AlwaysOn)
+ sz.setHeight(sz.height() + d->hbar->sizeHint().height());
+ return sz.expandedTo(QSize(12 * h, 8 * h))
+ .boundedTo(QSize(36 * h, 24 * h));
+}
+
+
+/*!
+ \reimp
+*/
+QSize Q3ScrollView::minimumSizeHint() const
+{
+ int h = fontMetrics().height();
+ if (h < 10)
+ h = 10;
+ int f = 2 * frameWidth();
+ return QSize((6 * h) + f, (4 * h) + f);
+}
+
+
+/*!
+ \reimp
+
+ (Implemented to get rid of a compiler warning.)
+*/
+void Q3ScrollView::drawContents(QPainter *)
+{
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+ \internal
+*/
+void Q3ScrollView::startDragAutoScroll()
+{
+ if (!d->autoscroll_timer.isActive()) {
+ d->autoscroll_time = initialScrollTime;
+ d->autoscroll_accel = initialScrollAccel;
+ d->autoscroll_timer.start(d->autoscroll_time);
+ }
+}
+
+
+/*!
+ \internal
+*/
+void Q3ScrollView::stopDragAutoScroll()
+{
+ d->autoscroll_timer.stop();
+}
+
+
+/*!
+ \internal
+*/
+void Q3ScrollView::doDragAutoScroll()
+{
+ QPoint p = d->viewport->mapFromGlobal(QCursor::pos());
+
+ if (d->autoscroll_accel-- <= 0 && d->autoscroll_time) {
+ d->autoscroll_accel = initialScrollAccel;
+ d->autoscroll_time--;
+ d->autoscroll_timer.start(d->autoscroll_time);
+ }
+ int l = QMAX(1, (initialScrollTime- d->autoscroll_time));
+
+ int dx = 0, dy = 0;
+ if (p.y() < autoscroll_margin) {
+ dy = -l;
+ } else if (p.y() > visibleHeight() - autoscroll_margin) {
+ dy = +l;
+ }
+ if (p.x() < autoscroll_margin) {
+ dx = -l;
+ } else if (p.x() > visibleWidth() - autoscroll_margin) {
+ dx = +l;
+ }
+ if (dx || dy) {
+ scrollBy(dx,dy);
+ } else {
+ stopDragAutoScroll();
+ }
+}
+
+
+/*!
+ \property Q3ScrollView::dragAutoScroll
+ \brief whether autoscrolling in drag move events is enabled
+
+ If this property is set to true (the default), the Q3ScrollView
+ automatically scrolls the contents in drag move events if the user
+ moves the cursor close to a border of the view. Of course this
+ works only if the viewport accepts drops. Specifying false
+ disables this autoscroll feature.
+*/
+
+void Q3ScrollView::setDragAutoScroll(bool b)
+{
+ d->drag_autoscroll = b;
+}
+
+bool Q3ScrollView::dragAutoScroll() const
+{
+ return d->drag_autoscroll;
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!\internal
+ */
+void Q3ScrollView::setCachedSizeHint(const QSize &sh) const
+{
+ if (isVisible() && !d->cachedSizeHint.isValid())
+ d->cachedSizeHint = sh;
+}
+
+/*!\internal
+ */
+void Q3ScrollView::disableSizeHintCaching()
+{
+ d->use_cached_size_hint = false;
+}
+
+/*!\internal
+ */
+QSize Q3ScrollView::cachedSizeHint() const
+{
+ return d->use_cached_size_hint ? d->cachedSizeHint : QSize();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCROLLVIEW