File indexing completed on 2024-04-28 09:38:54

0001 /****************************************************************************
0002 **
0003 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
0004 ** Contact: http://www.qt-project.org/legal
0005 **
0006 ** This file is part of the Qt3Support module of the Qt Toolkit.
0007 **
0008 ** $QT_BEGIN_LICENSE:LGPL$
0009 ** Commercial License Usage
0010 ** Licensees holding valid commercial Qt licenses may use this file in
0011 ** accordance with the commercial license agreement provided with the
0012 ** Software or, alternatively, in accordance with the terms contained in
0013 ** a written agreement between you and Digia.  For licensing terms and
0014 ** conditions see http://qt.digia.com/licensing.  For further information
0015 ** use the contact form at http://qt.digia.com/contact-us.
0016 **
0017 ** GNU Lesser General Public License Usage
0018 ** Alternatively, this file may be used under the terms of the GNU Lesser
0019 ** General Public License version 2.1 as published by the Free Software
0020 ** Foundation and appearing in the file LICENSE.LGPL included in the
0021 ** packaging of this file.  Please review the following information to
0022 ** ensure the GNU Lesser General Public License version 2.1 requirements
0023 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
0024 **
0025 ** In addition, as a special exception, Digia gives you certain additional
0026 ** rights.  These rights are described in the Digia Qt LGPL Exception
0027 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
0028 **
0029 ** GNU General Public License Usage
0030 ** Alternatively, this file may be used under the terms of the GNU
0031 ** General Public License version 3.0 as published by the Free Software
0032 ** Foundation and appearing in the file LICENSE.GPL included in the
0033 ** packaging of this file.  Please review the following information to
0034 ** ensure the GNU General Public License version 3.0 requirements will be
0035 ** met: http://www.gnu.org/copyleft/gpl.html.
0036 **
0037 **
0038 ** $QT_END_LICENSE$
0039 **
0040 ****************************************************************************/
0041 
0042 #include "ktlq3scrollview.h"
0043 
0044 #include <QCursor>
0045 #include <QPainter>
0046 #include <QPixmap>
0047 #include <QScrollBar>
0048 #include <QWidget>
0049 // #include "q3ptrdict.h"
0050 #include <QApplication>
0051 #include <QHash>
0052 #include <QStyle>
0053 #include <QTimer>
0054 // #include "q3ptrlist.h"
0055 #include <QContextMenuEvent>
0056 #include <QDragEnterEvent>
0057 #include <QDragLeaveEvent>
0058 //#include "q3listview.h"
0059 // #ifdef Q_WS_MAC      // 2018.10.18 - do not depend on internal headers
0060 // # include "private/qt_mac_p.h"
0061 // #endif
0062 
0063 // QT_BEGIN_NAMESPACE
0064 
0065 // using namespace Qt;
0066 
0067 static const int coord_limit = 4000;
0068 static const int autoscroll_margin = 16;
0069 static const int initialScrollTime = 30;
0070 static const int initialScrollAccel = 5;
0071 
0072 struct QSVChildRec {
0073     QSVChildRec(QWidget *c, int xx, int yy)
0074         : child(c)
0075         , x(xx)
0076         , y(yy)
0077     {
0078     }
0079 
0080     void hideOrShow(KtlQ3ScrollView *sv, QWidget *clipped_viewport);
0081     void moveTo(KtlQ3ScrollView *sv, int xx, int yy, QWidget *clipped_viewport)
0082     {
0083         if (x != xx || y != yy) {
0084             x = xx;
0085             y = yy;
0086             hideOrShow(sv, clipped_viewport);
0087         }
0088     }
0089     QWidget *child;
0090     int x, y;
0091 };
0092 
0093 void QSVChildRec::hideOrShow(KtlQ3ScrollView *sv, QWidget *clipped_viewport)
0094 {
0095     if (clipped_viewport) {
0096         if (x + child->width() < sv->contentsX() + clipped_viewport->x() || x > sv->contentsX() + clipped_viewport->width() || y + child->height() < sv->contentsY() + clipped_viewport->y() ||
0097             y > sv->contentsY() + clipped_viewport->height()) {
0098             child->move(clipped_viewport->width(), clipped_viewport->height());
0099         } else {
0100             child->move(x - sv->contentsX() - clipped_viewport->x(), y - sv->contentsY() - clipped_viewport->y());
0101         }
0102     } else {
0103         child->move(x - sv->contentsX(), y - sv->contentsY());
0104     }
0105 }
0106 
0107 // QT_BEGIN_INCLUDE_NAMESPACE
0108 
0109 // QT_END_INCLUDE_NAMESPACE
0110 
0111 class KtlQ3ScrollViewData
0112 {
0113 public:
0114     KtlQ3ScrollViewData(KtlQ3ScrollView *parent, int vpwflags)
0115         : hbar(new QScrollBar(Qt::Horizontal, parent /*, "qt_hbar"*/))
0116         , vbar(new QScrollBar(Qt::Vertical, parent /*, "qt_vbar" */))
0117         , viewport(new KtlQAbstractScrollAreaWidget(parent, "qt_viewport", QFlag(vpwflags)))
0118         , clipped_viewport(nullptr)
0119         , flags(vpwflags)
0120         , vx(0)
0121         , vy(0)
0122         , vwidth(1)
0123         , vheight(1)
0124         ,
0125 #ifndef QT_NO_DRAGANDDROP
0126         autoscroll_timer(parent /* , "scrollview autoscroll timer" */)
0127         , drag_autoscroll(true)
0128         ,
0129 #endif
0130         scrollbar_timer(parent /*, "scrollview scrollbar timer" */)
0131         , inresize(false)
0132         , use_cached_size_hint(true)
0133     {
0134         hbar->setObjectName("qt_hbar");
0135         vbar->setObjectName("qt_vbar");
0136 #ifndef QT_NO_DRAGANDDROP
0137         autoscroll_timer.setObjectName("scrollview autoscroll timer");
0138 #endif
0139         scrollbar_timer.setObjectName("scrollview scrollbar timer");
0140         l_marg = r_marg = t_marg = b_marg = 0;
0141         viewport->ensurePolished();
0142         vMode = KtlQ3ScrollView::Auto;
0143         hMode = KtlQ3ScrollView::Auto;
0144         corner = nullptr;
0145         // vbar->setSteps(20, 1/*set later*/);
0146         vbar->setSingleStep(20);
0147         vbar->setPageStep(1);
0148         // hbar->setSteps(20, 1/*set later*/);
0149         hbar->setSingleStep(20);
0150         hbar->setPageStep(1);
0151         policy = KtlQ3ScrollView::Default;
0152         signal_choke = false;
0153         static_bg = false;
0154         fake_scroll = false;
0155         hbarPressed = false;
0156         vbarPressed = false;
0157         hbar->setLayoutDirection(Qt::LeftToRight);
0158     }
0159     ~KtlQ3ScrollViewData();
0160 
0161     QSVChildRec *rec(QWidget *w)
0162     {
0163         return /* childDict.find(w); */ childDict.value(w);
0164     }
0165     QSVChildRec *ancestorRec(QWidget *w);
0166     QSVChildRec *addChildRec(QWidget *w, int x, int y)
0167     {
0168         QSVChildRec *r = new QSVChildRec(w, x, y);
0169         children.append(r);
0170         childDict.insert(w, r);
0171         return r;
0172     }
0173     void deleteChildRec(QSVChildRec *r)
0174     {
0175         childDict.remove(r->child);
0176         // children.removeRef(r);
0177         children.removeAll(r);
0178         delete r;
0179     }
0180 
0181     void hideOrShowAll(KtlQ3ScrollView *sv, bool isScroll = false);
0182     void moveAllBy(int dx, int dy);
0183     bool anyVisibleChildren();
0184     void autoMove(KtlQ3ScrollView *sv);
0185     void autoResize(KtlQ3ScrollView *sv);
0186     void autoResizeHint(KtlQ3ScrollView *sv);
0187     void viewportResized(int w, int h);
0188 
0189     QScrollBar *hbar;
0190     QScrollBar *vbar;
0191     bool hbarPressed;
0192     bool vbarPressed;
0193     KtlQAbstractScrollAreaWidget *viewport;
0194     KtlQClipperWidget *clipped_viewport;
0195     int flags;
0196     // Q3PtrList<QSVChildRec>       children;
0197     QList<QSVChildRec *> children;
0198     // Q3PtrDict<QSVChildRec>       childDict; // 2018.10.07
0199     QHash<QWidget *, QSVChildRec *> childDict;
0200     QWidget *corner;
0201     int vx, vy, vwidth, vheight; // for drawContents-style usage
0202     int l_marg, r_marg, t_marg, b_marg;
0203     KtlQ3ScrollView::ResizePolicy policy;
0204     KtlQ3ScrollView::ScrollBarMode vMode;
0205     KtlQ3ScrollView::ScrollBarMode hMode;
0206 #ifndef QT_NO_DRAGANDDROP
0207     QPoint cpDragStart;
0208     QTimer autoscroll_timer;
0209     int autoscroll_time;
0210     int autoscroll_accel;
0211     bool drag_autoscroll;
0212 #endif
0213     QTimer scrollbar_timer;
0214 
0215     uint static_bg : 1;
0216     uint fake_scroll : 1;
0217 
0218     // This variable allows ensureVisible to move the contents then
0219     // update both the sliders.  Otherwise, updating the sliders would
0220     // cause two image scrolls, creating ugly flashing.
0221     //
0222     uint signal_choke : 1;
0223 
0224     // This variables indicates in updateScrollBars() that we are
0225     // in a resizeEvent() and thus don't want to flash scroll bars
0226     uint inresize : 1;
0227     uint use_cached_size_hint : 1;
0228     QSize cachedSizeHint;
0229 
0230     inline int contentsX() const
0231     {
0232         return -vx;
0233     }
0234     inline int contentsY() const
0235     {
0236         return -vy;
0237     }
0238     inline int contentsWidth() const
0239     {
0240         return vwidth;
0241     }
0242 };
0243 
0244 inline KtlQ3ScrollViewData::~KtlQ3ScrollViewData()
0245 {
0246     // children.setAutoDelete(true); // 2018.12.08
0247     for (QList<QSVChildRec *>::iterator it = children.begin(); it != children.end(); ++it) {
0248         QSVChildRec *r = *it;
0249         delete r;
0250     }
0251     children.removeAll(nullptr);
0252 }
0253 
0254 QSVChildRec *KtlQ3ScrollViewData::ancestorRec(QWidget *w)
0255 {
0256     if (clipped_viewport) {
0257         while (w->parentWidget() != clipped_viewport) {
0258             w = w->parentWidget();
0259             if (!w)
0260                 return nullptr;
0261         }
0262     } else {
0263         while (w->parentWidget() != viewport) {
0264             w = w->parentWidget();
0265             if (!w)
0266                 return nullptr;
0267         }
0268     }
0269     return rec(w);
0270 }
0271 
0272 void KtlQ3ScrollViewData::hideOrShowAll(KtlQ3ScrollView *sv, bool isScroll)
0273 {
0274     if (!clipped_viewport)
0275         return;
0276     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()) {
0277         // clipped_viewport still covers viewport
0278         if (static_bg) {
0279             // clipped_viewport->repaint(true); // 2018.11.30
0280             clipped_viewport->repaint();
0281         } else if ((!isScroll && !clipped_viewport->testAttribute(Qt::WA_StaticContents)) || static_bg)
0282             clipped_viewport->update();
0283     } else {
0284         // Re-center
0285         int nx = (viewport->width() - clipped_viewport->width()) / 2;
0286         int ny = (viewport->height() - clipped_viewport->height()) / 2;
0287         clipped_viewport->move(nx, ny);
0288         clipped_viewport->update();
0289     }
0290     // for (QSVChildRec *r = children.first(); r; r=children.next()) {   // 2018.12.08
0291     //    r->hideOrShow(sv, clipped_viewport);
0292     //}
0293     for (QList<QSVChildRec *>::iterator it = children.begin(); it != children.end(); ++it) {
0294         QSVChildRec *r = *it;
0295         r->hideOrShow(sv, clipped_viewport);
0296     }
0297 }
0298 
0299 void KtlQ3ScrollViewData::moveAllBy(int dx, int dy)
0300 {
0301     if (clipped_viewport && !static_bg) {
0302         clipped_viewport->move(clipped_viewport->x() + dx, clipped_viewport->y() + dy);
0303     } else {
0304         // for (QSVChildRec *r = children.first(); r; r=children.next()) { // 2018.12.07
0305         //    r->child->move(r->child->x()+dx,r->child->y()+dy);
0306         //}
0307         for (QList<QSVChildRec *>::iterator it = children.begin(); it != children.end(); ++it) {
0308             QSVChildRec *r = *it;
0309             r->child->move(r->child->x() + dx, r->child->y() + dy);
0310         }
0311 
0312         if (static_bg) {
0313             // viewport->repaint(true); // 2018.11.30
0314             viewport->repaint();
0315         }
0316     }
0317 }
0318 
0319 bool KtlQ3ScrollViewData::anyVisibleChildren()
0320 {
0321     // for (QSVChildRec *r = children.first(); r; r=children.next()) {   // 2018.12.08
0322     //    if (r->child->isVisible()) return true;
0323     //}
0324     for (QList<QSVChildRec *>::iterator it = children.begin(); it != children.end(); ++it) {
0325         QSVChildRec *r = *it;
0326         if (r->child->isVisible())
0327             return true;
0328     }
0329     return false;
0330 }
0331 
0332 void KtlQ3ScrollViewData::autoMove(KtlQ3ScrollView *sv)
0333 {
0334     if (policy == KtlQ3ScrollView::AutoOne) {
0335         QSVChildRec *r = children.first();
0336         if (r)
0337             sv->setContentsPos(-r->child->x(), -r->child->y());
0338     }
0339 }
0340 
0341 void KtlQ3ScrollViewData::autoResize(KtlQ3ScrollView *sv)
0342 {
0343     if (policy == KtlQ3ScrollView::AutoOne) {
0344         QSVChildRec *r = children.first();
0345         if (r)
0346             sv->resizeContents(r->child->width(), r->child->height());
0347     }
0348 }
0349 
0350 void KtlQ3ScrollViewData::autoResizeHint(KtlQ3ScrollView *sv)
0351 {
0352     if (policy == KtlQ3ScrollView::AutoOne) {
0353         QSVChildRec *r = children.first();
0354         if (r) {
0355             QSize s = r->child->sizeHint();
0356             if (s.isValid())
0357                 r->child->resize(s);
0358         }
0359     } else if (policy == KtlQ3ScrollView::AutoOneFit) {
0360         QSVChildRec *r = children.first();
0361         if (r) {
0362             QSize sh = r->child->sizeHint();
0363             sh = sh.boundedTo(r->child->maximumSize());
0364             sv->resizeContents(sh.width(), sh.height());
0365         }
0366     }
0367 }
0368 
0369 void KtlQ3ScrollViewData::viewportResized(int w, int h)
0370 {
0371     if (policy == KtlQ3ScrollView::AutoOneFit) {
0372         QSVChildRec *r = children.first();
0373         if (r) {
0374             QSize sh = r->child->sizeHint();
0375             sh = sh.boundedTo(r->child->maximumSize());
0376             r->child->resize(qMax(w, sh.width()), qMax(h, sh.height()));
0377         }
0378     }
0379 }
0380 
0381 /*!
0382     \class KtlQ3ScrollView
0383     \brief The KtlQ3ScrollView widget provides a scrolling area with on-demand scroll bars.
0384 
0385     \compat
0386 
0387     The KtlQ3ScrollView is a large canvas - potentially larger than the
0388     coordinate system normally supported by the underlying window
0389     system. This is important because it is quite easy to go beyond
0390     these limitations (e.g. many web pages are more than 32000 pixels
0391     high). Additionally, the KtlQ3ScrollView can have QWidgets positioned
0392     on it that scroll around with the drawn content. These sub-widgets
0393     can also have positions outside the normal coordinate range (but
0394     they are still limited in size).
0395 
0396     To provide content for the widget, inherit from KtlQ3ScrollView,
0397     reimplement drawContents() and use resizeContents() to set the
0398     size of the viewed area. Use addChild() and moveChild() to
0399     position widgets on the view.
0400 
0401     To use KtlQ3ScrollView effectively it is important to understand its
0402     widget structure in the three styles of use: a single large child
0403     widget, a large panning area with some widgets and a large panning
0404     area with many widgets.
0405 
0406     \section1 Using One Big Widget
0407 
0408     \img qscrollview-vp2.png
0409 
0410     The first, simplest usage of KtlQ3ScrollView (depicted above), is
0411     appropriate for scrolling areas that are never more than about
0412     4000 pixels in either dimension (this is about the maximum
0413     reliable size on X11 servers). In this usage, you just make one
0414     large child in the KtlQ3ScrollView. The child should be a child of the
0415     viewport() of the scrollview and be added with addChild():
0416     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 0
0417     You can go on to add arbitrary child widgets to the single child
0418     in the scrollview as you would with any widget:
0419     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 1
0420 
0421     Here the KtlQ3ScrollView has four children: the viewport(), the
0422     verticalScrollBar(), the horizontalScrollBar() and a small
0423     cornerWidget(). The viewport() has one child: the QWidget. The
0424     QWidget has the three QLabel objects as child widgets. When the view
0425     is scrolled, the QWidget is moved; its children move with it as
0426     child widgets normally do.
0427 
0428     \section1 Using a Very Big View with Some Widgets
0429 
0430     \img qscrollview-vp.png
0431 
0432     The second usage of KtlQ3ScrollView (depicted above) is appropriate
0433     when few, if any, widgets are on a very large scrolling area that
0434     is potentially larger than 4000 pixels in either dimension. In
0435     this usage you call resizeContents() to set the size of the area
0436     and reimplement drawContents() to paint the contents. You may also
0437     add some widgets by making them children of the viewport() and
0438     adding them with addChild() (this is the same as the process for
0439     the single large widget in the previous example):
0440     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 2
0441     Here, the KtlQ3ScrollView has the same four children: the viewport(),
0442     the verticalScrollBar(), the horizontalScrollBar() and a small
0443     cornerWidget(). The viewport() has the three QLabel objects as
0444     child widgets. When the view is scrolled, the scrollview moves the
0445     child widgets individually.
0446 
0447     \section1 Using a Very Big View with Many Widgets
0448 
0449     \img qscrollview-cl.png
0450 
0451     The final usage of KtlQ3ScrollView (depicted above) is appropriate
0452     when many widgets are on a very large scrolling area that is
0453     potentially larger than 4000 pixels in either dimension. In this
0454     usage you call resizeContents() to set the size of the area and
0455     reimplement drawContents() to paint the contents. You then call
0456     enableClipper(true) and add widgets, again by making them children
0457     of the viewport(), and adding them with addChild():
0458     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 3
0459 
0460     Here, the KtlQ3ScrollView has four children:  the clipper() (not the
0461     viewport() this time), the verticalScrollBar(), the
0462     horizontalScrollBar() and a small cornerWidget(). The clipper()
0463     has one child: the viewport(). The viewport() has the same three
0464     labels as child widgets. When the view is scrolled the viewport()
0465     is moved; its children move with it as child widgets normally do.
0466 
0467     \target allviews
0468     \section1 Details Relevant for All Views
0469 
0470     Normally you will use the first or third method if you want any
0471     child widgets in the view.
0472 
0473     Note that the widget you see in the scrolled area is the
0474     viewport() widget, not the KtlQ3ScrollView itself. So to turn mouse
0475     tracking on, for example, use viewport()->setMouseTracking(true).
0476 
0477     To enable drag-and-drop, you would setAcceptDrops(true) on the
0478     KtlQ3ScrollView (because drag-and-drop events propagate to the
0479     parent). But to work out the logical position in the view, you
0480     would need to map the drop co-ordinate from being relative to the
0481     KtlQ3ScrollView to being relative to the contents; use the function
0482     viewportToContents() for this.
0483 
0484     To handle mouse events on the scrolling area, subclass scrollview
0485     as you would subclass other widgets, but rather than
0486     reimplementing mousePressEvent(), reimplement
0487     contentsMousePressEvent() instead. The contents specific event
0488     handlers provide translated events in the coordinate system of the
0489     scrollview. If you reimplement mousePressEvent(), you'll get
0490     called only when part of the KtlQ3ScrollView is clicked: and the only
0491     such part is the "corner" (if you don't set a cornerWidget()) and
0492     the frame; everything else is covered up by the viewport, clipper
0493     or scroll bars.
0494 
0495     When you construct a KtlQ3ScrollView, some of the window flags apply
0496     to the viewport() instead of being sent to the QWidget constructor
0497     for the KtlQ3ScrollView.
0498 
0499     \list
0500 
0501     \i An image-manipulation widget would use \c
0502     WNoAutoErase|WStaticContents because the widget draws all pixels
0503     itself, and when its size increases, it only needs a paint event
0504     for the new part because the old part remains unchanged.
0505 
0506     \i A scrolling game widget in which the background scrolls as the
0507     characters move might use \c WNoAutoErase (in addition to \c
0508     WStaticContents) so that the window system background does not
0509     flash in and out during scrolling.
0510 
0511     \i A word processing widget might use \c WNoAutoErase and repaint
0512     itself line by line to get a less-flickery resizing. If the widget
0513     is in a mode in which no text justification can take place, it
0514     might use \c WStaticContents too, so that it would only get a
0515     repaint for the newly visible parts.
0516 
0517     \endlist
0518 
0519     Child widgets may be moved using addChild() or moveChild(). Use
0520     childX() and childY() to get the position of a child widget.
0521 
0522     A widget may be placed in the corner between the vertical and
0523     horizontal scroll bars with setCornerWidget(). You can get access
0524     to the scroll bars using horizontalScrollBar() and
0525     verticalScrollBar(), and to the viewport with viewport(). The
0526     scroll view can be scrolled using scrollBy(), ensureVisible(),
0527     setContentsPos() or center().
0528 
0529     The visible area is given by visibleWidth() and visibleHeight(),
0530     and the contents area by contentsWidth() and contentsHeight(). The
0531     contents may be repainted using one of the repaintContents() or
0532     updateContents() functions.
0533 
0534     Coordinate conversion is provided by contentsToViewport() and
0535     viewportToContents().
0536 
0537     The contentsMoving() signal is emitted just before the contents
0538     are moved to a new position.
0539 
0540     \warning KtlQ3ScrollView currently does not erase the background when
0541     resized, i.e. you must always clear the background manually in
0542     scrollview subclasses. This will change in a future version of Qt
0543     and we recommend specifying the \c WNoAutoErase flag explicitly.
0544 */
0545 
0546 /*!
0547     \enum KtlQ3ScrollView::ResizePolicy
0548 
0549     This enum type is used to control a KtlQ3ScrollView's reaction to
0550     resize events.
0551 
0552     \value Default  the KtlQ3ScrollView selects one of the other settings
0553     automatically when it has to. In this version of Qt, KtlQ3ScrollView
0554     changes to \c Manual if you resize the contents with
0555     resizeContents() and to \c AutoOne if a child is added.
0556 
0557     \value Manual  the contents stays the size set by resizeContents().
0558 
0559     \value AutoOne  if there is only one child widget the contents stays
0560     the size of that widget. Otherwise the behavior is undefined.
0561 
0562     \value AutoOneFit if there is only one child widget the contents stays
0563     the size of that widget's sizeHint(). If the scrollview is resized
0564     larger than the child's sizeHint(), the child will be resized to
0565     fit. If there is more than one child, the behavior is undefined.
0566 
0567 */
0568 //####  The widget will be resized to its sizeHint() when a LayoutHint event
0569 //#### is received
0570 
0571 /*!
0572     Constructs a KtlQ3ScrollView called \a name with parent \a parent and
0573     widget flags \a f.
0574 
0575     The widget flags \c WStaticContents, \c WNoAutoErase and \c
0576     WPaintClever are propagated to the viewport() widget. The other
0577     widget flags are propagated to the parent constructor as usual.
0578 */
0579 
0580 KtlQ3ScrollView::KtlQ3ScrollView(QWidget *parent, const char *name, Qt::WindowFlags f)
0581     : KtlQ3Frame(parent, name, f & (~Qt::WA_StaticContents) /*& (~Qt::WNoAutoErase) & (~Qt::WResizeNoErase) */)
0582 {
0583     Qt::WindowFlags flags = /* Qt::WResizeNoErase |  (f&Qt::WPaintClever)
0584         | (f&Qt::WRepaintNoErase) | */
0585         (f & Qt::WA_StaticContents);
0586     d = new KtlQ3ScrollViewData(this, flags);
0587 
0588 #ifndef QT_NO_DRAGANDDROP
0589     connect(&d->autoscroll_timer, SIGNAL(timeout()), this, SLOT(doDragAutoScroll()));
0590 #endif
0591 
0592     connect(d->hbar, SIGNAL(valueChanged(int)), this, SLOT(hslide(int)));
0593     connect(d->vbar, SIGNAL(valueChanged(int)), this, SLOT(vslide(int)));
0594 
0595     connect(d->hbar, SIGNAL(sliderPressed()), this, SLOT(hbarIsPressed()));
0596     connect(d->hbar, SIGNAL(sliderReleased()), this, SLOT(hbarIsReleased()));
0597     connect(d->vbar, SIGNAL(sliderPressed()), this, SLOT(vbarIsPressed()));
0598     connect(d->vbar, SIGNAL(sliderReleased()), this, SLOT(vbarIsReleased()));
0599 
0600     d->viewport->installEventFilter(this);
0601 
0602     connect(&d->scrollbar_timer, SIGNAL(timeout()), this, SLOT(updateScrollBars()));
0603 
0604     setFrameStyle(KtlQ3Frame::StyledPanel | KtlQ3Frame::Sunken);
0605     setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
0606     setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
0607 }
0608 
0609 /*!
0610     Destroys the KtlQ3ScrollView. Any children added with addChild() will
0611     be deleted.
0612 */
0613 KtlQ3ScrollView::~KtlQ3ScrollView()
0614 {
0615     // Be careful not to get all those useless events...
0616     if (d->clipped_viewport)
0617         d->clipped_viewport->removeEventFilter(this);
0618     else
0619         d->viewport->removeEventFilter(this);
0620 
0621     // order is important
0622     // ~QWidget may cause a WM_ERASEBKGND on Windows
0623     delete d->vbar;
0624     d->vbar = nullptr;
0625     delete d->hbar;
0626     d->hbar = nullptr;
0627     delete d->viewport;
0628     d->viewport = nullptr;
0629     delete d;
0630     d = nullptr;
0631 }
0632 
0633 /*!
0634     \fn void KtlQ3ScrollView::horizontalSliderPressed()
0635 
0636     This signal is emitted whenever the user presses the horizontal slider.
0637 */
0638 /*!
0639     \fn void KtlQ3ScrollView::horizontalSliderReleased()
0640 
0641     This signal is emitted whenever the user releases the horizontal slider.
0642 */
0643 /*!
0644     \fn void KtlQ3ScrollView::verticalSliderPressed()
0645 
0646     This signal is emitted whenever the user presses the vertical slider.
0647 */
0648 /*!
0649     \fn void KtlQ3ScrollView::verticalSliderReleased()
0650 
0651     This signal is emitted whenever the user releases the vertical slider.
0652 */
0653 void KtlQ3ScrollView::hbarIsPressed()
0654 {
0655     d->hbarPressed = true;
0656     emit(horizontalSliderPressed());
0657 }
0658 
0659 void KtlQ3ScrollView::hbarIsReleased()
0660 {
0661     d->hbarPressed = false;
0662     emit(horizontalSliderReleased());
0663 }
0664 
0665 /*!
0666     Returns true if horizontal slider is pressed by user; otherwise returns false.
0667 */
0668 bool KtlQ3ScrollView::isHorizontalSliderPressed()
0669 {
0670     return d->hbarPressed;
0671 }
0672 
0673 void KtlQ3ScrollView::vbarIsPressed()
0674 {
0675     d->vbarPressed = true;
0676     emit(verticalSliderPressed());
0677 }
0678 
0679 void KtlQ3ScrollView::vbarIsReleased()
0680 {
0681     d->vbarPressed = false;
0682     emit(verticalSliderReleased());
0683 }
0684 
0685 /*!
0686     Returns true if vertical slider is pressed by user; otherwise returns false.
0687 */
0688 bool KtlQ3ScrollView::isVerticalSliderPressed()
0689 {
0690     return d->vbarPressed;
0691 }
0692 
0693 /*!
0694     \internal
0695 */
0696 void KtlQ3ScrollView::styleChange(QStyle &/*old*/)
0697 {
0698     // QWidget::styleChange(old); // 2019.04.14
0699     updateScrollBars();
0700     d->cachedSizeHint = QSize();
0701 }
0702 
0703 /*!
0704     \internal
0705 */
0706 void KtlQ3ScrollView::fontChange(const QFont &/*old*/)
0707 {
0708     // QWidget::fontChange(old); // 2019.04.14
0709     updateScrollBars();
0710     d->cachedSizeHint = QSize();
0711 }
0712 
0713 void KtlQ3ScrollView::hslide(int pos)
0714 {
0715     if (!d->signal_choke) {
0716         moveContents(-pos, -d->contentsY());
0717         QGuiApplication::sync();
0718     }
0719 }
0720 
0721 void KtlQ3ScrollView::vslide(int pos)
0722 {
0723     if (!d->signal_choke) {
0724         moveContents(-d->contentsX(), -pos);
0725         QGuiApplication::sync();
0726     }
0727 }
0728 
0729 /*!
0730     Called when the horizontal scroll bar geometry changes. This is
0731     provided as a protected function so that subclasses can do
0732     interesting things such as providing extra buttons in some of the
0733     space normally used by the scroll bars.
0734 
0735     The default implementation simply gives all the space to \a hbar.
0736     The new geometry is given by \a x, \a y, \a w and \a h.
0737 
0738     \sa setVBarGeometry()
0739 */
0740 void KtlQ3ScrollView::setHBarGeometry(QScrollBar &hbar, int x, int y, int w, int h)
0741 {
0742     hbar.setGeometry(x, y, w, h);
0743 }
0744 
0745 /*!
0746     Called when the vertical scroll bar geometry changes. This is
0747     provided as a protected function so that subclasses can do
0748     interesting things such as providing extra buttons in some of the
0749     space normally used by the scroll bars.
0750 
0751     The default implementation simply gives all the space to \a vbar.
0752     The new geometry is given by \a x, \a y, \a w and \a h.
0753 
0754     \sa setHBarGeometry()
0755 */
0756 void KtlQ3ScrollView::setVBarGeometry(QScrollBar &vbar, int x, int y, int w, int h)
0757 {
0758     vbar.setGeometry(x, y, w, h);
0759 }
0760 
0761 /*!
0762     Returns the viewport size for size (\a x, \a y).
0763 
0764     The viewport size depends on (\a x, \a y) (the size of the contents),
0765     the size of this widget and the modes of the horizontal and
0766     vertical scroll bars.
0767 
0768     This function permits widgets that can trade vertical and
0769     horizontal space for each other to control scroll bar appearance
0770     better. For example, a word processor or web browser can control
0771     the width of the right margin accurately, whether or not there
0772     needs to be a vertical scroll bar.
0773 */
0774 
0775 QSize KtlQ3ScrollView::viewportSize(int x, int y) const
0776 {
0777     int fw = frameWidth();
0778     int lmarg = fw + d->l_marg;
0779     int rmarg = fw + d->r_marg;
0780     int tmarg = fw + d->t_marg;
0781     int bmarg = fw + d->b_marg;
0782 
0783     int w = width();
0784     int h = height();
0785 
0786     bool needh, needv;
0787     bool showh, showv;
0788     int hsbExt = horizontalScrollBar()->sizeHint().height();
0789     int vsbExt = verticalScrollBar()->sizeHint().width();
0790 
0791     if (d->policy != AutoOne || d->anyVisibleChildren()) {
0792         // Do we definitely need the scroll bar?
0793         needh = w - lmarg - rmarg < x;
0794         needv = h - tmarg - bmarg < y;
0795 
0796         // Do we intend to show the scroll bar?
0797         if (d->hMode == AlwaysOn)
0798             showh = true;
0799         else if (d->hMode == AlwaysOff)
0800             showh = false;
0801         else
0802             showh = needh;
0803 
0804         if (d->vMode == AlwaysOn)
0805             showv = true;
0806         else if (d->vMode == AlwaysOff)
0807             showv = false;
0808         else
0809             showv = needv;
0810 
0811         // Given other scroll bar will be shown, NOW do we need one?
0812         if (showh && h - vsbExt - tmarg - bmarg < y) {
0813             if (d->vMode == Auto)
0814                 showv = true;
0815         }
0816         if (showv && w - hsbExt - lmarg - rmarg < x) {
0817             if (d->hMode == Auto)
0818                 showh = true;
0819         }
0820     } else {
0821         // Scroll bars not needed, only show scroll bar that are always on.
0822         showh = d->hMode == AlwaysOn;
0823         showv = d->vMode == AlwaysOn;
0824     }
0825 
0826     return QSize(w - lmarg - rmarg - (showv ? vsbExt : 0), h - tmarg - bmarg - (showh ? hsbExt : 0));
0827 }
0828 
0829 /*!
0830     Updates scroll bars: all possibilities are considered. You should
0831     never need to call this in your code.
0832 */
0833 void KtlQ3ScrollView::updateScrollBars()
0834 {
0835     if (!horizontalScrollBar() && !verticalScrollBar())
0836         return;
0837 
0838     // I support this should use viewportSize()... but it needs
0839     // so many of the temporary variables from viewportSize.  hm.
0840     int fw = frameWidth();
0841     int lmarg = fw + d->l_marg;
0842     int rmarg = fw + d->r_marg;
0843     int tmarg = fw + d->t_marg;
0844     int bmarg = fw + d->b_marg;
0845 
0846     int w = width();
0847     int h = height();
0848 
0849     int portw, porth;
0850 
0851     bool needh;
0852     bool needv;
0853     bool showh;
0854     bool showv;
0855     bool showc = false;
0856 
0857     int hsbExt = horizontalScrollBar()->sizeHint().height();
0858     int vsbExt = verticalScrollBar()->sizeHint().width();
0859 
0860     QSize oldVisibleSize(visibleWidth(), visibleHeight());
0861 
0862     if (d->policy != AutoOne || d->anyVisibleChildren()) {
0863         // Do we definitely need the scroll bar?
0864         needh = w - lmarg - rmarg < d->contentsWidth();
0865         if (d->inresize)
0866             needh = !horizontalScrollBar()->isHidden();
0867         needv = h - tmarg - bmarg < contentsHeight();
0868 
0869         // Do we intend to show the scroll bar?
0870         if (d->hMode == AlwaysOn)
0871             showh = true;
0872         else if (d->hMode == AlwaysOff)
0873             showh = false;
0874         else
0875             showh = needh;
0876 
0877         if (d->vMode == AlwaysOn)
0878             showv = true;
0879         else if (d->vMode == AlwaysOff)
0880             showv = false;
0881         else
0882             showv = needv;
0883 
0884 #ifdef Q_WS_MAC
0885         bool mac_need_scroll = false;
0886         if (!parentWidget()) {
0887             mac_need_scroll = true;
0888         } else {
0889             QWidget *tlw = window();
0890             // #ifndef QT_MAC_USE_COCOA           // 2018.10.18 - do not depend on internal headers
0891             //             QPoint tlw_br = QPoint(tlw->width(), tlw->height()),
0892             //                     my_br = qt_mac_posInWindow(this) + QPoint(w, h);
0893             //             if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3)
0894             // #endif
0895             mac_need_scroll = true;
0896         }
0897         if (mac_need_scroll) {
0898             // #ifndef QT_MAC_USE_COCOA           // 2018.10.18 - do not depend on internal headers
0899             //             WindowAttributes attr;
0900             //             GetWindowAttributes((WindowPtr)handle(), &attr);
0901             //             mac_need_scroll = (attr & kWindowResizableAttribute);
0902             // #endif
0903         }
0904         if (mac_need_scroll) {
0905             showc = true;
0906             if (d->vMode == Auto)
0907                 showv = true;
0908             if (d->hMode == Auto)
0909                 showh = true;
0910         }
0911 #endif
0912 
0913         // Given other scroll bar will be shown, NOW do we need one?
0914         if (showh && h - vsbExt - tmarg - bmarg < contentsHeight()) {
0915             needv = true;
0916             if (d->vMode == Auto)
0917                 showv = true;
0918         }
0919         if (showv && !d->inresize && w - hsbExt - lmarg - rmarg < d->contentsWidth()) {
0920             needh = true;
0921             if (d->hMode == Auto)
0922                 showh = true;
0923         }
0924     } else {
0925         // Scrollbars not needed, only show scroll bar that are always on.
0926         needh = needv = false;
0927         showh = d->hMode == AlwaysOn;
0928         showv = d->vMode == AlwaysOn;
0929     }
0930 
0931     bool sc = d->signal_choke;
0932     d->signal_choke = true;
0933 
0934     // Hide unneeded scroll bar, calculate viewport size
0935     if (showh) {
0936         porth = h - hsbExt - tmarg - bmarg;
0937     } else {
0938         if (!needh)
0939             d->hbar->setValue(0);
0940         d->hbar->hide();
0941         porth = h - tmarg - bmarg;
0942     }
0943     if (showv) {
0944         portw = w - vsbExt - lmarg - rmarg;
0945     } else {
0946         if (!needv)
0947             d->vbar->setValue(0);
0948         d->vbar->hide();
0949         portw = w - lmarg - rmarg;
0950     }
0951 
0952     // Configure scroll bars that we will show
0953     if (needv) {
0954         d->vbar->setRange(0, contentsHeight() - porth);
0955         // d->vbar->setSteps(KtlQ3ScrollView::d->vbar->lineStep(), porth); // 2018.11.30
0956         d->vbar->setSingleStep(KtlQ3ScrollView::d->vbar->singleStep());
0957         d->vbar->setPageStep(porth);
0958     } else {
0959         d->vbar->setRange(0, 0);
0960     }
0961     if (needh) {
0962         d->hbar->setRange(0, qMax(0, d->contentsWidth() - portw));
0963         // d->hbar->setSteps(KtlQ3ScrollView::d->hbar->lineStep(), portw); // 2018.11.30
0964         d->hbar->setSingleStep(KtlQ3ScrollView::d->hbar->singleStep());
0965         d->hbar->setPageStep(portw);
0966     } else {
0967         d->hbar->setRange(0, 0);
0968     }
0969 
0970     // Position the scroll bars, viewport and corner widget.
0971     int bottom;
0972     bool reverse = QApplication::layoutDirection() == Qt::RightToLeft;
0973     int xoffset = (reverse && (showv || cornerWidget())) ? vsbExt : 0;
0974     int xpos = reverse ? 0 : w - vsbExt;
0975     bool frameContentsOnly = style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
0976 
0977     if (!frameContentsOnly) {
0978         if (reverse)
0979             xpos += fw;
0980         else
0981             xpos -= fw;
0982     }
0983     if (showh) {
0984         int right = (showc || showv || cornerWidget()) ? w - vsbExt : w;
0985         if (!frameContentsOnly)
0986             setHBarGeometry(*d->hbar, fw + xoffset, h - hsbExt - fw, right - fw - fw, hsbExt);
0987         else
0988             setHBarGeometry(*d->hbar, 0 + xoffset, h - hsbExt, right, hsbExt);
0989         bottom = h - hsbExt;
0990     } else {
0991         bottom = h;
0992     }
0993     if (showv) {
0994         clipper()->setGeometry(lmarg + xoffset, tmarg, w - vsbExt - lmarg - rmarg, bottom - tmarg - bmarg);
0995         d->viewportResized(w - vsbExt - lmarg - rmarg, bottom - tmarg - bmarg);
0996         if (!frameContentsOnly)
0997             changeFrameRect(QRect(0, 0, w, h));
0998         else
0999             changeFrameRect(QRect(xoffset, 0, w - vsbExt, bottom));
1000         if (showc || cornerWidget()) {
1001             if (!frameContentsOnly)
1002                 setVBarGeometry(*d->vbar, xpos, fw, vsbExt, h - hsbExt - fw - fw);
1003             else
1004                 setVBarGeometry(*d->vbar, xpos, 0, vsbExt, h - hsbExt);
1005         } else {
1006             if (!frameContentsOnly)
1007                 setVBarGeometry(*d->vbar, xpos, fw, vsbExt, bottom - fw - fw);
1008             else
1009                 setVBarGeometry(*d->vbar, xpos, 0, vsbExt, bottom);
1010         }
1011     } else {
1012         if (!frameContentsOnly)
1013             changeFrameRect(QRect(0, 0, w, h));
1014         else
1015             changeFrameRect(QRect(0, 0, w, bottom));
1016         clipper()->setGeometry(lmarg, tmarg, w - lmarg - rmarg, bottom - tmarg - bmarg);
1017         d->viewportResized(w - lmarg - rmarg, bottom - tmarg - bmarg);
1018     }
1019 
1020     QWidget *corner = d->corner;
1021     if (d->corner) {
1022         if (!frameContentsOnly)
1023             corner->setGeometry(xpos, h - hsbExt - fw, vsbExt, hsbExt);
1024         else
1025             corner->setGeometry(xpos, h - hsbExt, vsbExt, hsbExt);
1026     }
1027 
1028     d->signal_choke = sc;
1029 
1030     if (d->contentsX() + visibleWidth() > d->contentsWidth()) {
1031         int x;
1032 #if 0
1033         if (reverse)
1034             x =qMin(0,d->contentsWidth()-visibleWidth());
1035         else
1036 #endif
1037         x = qMax(0, d->contentsWidth() - visibleWidth());
1038         d->hbar->setValue(x);
1039         // Do it even if it is recursive
1040         moveContents(-x, -d->contentsY());
1041     }
1042     if (d->contentsY() + visibleHeight() > contentsHeight()) {
1043         int y = qMax(0, contentsHeight() - visibleHeight());
1044         d->vbar->setValue(y);
1045         // Do it even if it is recursive
1046         moveContents(-d->contentsX(), -y);
1047     }
1048 
1049     // Finally, show the scroll bars
1050     if (showh && (d->hbar->isHidden() || !d->hbar->isVisible()))
1051         d->hbar->show();
1052     if (showv && (d->vbar->isHidden() || !d->vbar->isVisible()))
1053         d->vbar->show();
1054 
1055     d->signal_choke = true;
1056     d->vbar->setValue(d->contentsY());
1057     d->hbar->setValue(d->contentsX());
1058     d->signal_choke = false;
1059 
1060     QSize newVisibleSize(visibleWidth(), visibleHeight());
1061     if (d->clipped_viewport && oldVisibleSize != newVisibleSize) {
1062         QResizeEvent e(newVisibleSize, oldVisibleSize);
1063         viewportResizeEvent(&e);
1064     }
1065 }
1066 
1067 /*!
1068     \reimp
1069 */
1070 void KtlQ3ScrollView::setVisible(bool visible)
1071 {
1072     if (visible && !isVisible()) {
1073         QWidget::setVisible(visible);
1074         updateScrollBars();
1075         d->hideOrShowAll(this);
1076     } else {
1077         QWidget::setVisible(visible);
1078     }
1079 }
1080 
1081 /*!
1082     \internal
1083  */
1084 void KtlQ3ScrollView::resize(int w, int h)
1085 {
1086     QWidget::resize(w, h);
1087 }
1088 
1089 /*!
1090     \internal
1091 */
1092 void KtlQ3ScrollView::resize(const QSize &s)
1093 {
1094     resize(s.width(), s.height());
1095 }
1096 
1097 /*!
1098     \reimp
1099 */
1100 void KtlQ3ScrollView::resizeEvent(QResizeEvent */*event*/)
1101 {
1102     // KtlQ3Frame::resizeEvent();
1103 
1104 #if 0
1105     if (QApplication::reverseLayout()) {
1106         d->fake_scroll = true;
1107         scrollBy(-event->size().width() + event->oldSize().width(), 0);
1108         d->fake_scroll = false;
1109     }
1110 #endif
1111 
1112     bool inresize = d->inresize;
1113     d->inresize = true;
1114     updateScrollBars();
1115     d->inresize = inresize;
1116     // d->scrollbar_timer.start(0, true); // 2018.11.30
1117     d->scrollbar_timer.setSingleShot(true);
1118     d->scrollbar_timer.start(0);
1119 
1120     d->hideOrShowAll(this);
1121 }
1122 
1123 /*!
1124     \reimp
1125 */
1126 void KtlQ3ScrollView::mousePressEvent(QMouseEvent *e)
1127 {
1128     e->ignore();
1129 }
1130 
1131 /*!
1132     \reimp
1133 */
1134 void KtlQ3ScrollView::mouseReleaseEvent(QMouseEvent *e)
1135 {
1136     e->ignore();
1137 }
1138 
1139 /*!
1140     \reimp
1141 */
1142 void KtlQ3ScrollView::mouseDoubleClickEvent(QMouseEvent *e)
1143 {
1144     e->ignore();
1145 }
1146 
1147 /*!
1148     \reimp
1149 */
1150 void KtlQ3ScrollView::mouseMoveEvent(QMouseEvent *e)
1151 {
1152     e->ignore();
1153 }
1154 
1155 /*!
1156     \reimp
1157 */
1158 #ifndef QT_NO_WHEELEVENT
1159 void KtlQ3ScrollView::wheelEvent(QWheelEvent *e)
1160 {
1161     /* QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()),
1162                     e->globalPos(), e->delta(), e->state());  - 2018.11.30*/
1163     /* QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()), e->globalPos(), e->delta(), e->buttons(), e->modifiers());  - 2023.04.10 */
1164     QWheelEvent ce(viewport()->mapFromGlobal(e->globalPosition().toPoint()),
1165                 e->globalPosition(),
1166                 e->pixelDelta(),
1167                 e->angleDelta(),
1168                 e->buttons(),
1169                 e->modifiers(),
1170                 e->phase(),
1171                 e->inverted());
1172     viewportWheelEvent(&ce);
1173     if (!ce.isAccepted()) {
1174         if ((e->angleDelta().x() != 0) && horizontalScrollBar())
1175             horizontalScrollBar()->event(e);
1176         else if ((e->angleDelta().y() != 0) && verticalScrollBar())
1177             verticalScrollBar()->event(e);
1178     } else {
1179         e->accept();
1180     }
1181 }
1182 #endif
1183 
1184 /*!
1185     \reimp
1186 */
1187 void KtlQ3ScrollView::contextMenuEvent(QContextMenuEvent *e)
1188 {
1189     if (e->reason() != QContextMenuEvent::Keyboard) {
1190         e->ignore();
1191         return;
1192     }
1193 
1194     /* QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()),
1195                           e->globalPos(), e->state()); - 2018.11.30 */
1196     QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()), e->globalPos(), e->modifiers());
1197     viewportContextMenuEvent(&ce);
1198     if (ce.isAccepted())
1199         e->accept();
1200     else
1201         e->ignore();
1202 }
1203 
1204 KtlQ3ScrollView::ScrollBarMode KtlQ3ScrollView::vScrollBarMode() const
1205 {
1206     return d->vMode;
1207 }
1208 
1209 /*!
1210     \enum KtlQ3ScrollView::ScrollBarMode
1211 
1212     This enum type describes the various modes of KtlQ3ScrollView's scroll
1213     bars.
1214 
1215     \value Auto  KtlQ3ScrollView shows a scroll bar when the content is
1216     too large to fit and not otherwise. This is the default.
1217 
1218     \value AlwaysOff  KtlQ3ScrollView never shows a scroll bar.
1219 
1220     \value AlwaysOn  KtlQ3ScrollView always shows a scroll bar.
1221 
1222     (The modes for the horizontal and vertical scroll bars are
1223     independent.)
1224 */
1225 
1226 /*!
1227     \property KtlQ3ScrollView::vScrollBarMode
1228     \brief the mode for the vertical scroll bar
1229 
1230     The default mode is KtlQ3ScrollView::Auto.
1231 
1232     \sa hScrollBarMode
1233 */
1234 void KtlQ3ScrollView::setVScrollBarMode(ScrollBarMode mode)
1235 {
1236     if (d->vMode != mode) {
1237         d->vMode = mode;
1238         updateScrollBars();
1239     }
1240 }
1241 
1242 /*!
1243     \property KtlQ3ScrollView::hScrollBarMode
1244     \brief the mode for the horizontal scroll bar
1245 
1246     The default mode is KtlQ3ScrollView::Auto.
1247 
1248     \sa vScrollBarMode
1249 */
1250 KtlQ3ScrollView::ScrollBarMode KtlQ3ScrollView::hScrollBarMode() const
1251 {
1252     return d->hMode;
1253 }
1254 
1255 void KtlQ3ScrollView::setHScrollBarMode(ScrollBarMode mode)
1256 {
1257     if (d->hMode != mode) {
1258         d->hMode = mode;
1259         updateScrollBars();
1260     }
1261 }
1262 
1263 /*!
1264     Returns the widget in the corner between the two scroll bars.
1265 
1266     By default, no corner widget is present.
1267 */
1268 QWidget *KtlQ3ScrollView::cornerWidget() const
1269 {
1270     return d->corner;
1271 }
1272 
1273 /*!
1274     Sets the widget in the \a corner between the two scroll bars.
1275 
1276     You will probably also want to set at least one of the scroll bar
1277     modes to \c AlwaysOn.
1278 
1279     Passing 0 shows no widget in the corner.
1280 
1281     Any previous \a corner widget is hidden.
1282 
1283     You may call setCornerWidget() with the same widget at different
1284     times.
1285 
1286     All widgets set here will be deleted by the KtlQ3ScrollView when it is
1287     destroyed unless you separately reparent the widget after setting
1288     some other corner widget (or 0).
1289 
1290     Any \e newly set widget should have no current parent.
1291 
1292     By default, no corner widget is present.
1293 
1294     \sa setVScrollBarMode(), setHScrollBarMode()
1295 */
1296 void KtlQ3ScrollView::setCornerWidget(QWidget *corner)
1297 {
1298     QWidget *oldcorner = d->corner;
1299     if (oldcorner != corner) {
1300         if (oldcorner)
1301             oldcorner->hide();
1302         d->corner = corner;
1303         if (corner)
1304             corner->setParent(this);
1305         updateScrollBars();
1306         if (corner)
1307             corner->show();
1308     }
1309 }
1310 
1311 void KtlQ3ScrollView::setResizePolicy(ResizePolicy r)
1312 {
1313     d->policy = r;
1314 }
1315 
1316 /*!
1317     \property KtlQ3ScrollView::resizePolicy
1318     \brief the resize policy
1319 
1320     The default is \c Default.
1321 
1322     \sa ResizePolicy
1323 */
1324 KtlQ3ScrollView::ResizePolicy KtlQ3ScrollView::resizePolicy() const
1325 {
1326     return d->policy;
1327 }
1328 
1329 /*!
1330     \internal
1331 */
1332 void KtlQ3ScrollView::setEnabled(bool enable)
1333 {
1334     KtlQ3Frame::setEnabled(enable);
1335 }
1336 
1337 /*!
1338     Removes the \a child widget from the scrolled area. Note that this
1339     happens automatically if the \a child is deleted.
1340 */
1341 void KtlQ3ScrollView::removeChild(QWidget *child)
1342 {
1343     if (!d || !child) // First check in case we are destructing
1344         return;
1345 
1346     QSVChildRec *r = d->rec(child);
1347     if (r)
1348         d->deleteChildRec(r);
1349 }
1350 
1351 /*!
1352     \internal
1353 */
1354 void KtlQ3ScrollView::removeChild(QObject *child)
1355 {
1356     // KtlQ3Frame::removeChild(child); // 2018.11.30
1357     if (child) {
1358         child->setParent(nullptr);
1359     }
1360 }
1361 
1362 /*!
1363     Inserts the widget, \a child, into the scrolled area positioned at
1364     (\a x, \a y). The position defaults to (0, 0). If the child is
1365     already in the view, it is just moved.
1366 
1367     You may want to call enableClipper(true) if you add a large number
1368     of widgets.
1369 */
1370 void KtlQ3ScrollView::addChild(QWidget *child, int x, int y)
1371 {
1372     if (!child) {
1373 #if defined(QT_CHECK_NULL)
1374         qWarning("KtlQ3ScrollView::addChild(): Cannot add null child");
1375 #endif
1376         return;
1377     }
1378     child->ensurePolished();
1379     // child->setBackgroundOrigin(WidgetOrigin); // 2018.11.30 - does nothing in qt4
1380 
1381     if (child->parentWidget() == viewport()) {
1382         // May already be there
1383         QSVChildRec *r = d->rec(child);
1384         if (r) {
1385             r->moveTo(this, x, y, d->clipped_viewport);
1386             if (d->policy > Manual) {
1387                 d->autoResizeHint(this);
1388                 d->autoResize(this); // #### better to just deal with this one widget!
1389             }
1390             return;
1391         }
1392     }
1393 
1394     if (d->children.isEmpty() && d->policy != Manual) {
1395         if (d->policy == Default)
1396             setResizePolicy(AutoOne);
1397         child->installEventFilter(this);
1398     } else if (d->policy == AutoOne) {
1399         child->removeEventFilter(this); //#### ?????
1400         setResizePolicy(Manual);
1401     }
1402     if (child->parentWidget() != viewport()) {
1403         // child->reparent(viewport(), 0, QPoint(0,0), false); // 2018.11.30
1404         child->setParent(viewport());
1405         child->setGeometry(0, 0, child->width(), child->height());
1406     }
1407     d->addChildRec(child, x, y)->hideOrShow(this, d->clipped_viewport);
1408 
1409     if (d->policy > Manual) {
1410         d->autoResizeHint(this);
1411         d->autoResize(this); // #### better to just deal with this one widget!
1412     }
1413 }
1414 
1415 /*!
1416     Repositions the \a child widget to (\a x, \a y). This function is
1417     the same as addChild().
1418 */
1419 void KtlQ3ScrollView::moveChild(QWidget *child, int x, int y)
1420 {
1421     addChild(child, x, y);
1422 }
1423 
1424 /*!
1425     Returns the X position of the given \a child widget. Use this
1426     rather than QWidget::x() for widgets added to the view.
1427 
1428     This function returns 0 if \a child has not been added to the view.
1429 */
1430 int KtlQ3ScrollView::childX(QWidget *child)
1431 {
1432     QSVChildRec *r = d->rec(child);
1433     return r ? r->x : 0;
1434 }
1435 
1436 /*!
1437     Returns the Y position of the given \a child widget. Use this
1438     rather than QWidget::y() for widgets added to the view.
1439 
1440     This function returns 0 if \a child has not been added to the view.
1441 */
1442 int KtlQ3ScrollView::childY(QWidget *child)
1443 {
1444     QSVChildRec *r = d->rec(child);
1445     return r ? r->y : 0;
1446 }
1447 
1448 /*! \fn bool KtlQ3ScrollView::childIsVisible(QWidget*)
1449   \obsolete
1450 
1451   Returns true if \a child is visible. This is equivalent
1452   to child->isVisible().
1453 */
1454 
1455 /*! \fn void KtlQ3ScrollView::showChild(QWidget* child, bool y)
1456   \obsolete
1457 
1458   Sets the visibility of \a child. Equivalent to
1459   QWidget::show() or QWidget::hide().
1460 */
1461 
1462 /*!
1463     This event filter ensures the scroll bars are updated when a
1464     single contents widget is resized, shown, hidden or destroyed; it
1465     passes mouse events to the KtlQ3ScrollView. The event is in \a e and
1466     the object is in \a obj.
1467 */
1468 
1469 bool KtlQ3ScrollView::eventFilter(QObject *obj, QEvent *e)
1470 {
1471     bool disabled = !(qobject_cast<QWidget *>(obj)->isEnabled());
1472     if (!d)
1473         return false; // we are destructing
1474     if (obj == d->viewport || obj == d->clipped_viewport) {
1475         switch (e->type()) {
1476             /* Forward many events to viewport...() functions */
1477         case QEvent::Paint:
1478             viewportPaintEvent(static_cast<QPaintEvent *>(e));
1479             break;
1480         case QEvent::Resize:
1481             if (!d->clipped_viewport)
1482                 viewportResizeEvent(static_cast<QResizeEvent *>(e));
1483             break;
1484         case QEvent::MouseButtonPress:
1485             if (disabled)
1486                 return false;
1487             viewportMousePressEvent(static_cast<QMouseEvent *>(e));
1488             if ((static_cast<QMouseEvent *>(e))->isAccepted())
1489                 return true;
1490             break;
1491         case QEvent::MouseButtonRelease:
1492             if (disabled)
1493                 return false;
1494             viewportMouseReleaseEvent(static_cast<QMouseEvent *>(e));
1495             if ((static_cast<QMouseEvent *>(e))->isAccepted())
1496                 return true;
1497             break;
1498         case QEvent::MouseButtonDblClick:
1499             if (disabled)
1500                 return false;
1501             viewportMouseDoubleClickEvent(static_cast<QMouseEvent *>(e));
1502             if ((static_cast<QMouseEvent *>(e))->isAccepted())
1503                 return true;
1504             break;
1505         case QEvent::MouseMove:
1506             if (disabled)
1507                 return false;
1508             viewportMouseMoveEvent(static_cast<QMouseEvent *>(e));
1509             if ((static_cast<QMouseEvent *>(e))->isAccepted())
1510                 return true;
1511             break;
1512 #ifndef QT_NO_DRAGANDDROP
1513         case QEvent::DragEnter:
1514             if (disabled)
1515                 return false;
1516             viewportDragEnterEvent(static_cast<QDragEnterEvent *>(e));
1517             break;
1518         case QEvent::DragMove: {
1519             if (disabled)
1520                 return false;
1521             if (d->drag_autoscroll) {
1522                 QPoint vp = (static_cast<QDragMoveEvent *>(e))->pos();
1523                 QRect inside_margin(autoscroll_margin, autoscroll_margin, visibleWidth() - autoscroll_margin * 2, visibleHeight() - autoscroll_margin * 2);
1524                 if (!inside_margin.contains(vp)) {
1525                     startDragAutoScroll();
1526                     // Keep sending move events
1527                     (static_cast<QDragMoveEvent *>(e))->accept(QRect(0, 0, 0, 0));
1528                 }
1529             }
1530             viewportDragMoveEvent(static_cast<QDragMoveEvent *>(e));
1531         } break;
1532         case QEvent::DragLeave:
1533             if (disabled)
1534                 return false;
1535             stopDragAutoScroll();
1536             viewportDragLeaveEvent(static_cast<QDragLeaveEvent *>(e));
1537             break;
1538         case QEvent::Drop:
1539             if (disabled)
1540                 return false;
1541             stopDragAutoScroll();
1542             viewportDropEvent(static_cast<QDropEvent *>(e));
1543             break;
1544 #endif // QT_NO_DRAGANDDROP
1545 #ifndef QT_NO_WHEELEVENT
1546         case QEvent::Wheel:
1547             if (disabled)
1548                 return false;
1549             break;
1550 #endif
1551         case QEvent::ContextMenu:
1552             if (disabled)
1553                 return false;
1554             viewportContextMenuEvent(static_cast<QContextMenuEvent *>(e));
1555             if ((static_cast<QContextMenuEvent *>(e))->isAccepted())
1556                 return true;
1557             break;
1558         case QEvent::ChildRemoved:
1559             removeChild(static_cast<QWidget *>((static_cast<QChildEvent *>(e))->child()));
1560             break;
1561         // case QEvent::LayoutHint:  // 2018.12.08 - deprecated
1562         //    d->autoResizeHint(this);
1563         //    break;
1564         default:
1565             break;
1566         }
1567     } else if (d && d->rec(static_cast<QWidget *>(obj))) { // must be a child
1568         if (e->type() == QEvent::Resize)
1569             d->autoResize(this);
1570         else if (e->type() == QEvent::Move)
1571             d->autoMove(this);
1572     }
1573     return KtlQ3Frame::eventFilter(obj, e); // always continue with standard event processing
1574 }
1575 
1576 /*!
1577     This event handler is called whenever the KtlQ3ScrollView receives a
1578     mousePressEvent(): the press position in \a e is translated to be a point
1579     on the contents.
1580 */
1581 void KtlQ3ScrollView::contentsMousePressEvent(QMouseEvent *e)
1582 {
1583     e->ignore();
1584 }
1585 
1586 /*!
1587     This event handler is called whenever the KtlQ3ScrollView receives a
1588     mouseReleaseEvent(): the release position in \a e is translated to be a
1589     point on the contents.
1590 */
1591 void KtlQ3ScrollView::contentsMouseReleaseEvent(QMouseEvent *e)
1592 {
1593     e->ignore();
1594 }
1595 
1596 /*!
1597     This event handler is called whenever the KtlQ3ScrollView receives a
1598     mouseDoubleClickEvent(): the click position in \a e is translated to be a
1599     point on the contents.
1600 
1601     The default implementation generates a normal mouse press event.
1602 */
1603 void KtlQ3ScrollView::contentsMouseDoubleClickEvent(QMouseEvent *e)
1604 {
1605     contentsMousePressEvent(e); // try mouse press event
1606 }
1607 
1608 /*!
1609     This event handler is called whenever the KtlQ3ScrollView receives a
1610     mouseMoveEvent(): the mouse position in \a e is translated to be a point
1611     on the contents.
1612 */
1613 void KtlQ3ScrollView::contentsMouseMoveEvent(QMouseEvent *e)
1614 {
1615     e->ignore();
1616 }
1617 
1618 #ifndef QT_NO_DRAGANDDROP
1619 
1620 /*!
1621     This event handler is called whenever the KtlQ3ScrollView receives a
1622     dragEnterEvent(): the drag position is translated to be a point
1623     on the contents.
1624 
1625     The default implementation does nothing. The \a event parameter is
1626     ignored.
1627 */
1628 void KtlQ3ScrollView::contentsDragEnterEvent(QDragEnterEvent * /* event */)
1629 {
1630 }
1631 
1632 /*!
1633     This event handler is called whenever the KtlQ3ScrollView receives a
1634     dragMoveEvent(): the drag position is translated to be a point on
1635     the contents.
1636 
1637     The default implementation does nothing. The \a event parameter is
1638     ignored.
1639 */
1640 void KtlQ3ScrollView::contentsDragMoveEvent(QDragMoveEvent * /* event */)
1641 {
1642 }
1643 
1644 /*!
1645     This event handler is called whenever the KtlQ3ScrollView receives a
1646     dragLeaveEvent(): the drag position is translated to be a point
1647     on the contents.
1648 
1649     The default implementation does nothing. The \a event parameter is
1650     ignored.
1651 */
1652 void KtlQ3ScrollView::contentsDragLeaveEvent(QDragLeaveEvent * /* event */)
1653 {
1654 }
1655 
1656 /*!
1657     This event handler is called whenever the KtlQ3ScrollView receives a
1658     dropEvent(): the drop position is translated to be a point on the
1659     contents.
1660 
1661     The default implementation does nothing. The \a event parameter is
1662     ignored.
1663 */
1664 
1665 void KtlQ3ScrollView::contentsDropEvent(QDropEvent * /* event */)
1666 {
1667 }
1668 
1669 #endif // QT_NO_DRAGANDDROP
1670 
1671 /*!
1672     This event handler is called whenever the KtlQ3ScrollView receives a
1673     wheelEvent() in \a{e}: the mouse position is translated to be a
1674     point on the contents.
1675 */
1676 #ifndef QT_NO_WHEELEVENT
1677 void KtlQ3ScrollView::contentsWheelEvent(QWheelEvent *e)
1678 {
1679     e->ignore();
1680 }
1681 #endif
1682 /*!
1683     This event handler is called whenever the KtlQ3ScrollView receives a
1684     contextMenuEvent() in \a{e}: the mouse position is translated to
1685     be a point on the contents.
1686 */
1687 void KtlQ3ScrollView::contentsContextMenuEvent(QContextMenuEvent *e)
1688 {
1689     e->ignore();
1690 }
1691 
1692 /*!
1693     This is a low-level painting routine that draws the viewport
1694     contents. Reimplement this if drawContents() is too high-level
1695     (for example, if you don't want to open a QPainter on the
1696     viewport). The paint event is passed in \a pe.
1697 */
1698 void KtlQ3ScrollView::viewportPaintEvent(QPaintEvent *pe)
1699 {
1700     QWidget *vp = viewport();
1701 
1702     QPainter p(vp);
1703     QRect r = pe->rect();
1704 
1705     if (d->clipped_viewport) {
1706         QRect rr(-d->clipped_viewport->x(), -d->clipped_viewport->y(), d->viewport->width(), d->viewport->height());
1707         r &= rr;
1708         if (r.isValid()) {
1709             int ex = r.x() + d->clipped_viewport->x() + d->contentsX();
1710             int ey = r.y() + d->clipped_viewport->y() + d->contentsY();
1711             int ew = r.width();
1712             int eh = r.height();
1713             drawContentsOffset(&p, d->contentsX() + d->clipped_viewport->x(), d->contentsY() + d->clipped_viewport->y(), ex, ey, ew, eh);
1714         }
1715     } else {
1716         r &= d->viewport->rect();
1717         int ex = r.x() + d->contentsX();
1718         int ey = r.y() + d->contentsY();
1719         int ew = r.width();
1720         int eh = r.height();
1721         drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh);
1722     }
1723 }
1724 
1725 /*!
1726     To provide simple processing of events on the contents, this
1727     function receives all resize events sent to the viewport.
1728 
1729     The default implementation does nothing. The \a event parameter is
1730     ignored.
1731 
1732     \sa QWidget::resizeEvent()
1733 */
1734 void KtlQ3ScrollView::viewportResizeEvent(QResizeEvent * /* event */)
1735 {
1736 }
1737 
1738 /*! \internal
1739 
1740   To provide simple processing of events on the contents, this
1741   function receives all mouse press events sent to the viewport,
1742   translates the event and calls contentsMousePressEvent().
1743 
1744   \sa contentsMousePressEvent(), QWidget::mousePressEvent()
1745 */
1746 void KtlQ3ScrollView::viewportMousePressEvent(QMouseEvent *e)
1747 {
1748     /* QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1749         e->globalPos(), e->button(), e->state()); - 2018.11.30 */
1750     QMouseEvent ce(e->type(), viewportToContents(e->pos()), e->globalPos(), e->button(), e->buttons(), e->modifiers());
1751     contentsMousePressEvent(&ce);
1752     if (!ce.isAccepted())
1753         e->ignore();
1754 }
1755 
1756 /*!\internal
1757 
1758   To provide simple processing of events on the contents, this function
1759   receives all mouse release events sent to the viewport, translates
1760   the event and calls contentsMouseReleaseEvent().
1761 
1762   \sa QWidget::mouseReleaseEvent()
1763 */
1764 void KtlQ3ScrollView::viewportMouseReleaseEvent(QMouseEvent *e)
1765 {
1766     /* QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1767         e->globalPos(), e->button(), e->state()); -- 2018.11.30 */
1768     QMouseEvent ce(e->type(), viewportToContents(e->pos()), e->globalPos(), e->button(), e->buttons(), e->modifiers());
1769     contentsMouseReleaseEvent(&ce);
1770     if (!ce.isAccepted())
1771         e->ignore();
1772 }
1773 
1774 /*!\internal
1775 
1776   To provide simple processing of events on the contents, this function
1777   receives all mouse double click events sent to the viewport,
1778   translates the event and calls contentsMouseDoubleClickEvent().
1779 
1780   \sa QWidget::mouseDoubleClickEvent()
1781 */
1782 void KtlQ3ScrollView::viewportMouseDoubleClickEvent(QMouseEvent *e)
1783 {
1784     /* QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1785         e->globalPos(), e->button(), e->state());  - 2018.11.30 */
1786     QMouseEvent ce(e->type(), viewportToContents(e->pos()), e->globalPos(), e->button(), e->buttons(), e->modifiers());
1787     contentsMouseDoubleClickEvent(&ce);
1788     if (!ce.isAccepted())
1789         e->ignore();
1790 }
1791 
1792 /*!\internal
1793 
1794   To provide simple processing of events on the contents, this function
1795   receives all mouse move events sent to the viewport, translates the
1796   event and calls contentsMouseMoveEvent().
1797 
1798   \sa QWidget::mouseMoveEvent()
1799 */
1800 void KtlQ3ScrollView::viewportMouseMoveEvent(QMouseEvent *e)
1801 {
1802     QMouseEvent ce(e->type(), viewportToContents(e->pos()), e->globalPos(), e->button(), e->buttons(), e->modifiers());
1803     contentsMouseMoveEvent(&ce);
1804     if (!ce.isAccepted())
1805         e->ignore();
1806 }
1807 
1808 #ifndef QT_NO_DRAGANDDROP
1809 
1810 /*!\internal
1811 
1812   To provide simple processing of events on the contents, this function
1813   receives all drag enter events sent to the viewport, translates the
1814   event and calls contentsDragEnterEvent().
1815 
1816   \sa QWidget::dragEnterEvent()
1817 */
1818 void KtlQ3ScrollView::viewportDragEnterEvent(QDragEnterEvent *e)
1819 {
1820     // e->setPoint(viewportToContents(e->pos())); // 2018.11.30
1821     QDragEnterEvent ev(viewportToContents(e->pos()), e->possibleActions(), e->mimeData(), e->mouseButtons(), e->keyboardModifiers());
1822     contentsDragEnterEvent(&ev);
1823     // e->setPoint(contentsToViewport(e->pos())); // 2018.11.30
1824 }
1825 
1826 /*!\internal
1827 
1828   To provide simple processing of events on the contents, this function
1829   receives all drag move events sent to the viewport, translates the
1830   event and calls contentsDragMoveEvent().
1831 
1832   \sa QWidget::dragMoveEvent()
1833 */
1834 void KtlQ3ScrollView::viewportDragMoveEvent(QDragMoveEvent *e)
1835 {
1836     // e->setPoint(viewportToContents(e->pos())); // 2018.11.30
1837     QDragMoveEvent ev(viewportToContents(e->pos()), e->possibleActions(), e->mimeData(), e->mouseButtons(), e->keyboardModifiers());
1838     contentsDragMoveEvent(&ev);
1839     // e->setPoint(contentsToViewport(e->pos())); // 2018.11.30
1840 }
1841 
1842 /*!\internal
1843 
1844   To provide simple processing of events on the contents, this function
1845   receives all drag leave events sent to the viewport and calls
1846   contentsDragLeaveEvent().
1847 
1848   \sa QWidget::dragLeaveEvent()
1849 */
1850 void KtlQ3ScrollView::viewportDragLeaveEvent(QDragLeaveEvent *e)
1851 {
1852     contentsDragLeaveEvent(e);
1853 }
1854 
1855 /*!\internal
1856 
1857   To provide simple processing of events on the contents, this function
1858   receives all drop events sent to the viewport, translates the event
1859   and calls contentsDropEvent().
1860 
1861   \sa QWidget::dropEvent()
1862 */
1863 void KtlQ3ScrollView::viewportDropEvent(QDropEvent *e)
1864 {
1865     // e->setPoint(viewportToContents(e->pos())); // 2018.11.30
1866     QDropEvent ev(viewportToContents(e->pos()), e->possibleActions(), e->mimeData(), e->mouseButtons(), e->keyboardModifiers());
1867     contentsDropEvent(&ev);
1868     // e->setPoint(contentsToViewport(e->pos())); // 2018.11.30
1869 }
1870 
1871 #endif // QT_NO_DRAGANDDROP
1872 
1873 /*!\internal
1874 
1875   To provide simple processing of events on the contents, this function
1876   receives all wheel events sent to the viewport, translates the
1877   event and calls contentsWheelEvent().
1878 
1879   \sa QWidget::wheelEvent()
1880 */
1881 #ifndef QT_NO_WHEELEVENT
1882 void KtlQ3ScrollView::viewportWheelEvent(QWheelEvent *e)
1883 {
1884     /*
1885        Different than standard mouse events, because wheel events might
1886        be sent to the focus widget if the widget-under-mouse doesn't want
1887        the event itself.
1888     */
1889     /* QWheelEvent ce(viewportToContents(e->pos()),
1890         e->globalPos(), e->delta(), e->state()); */
1891     QWheelEvent ce(viewportToContents(e->position().toPoint()), e->globalPosition(), e->pixelDelta(), e->angleDelta(),
1892                    e->buttons(), e->modifiers(), e->phase(), e->inverted());
1893     contentsWheelEvent(&ce);
1894     if (ce.isAccepted())
1895         e->accept();
1896     else
1897         e->ignore();
1898 }
1899 #endif
1900 
1901 /*! \internal
1902 
1903   To provide simple processing of events on the contents, this function
1904   receives all context menu events sent to the viewport, translates the
1905   event and calls contentsContextMenuEvent().
1906 */
1907 void KtlQ3ScrollView::viewportContextMenuEvent(QContextMenuEvent *e)
1908 {
1909     // QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state());
1910     QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->modifiers());
1911     contentsContextMenuEvent(&ce);
1912     if (ce.isAccepted())
1913         e->accept();
1914     else
1915         e->ignore();
1916 }
1917 
1918 /*!
1919     Returns the component horizontal scroll bar. It is made available
1920     to allow accelerators, autoscrolling, etc.
1921 
1922     It should not be used for other purposes.
1923 
1924     This function never returns 0.
1925 */
1926 QScrollBar *KtlQ3ScrollView::horizontalScrollBar() const
1927 {
1928     return d->hbar;
1929 }
1930 
1931 /*!
1932     Returns the component vertical scroll bar. It is made available to
1933     allow accelerators, autoscrolling, etc.
1934 
1935     It should not be used for other purposes.
1936 
1937     This function never returns 0.
1938 */
1939 QScrollBar *KtlQ3ScrollView::verticalScrollBar() const
1940 {
1941     return d->vbar;
1942 }
1943 
1944 /*!
1945     Scrolls the content so that the point (\a x, \a y) is visible with at
1946     least 50-pixel margins (if possible, otherwise centered).
1947 */
1948 void KtlQ3ScrollView::ensureVisible(int x, int y)
1949 {
1950     ensureVisible(x, y, 50, 50);
1951 }
1952 
1953 /*!
1954     \overload
1955 
1956     Scrolls the content so that the point (\a x, \a y) is visible with at
1957     least the \a xmargin and \a ymargin margins (if possible,
1958     otherwise centered).
1959 */
1960 void KtlQ3ScrollView::ensureVisible(int x, int y, int xmargin, int ymargin)
1961 {
1962     int pw = visibleWidth();
1963     int ph = visibleHeight();
1964 
1965     int cx = -d->contentsX();
1966     int cy = -d->contentsY();
1967     int cw = d->contentsWidth();
1968     int ch = contentsHeight();
1969 
1970     if (pw < xmargin * 2)
1971         xmargin = pw / 2;
1972     if (ph < ymargin * 2)
1973         ymargin = ph / 2;
1974 
1975     if (cw <= pw) {
1976         xmargin = 0;
1977         cx = 0;
1978     }
1979     if (ch <= ph) {
1980         ymargin = 0;
1981         cy = 0;
1982     }
1983 
1984     if (x < -cx + xmargin)
1985         cx = -x + xmargin;
1986     else if (x >= -cx + pw - xmargin)
1987         cx = -x + pw - xmargin;
1988 
1989     if (y < -cy + ymargin)
1990         cy = -y + ymargin;
1991     else if (y >= -cy + ph - ymargin)
1992         cy = -y + ph - ymargin;
1993 
1994     if (cx > 0)
1995         cx = 0;
1996     else if (cx < pw - cw && cw > pw)
1997         cx = pw - cw;
1998 
1999     if (cy > 0)
2000         cy = 0;
2001     else if (cy < ph - ch && ch > ph)
2002         cy = ph - ch;
2003 
2004     setContentsPos(-cx, -cy);
2005 }
2006 
2007 /*!
2008     Scrolls the content so that the point (\a x, \a y) is in the top-left
2009     corner.
2010 */
2011 void KtlQ3ScrollView::setContentsPos(int x, int y)
2012 {
2013 #if 0
2014     // bounds checking...
2015     if (QApplication::reverseLayout())
2016         if (x > d->contentsWidth() - visibleWidth()) x = d->contentsWidth() - visibleWidth();
2017     else
2018 #endif
2019     if (x < 0)
2020         x = 0;
2021     if (y < 0)
2022         y = 0;
2023     // Choke signal handling while we update BOTH sliders.
2024     d->signal_choke = true;
2025     moveContents(-x, -y);
2026     d->vbar->setValue(y);
2027     d->hbar->setValue(x);
2028     d->signal_choke = false;
2029 }
2030 
2031 /*!
2032     Scrolls the content by \a dx to the left and \a dy upwards.
2033 */
2034 void KtlQ3ScrollView::scrollBy(int dx, int dy)
2035 {
2036     setContentsPos(qMax(d->contentsX() + dx, 0), qMax(d->contentsY() + dy, 0));
2037 }
2038 
2039 /*!
2040     Scrolls the content so that the point (\a x, \a y) is in the center
2041     of visible area.
2042 */
2043 void KtlQ3ScrollView::center(int x, int y)
2044 {
2045     ensureVisible(x, y, 32000, 32000);
2046 }
2047 
2048 /*!
2049     \overload
2050 
2051     Scrolls the content so that the point (\a x, \a y) is visible with
2052     the \a xmargin and \a ymargin margins (as fractions of visible
2053     the area).
2054 
2055     For example:
2056     \list
2057     \i Margin 0.0 allows (x, y) to be on the edge of the visible area.
2058     \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area.
2059     \i Margin 1.0 ensures that (x, y) is in the center of the visible area.
2060     \endlist
2061 */
2062 void KtlQ3ScrollView::center(int x, int y, float xmargin, float ymargin)
2063 {
2064     int pw = visibleWidth();
2065     int ph = visibleHeight();
2066     ensureVisible(x, y, int(xmargin / 2.0 * pw + 0.5), int(ymargin / 2.0 * ph + 0.5));
2067 }
2068 
2069 /*!
2070     \fn void KtlQ3ScrollView::contentsMoving(int x, int y)
2071 
2072     This signal is emitted just before the contents are moved to
2073     position (\a x, \a y).
2074 
2075     \sa contentsX(), contentsY()
2076 */
2077 
2078 /*!
2079     Moves the contents by (\a x, \a y).
2080 */
2081 void KtlQ3ScrollView::moveContents(int x, int y)
2082 {
2083     if (-x + visibleWidth() > d->contentsWidth())
2084 #if 0
2085         if(QApplication::reverseLayout())
2086             x=qMax(0,-d->contentsWidth()+visibleWidth());
2087         else
2088 #endif
2089         x = qMin(0, -d->contentsWidth() + visibleWidth());
2090     if (-y + visibleHeight() > contentsHeight())
2091         y = qMin(0, -contentsHeight() + visibleHeight());
2092 
2093     int dx = x - d->vx;
2094     int dy = y - d->vy;
2095 
2096     if (!dx && !dy)
2097         return; // Nothing to do
2098 
2099     emit contentsMoving(-x, -y);
2100 
2101     d->vx = x;
2102     d->vy = y;
2103 
2104     if (d->clipped_viewport || d->static_bg) {
2105         // Cheap move (usually)
2106         d->moveAllBy(dx, dy);
2107     } else if (/*dx && dy ||*/
2108                (qAbs(dy) * 5 > visibleHeight() * 4) || (qAbs(dx) * 5 > visibleWidth() * 4)) {
2109         // Big move
2110         if (viewport()->updatesEnabled())
2111             viewport()->update();
2112         d->moveAllBy(dx, dy);
2113     } else if (!d->fake_scroll || d->contentsWidth() > visibleWidth()) {
2114         // Small move
2115         clipper()->scroll(dx, dy);
2116     }
2117     d->hideOrShowAll(this, true);
2118 }
2119 
2120 /*!
2121     \property KtlQ3ScrollView::contentsX
2122     \brief the X coordinate of the contents that are at the left edge of
2123     the viewport.
2124 */
2125 int KtlQ3ScrollView::contentsX() const
2126 {
2127     return d->contentsX();
2128 }
2129 
2130 /*!
2131     \property KtlQ3ScrollView::contentsY
2132     \brief the Y coordinate of the contents that are at the top edge of
2133     the viewport.
2134 */
2135 int KtlQ3ScrollView::contentsY() const
2136 {
2137     return d->contentsY();
2138 }
2139 
2140 /*!
2141     \property KtlQ3ScrollView::contentsWidth
2142     \brief the width of the contents area
2143 */
2144 int KtlQ3ScrollView::contentsWidth() const
2145 {
2146     return d->contentsWidth();
2147 }
2148 
2149 /*!
2150     \property KtlQ3ScrollView::contentsHeight
2151     \brief the height of the contents area
2152 */
2153 int KtlQ3ScrollView::contentsHeight() const
2154 {
2155     return d->vheight;
2156 }
2157 
2158 /*!
2159     Sets the size of the contents area to \a w pixels wide and \a h
2160     pixels high and updates the viewport accordingly.
2161 */
2162 void KtlQ3ScrollView::resizeContents(int w, int h)
2163 {
2164     int ow = d->vwidth;
2165     int oh = d->vheight;
2166     d->vwidth = w;
2167     d->vheight = h;
2168 
2169     d->scrollbar_timer.setSingleShot(true);
2170     d->scrollbar_timer.start(0 /*, true */);
2171 
2172     if (d->children.isEmpty() && d->policy == Default)
2173         setResizePolicy(Manual);
2174 
2175     if (ow > w) {
2176         // Swap
2177         int t = w;
2178         w = ow;
2179         ow = t;
2180     }
2181     // Refresh area ow..w
2182     if (ow < visibleWidth() && w >= 0) {
2183         if (ow < 0)
2184             ow = 0;
2185         if (w > visibleWidth())
2186             w = visibleWidth();
2187         clipper()->update(d->contentsX() + ow, 0, w - ow, visibleHeight());
2188     }
2189 
2190     if (oh > h) {
2191         // Swap
2192         int t = h;
2193         h = oh;
2194         oh = t;
2195     }
2196     // Refresh area oh..h
2197     if (oh < visibleHeight() && h >= 0) {
2198         if (oh < 0)
2199             oh = 0;
2200         if (h > visibleHeight())
2201             h = visibleHeight();
2202         clipper()->update(0, d->contentsY() + oh, visibleWidth(), h - oh);
2203     }
2204 }
2205 
2206 /*!
2207     Calls update() on a rectangle defined by \a x, \a y, \a w, \a h,
2208     translated appropriately. If the rectangle is not visible, nothing
2209     is repainted.
2210 
2211     \sa repaintContents()
2212 */
2213 void KtlQ3ScrollView::updateContents(int x, int y, int w, int h)
2214 {
2215     if (!isVisible() || !updatesEnabled())
2216         return;
2217 
2218     QWidget *vp = viewport();
2219 
2220     // Translate
2221     x -= d->contentsX();
2222     y -= d->contentsY();
2223 
2224     if (x < 0) {
2225         w += x;
2226         x = 0;
2227     }
2228     if (y < 0) {
2229         h += y;
2230         y = 0;
2231     }
2232 
2233     if (w < 0 || h < 0)
2234         return;
2235     if (x > visibleWidth() || y > visibleHeight())
2236         return;
2237 
2238     if (w > visibleWidth())
2239         w = visibleWidth();
2240     if (h > visibleHeight())
2241         h = visibleHeight();
2242 
2243     if (d->clipped_viewport) {
2244         // Translate clipper() to viewport()
2245         x -= d->clipped_viewport->x();
2246         y -= d->clipped_viewport->y();
2247     }
2248 
2249     vp->update(x, y, w, h);
2250 }
2251 
2252 /*!
2253     \overload
2254 
2255     Updates the contents in rectangle \a r
2256 */
2257 void KtlQ3ScrollView::updateContents(const QRect &r)
2258 {
2259     updateContents(r.x(), r.y(), r.width(), r.height());
2260 }
2261 
2262 /*!
2263     \overload
2264 */
2265 void KtlQ3ScrollView::updateContents()
2266 {
2267     updateContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight());
2268 }
2269 
2270 /*!
2271     \overload
2272 
2273     Repaints the contents of rectangle \a r. If \a erase is true the
2274     background is cleared using the background color.
2275 */
2276 void KtlQ3ScrollView::repaintContents(const QRect &r, bool erase)
2277 {
2278     repaintContents(r.x(), r.y(), r.width(), r.height(), erase);
2279 }
2280 
2281 /*!
2282     \overload
2283 
2284     Repaints the contents. If \a erase is true the background is
2285     cleared using the background color.
2286 */
2287 void KtlQ3ScrollView::repaintContents(bool erase)
2288 {
2289     repaintContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase);
2290 }
2291 
2292 /*!
2293     Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h,
2294     translated appropriately. If the rectangle is not visible, nothing
2295     is repainted. If \a erase is true the background is cleared using
2296     the background color.
2297 
2298     \sa updateContents()
2299 */
2300 void KtlQ3ScrollView::repaintContents(int x, int y, int w, int h, bool /*erase*/)
2301 {
2302     if (!isVisible() || !updatesEnabled())
2303         return;
2304 
2305     QWidget *vp = viewport();
2306 
2307     // Translate logical to clipper()
2308     x -= d->contentsX();
2309     y -= d->contentsY();
2310 
2311     if (x < 0) {
2312         w += x;
2313         x = 0;
2314     }
2315     if (y < 0) {
2316         h += y;
2317         y = 0;
2318     }
2319 
2320     if (w < 0 || h < 0)
2321         return;
2322     if (w > visibleWidth())
2323         w = visibleWidth();
2324     if (h > visibleHeight())
2325         h = visibleHeight();
2326 
2327     if (d->clipped_viewport) {
2328         // Translate clipper() to viewport()
2329         x -= d->clipped_viewport->x();
2330         y -= d->clipped_viewport->y();
2331     }
2332 
2333     vp->update(x, y, w, h);
2334 }
2335 
2336 /*!
2337     For backward-compatibility only. It is easier to use
2338     drawContents(QPainter*,int,int,int,int).
2339 
2340     The default implementation translates the painter appropriately
2341     and calls drawContents(QPainter*,int,int,int,int). See
2342     drawContents() for an explanation of the parameters \a p, \a
2343     offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph.
2344 */
2345 void KtlQ3ScrollView::drawContentsOffset(QPainter *p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph)
2346 {
2347     p->translate(-offsetx, -offsety);
2348     drawContents(p, clipx, clipy, clipw, cliph);
2349 }
2350 
2351 /*!
2352     \fn void KtlQ3ScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph)
2353 
2354     Reimplement this function if you are viewing a drawing area rather
2355     than a widget.
2356 
2357     The function should draw the rectangle (\a clipx, \a clipy, \a
2358     clipw, \a cliph) of the contents using painter \a p. The clip
2359     rectangle is in the scrollview's coordinates.
2360 
2361     For example:
2362     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 4
2363 
2364     The clip rectangle and translation of the painter \a p is already
2365     set appropriately.
2366 */
2367 void KtlQ3ScrollView::drawContents(QPainter *, int, int, int, int)
2368 {
2369 }
2370 
2371 /*!
2372     \reimp
2373 */
2374 void KtlQ3ScrollView::frameChanged()
2375 {
2376     //     // slight ugle-hack - the listview header needs readjusting when
2377     //     // changing the frame
2378     //     if (Q3ListView *lv = qobject_cast<Q3ListView *>(this))
2379     //         lv->triggerUpdate();
2380     KtlQ3Frame::frameChanged();
2381     updateScrollBars();
2382 }
2383 
2384 /*!
2385     Returns the viewport widget of the scrollview. This is the widget
2386     containing the contents widget or which is the drawing area.
2387 */
2388 QWidget *KtlQ3ScrollView::viewport() const
2389 {
2390     if (d->clipped_viewport)
2391         return d->clipped_viewport;
2392     return d->viewport;
2393 }
2394 
2395 /*!
2396     Returns the clipper widget. Contents in the scrollview are
2397     ultimately clipped to be inside the clipper widget.
2398 
2399     You should not need to use this function.
2400 
2401     \sa visibleWidth(), visibleHeight()
2402 */
2403 QWidget *KtlQ3ScrollView::clipper() const
2404 {
2405     return d->viewport;
2406 }
2407 
2408 /*!
2409     \property KtlQ3ScrollView::visibleWidth
2410     \brief the horizontal amount of the content that is visible
2411 */
2412 int KtlQ3ScrollView::visibleWidth() const
2413 {
2414     return clipper()->width();
2415 }
2416 
2417 /*!
2418     \property KtlQ3ScrollView::visibleHeight
2419     \brief the vertical amount of the content that is visible
2420 */
2421 int KtlQ3ScrollView::visibleHeight() const
2422 {
2423     return clipper()->height();
2424 }
2425 
2426 void KtlQ3ScrollView::changeFrameRect(const QRect &r)
2427 {
2428     QRect oldr = frameRect();
2429     if (oldr != r) {
2430         QRect cr = contentsRect();
2431         QRegion fr(frameRect());
2432         fr = fr.subtracted(contentsRect());
2433         setFrameRect(r);
2434         if (isVisible()) {
2435             cr = cr.intersected(contentsRect());
2436             fr = fr.united(frameRect());
2437             fr = fr.subtracted(cr);
2438             if (!fr.isEmpty())
2439                 update(fr);
2440         }
2441     }
2442 }
2443 
2444 /*!
2445     Sets the margins around the scrolling area to \a left, \a top, \a
2446     right and \a bottom. This is useful for applications such as
2447     spreadsheets with "locked" rows and columns. The marginal space is
2448     \e inside the frameRect() and is left blank; reimplement
2449     drawFrame() or put widgets in the unused area.
2450 
2451     By default all margins are zero.
2452 
2453     \sa frameChanged()
2454 */
2455 void KtlQ3ScrollView::setMargins(int left, int top, int right, int bottom)
2456 {
2457     if (left == d->l_marg && top == d->t_marg && right == d->r_marg && bottom == d->b_marg)
2458         return;
2459 
2460     d->l_marg = left;
2461     d->t_marg = top;
2462     d->r_marg = right;
2463     d->b_marg = bottom;
2464     updateScrollBars();
2465 }
2466 
2467 /*!
2468     Returns the left margin.
2469 
2470     \sa setMargins()
2471 */
2472 int KtlQ3ScrollView::leftMargin() const
2473 {
2474     return d->l_marg;
2475 }
2476 
2477 /*!
2478     Returns the top margin.
2479 
2480     \sa setMargins()
2481 */
2482 int KtlQ3ScrollView::topMargin() const
2483 {
2484     return d->t_marg;
2485 }
2486 
2487 /*!
2488     Returns the right margin.
2489 
2490     \sa setMargins()
2491 */
2492 int KtlQ3ScrollView::rightMargin() const
2493 {
2494     return d->r_marg;
2495 }
2496 
2497 /*!
2498     Returns the bottom margin.
2499 
2500     \sa setMargins()
2501 */
2502 int KtlQ3ScrollView::bottomMargin() const
2503 {
2504     return d->b_marg;
2505 }
2506 
2507 /*!
2508     \reimp
2509 */
2510 bool KtlQ3ScrollView::focusNextPrevChild(bool next)
2511 {
2512     //  Makes sure that the new focus widget is on-screen, if
2513     //  necessary by scrolling the scroll view.
2514     bool retval = KtlQ3Frame::focusNextPrevChild(next);
2515     if (retval) {
2516         QWidget *w = window()->focusWidget();
2517         if (isAncestorOf(w)) {
2518             QSVChildRec *r = d->ancestorRec(w);
2519             if (r && (r->child == w || w->isVisibleTo(r->child))) {
2520                 QPoint cp = r->child->mapToGlobal(QPoint(0, 0));
2521                 QPoint cr = w->mapToGlobal(QPoint(0, 0)) - cp;
2522                 ensureVisible(r->x + cr.x() + w->width() / 2, r->y + cr.y() + w->height() / 2, w->width() / 2, w->height() / 2);
2523             }
2524         }
2525     }
2526     return retval;
2527 }
2528 
2529 /*!
2530     When a large numbers of child widgets are in a scrollview,
2531     especially if they are close together, the scrolling performance
2532     can suffer greatly. If \a y is true the scrollview will use an
2533     extra widget to group child widgets.
2534 
2535     Note that you may only call enableClipper() prior to adding
2536     widgets.
2537 */
2538 void KtlQ3ScrollView::enableClipper(bool y) // note: this method as of 2018.11.30 is unused
2539 {
2540     if (!d->clipped_viewport == !y)
2541         return;
2542     if (d->children.count())
2543         qFatal("May only call KtlQ3ScrollView::enableClipper() before adding widgets");
2544     if (y) {
2545         d->clipped_viewport = new KtlQClipperWidget(clipper(), "qt_clipped_viewport", QFlag(d->flags));
2546         d->clipped_viewport->setGeometry(-coord_limit / 2, -coord_limit / 2, coord_limit, coord_limit);
2547         // d->clipped_viewport->setBackgroundMode(d->viewport->backgroundMode());
2548         d->clipped_viewport->setBackgroundRole(d->viewport->backgroundRole());
2549         // d->viewport->setBackgroundMode(NoBackground); // no exposures for this // 2018.11.30
2550         d->viewport->setAttribute(Qt::WA_NoSystemBackground); // hope this is the correct replacement for above
2551         d->viewport->removeEventFilter(this);
2552         d->clipped_viewport->installEventFilter(this);
2553         d->clipped_viewport->show();
2554     } else {
2555         delete d->clipped_viewport;
2556         d->clipped_viewport = nullptr;
2557     }
2558 }
2559 
2560 /*!
2561     Sets the scrollview to have a static background if \a y is true,
2562     or a scrolling background if \a y is false. By default, the
2563     background is scrolling.
2564 
2565     Be aware that this mode is quite slow, as a full repaint of the
2566     visible area has to be triggered on every contents move.
2567 
2568     \sa hasStaticBackground()
2569 */
2570 void KtlQ3ScrollView::setStaticBackground(bool y)
2571 {
2572     d->static_bg = y;
2573 }
2574 
2575 /*!
2576     Returns true if KtlQ3ScrollView uses a static background; otherwise
2577     returns false.
2578 
2579     \sa setStaticBackground()
2580 */
2581 bool KtlQ3ScrollView::hasStaticBackground() const
2582 {
2583     return d->static_bg;
2584 }
2585 
2586 /*!
2587     \overload
2588 
2589     Returns the point \a p translated to a point on the viewport()
2590     widget.
2591 */
2592 QPoint KtlQ3ScrollView::contentsToViewport(const QPoint &p) const
2593 {
2594     if (d->clipped_viewport) {
2595         return QPoint(p.x() - d->contentsX() - d->clipped_viewport->x(), p.y() - d->contentsY() - d->clipped_viewport->y());
2596     } else {
2597         return QPoint(p.x() - d->contentsX(), p.y() - d->contentsY());
2598     }
2599 }
2600 
2601 /*!
2602     \overload
2603 
2604     Returns the point on the viewport \a vp translated to a point in
2605     the contents.
2606 */
2607 QPoint KtlQ3ScrollView::viewportToContents(const QPoint &vp) const
2608 {
2609     if (d->clipped_viewport) {
2610         return QPoint(vp.x() + d->contentsX() + d->clipped_viewport->x(), vp.y() + d->contentsY() + d->clipped_viewport->y());
2611     } else {
2612         return QPoint(vp.x() + d->contentsX(), vp.y() + d->contentsY());
2613     }
2614 }
2615 
2616 /*!
2617     Translates a point (\a x, \a y) in the contents to a point (\a vx,
2618     \a vy) on the viewport() widget.
2619 */
2620 void KtlQ3ScrollView::contentsToViewport(int x, int y, int &vx, int &vy) const
2621 {
2622     const QPoint v = contentsToViewport(QPoint(x, y));
2623     vx = v.x();
2624     vy = v.y();
2625 }
2626 
2627 /*!
2628     Translates a point (\a vx, \a vy) on the viewport() widget to a
2629     point (\a x, \a y) in the contents.
2630 */
2631 void KtlQ3ScrollView::viewportToContents(int vx, int vy, int &x, int &y) const
2632 {
2633     const QPoint c = viewportToContents(QPoint(vx, vy));
2634     x = c.x();
2635     y = c.y();
2636 }
2637 
2638 /*!
2639     \reimp
2640 */
2641 QSize KtlQ3ScrollView::sizeHint() const
2642 {
2643     if (d->use_cached_size_hint && d->cachedSizeHint.isValid())
2644         return d->cachedSizeHint;
2645 
2646     // constPolish(); // 2018.11.30
2647     ensurePolished();
2648     int f = 2 * frameWidth();
2649     int h = fontMetrics().height();
2650     QSize sz(f, f);
2651     if (d->policy > Manual) {
2652         QSVChildRec *r = d->children.first();
2653         if (r) {
2654             QSize cs = r->child->sizeHint();
2655             if (cs.isValid())
2656                 sz += cs.boundedTo(r->child->maximumSize());
2657             else
2658                 sz += r->child->size();
2659         }
2660     } else {
2661         sz += QSize(d->contentsWidth(), contentsHeight());
2662     }
2663     if (d->vMode == AlwaysOn)
2664         sz.setWidth(sz.width() + d->vbar->sizeHint().width());
2665     if (d->hMode == AlwaysOn)
2666         sz.setHeight(sz.height() + d->hbar->sizeHint().height());
2667     return sz.expandedTo(QSize(12 * h, 8 * h)).boundedTo(QSize(36 * h, 24 * h));
2668 }
2669 
2670 /*!
2671     \reimp
2672 */
2673 QSize KtlQ3ScrollView::minimumSizeHint() const
2674 {
2675     int h = fontMetrics().height();
2676     if (h < 10)
2677         h = 10;
2678     int f = 2 * frameWidth();
2679     return QSize((6 * h) + f, (4 * h) + f);
2680 }
2681 
2682 /*!
2683     \reimp
2684 
2685     (Implemented to get rid of a compiler warning.)
2686 */
2687 void KtlQ3ScrollView::drawContents(QPainter *)
2688 {
2689 }
2690 
2691 #ifndef QT_NO_DRAGANDDROP
2692 
2693 /*!
2694   \internal
2695 */
2696 void KtlQ3ScrollView::startDragAutoScroll()
2697 {
2698     if (!d->autoscroll_timer.isActive()) {
2699         d->autoscroll_time = initialScrollTime;
2700         d->autoscroll_accel = initialScrollAccel;
2701         d->autoscroll_timer.start(d->autoscroll_time);
2702     }
2703 }
2704 
2705 /*!
2706   \internal
2707 */
2708 void KtlQ3ScrollView::stopDragAutoScroll()
2709 {
2710     d->autoscroll_timer.stop();
2711 }
2712 
2713 /*!
2714   \internal
2715 */
2716 void KtlQ3ScrollView::doDragAutoScroll()
2717 {
2718     QPoint p = d->viewport->mapFromGlobal(QCursor::pos());
2719 
2720     if (d->autoscroll_accel-- <= 0 && d->autoscroll_time) {
2721         d->autoscroll_accel = initialScrollAccel;
2722         d->autoscroll_time--;
2723         d->autoscroll_timer.start(d->autoscroll_time);
2724     }
2725     int l = qMax(1, (initialScrollTime - d->autoscroll_time));
2726 
2727     int dx = 0, dy = 0;
2728     if (p.y() < autoscroll_margin) {
2729         dy = -l;
2730     } else if (p.y() > visibleHeight() - autoscroll_margin) {
2731         dy = +l;
2732     }
2733     if (p.x() < autoscroll_margin) {
2734         dx = -l;
2735     } else if (p.x() > visibleWidth() - autoscroll_margin) {
2736         dx = +l;
2737     }
2738     if (dx || dy) {
2739         scrollBy(dx, dy);
2740     } else {
2741         stopDragAutoScroll();
2742     }
2743 }
2744 
2745 /*!
2746     \property KtlQ3ScrollView::dragAutoScroll
2747     \brief whether autoscrolling in drag move events is enabled
2748 
2749     If this property is set to true (the default), the KtlQ3ScrollView
2750     automatically scrolls the contents in drag move events if the user
2751     moves the cursor close to a border of the view. Of course this
2752     works only if the viewport accepts drops. Specifying false
2753     disables this autoscroll feature.
2754 */
2755 
2756 void KtlQ3ScrollView::setDragAutoScroll(bool b)
2757 {
2758     d->drag_autoscroll = b;
2759 }
2760 
2761 bool KtlQ3ScrollView::dragAutoScroll() const
2762 {
2763     return d->drag_autoscroll;
2764 }
2765 
2766 #endif // QT_NO_DRAGANDDROP
2767 
2768 /*!\internal
2769  */
2770 void KtlQ3ScrollView::setCachedSizeHint(const QSize &sh) const
2771 {
2772     if (isVisible() && !d->cachedSizeHint.isValid())
2773         d->cachedSizeHint = sh;
2774 }
2775 
2776 /*!\internal
2777  */
2778 void KtlQ3ScrollView::disableSizeHintCaching()
2779 {
2780     d->use_cached_size_hint = false;
2781 }
2782 
2783 /*!\internal
2784  */
2785 QSize KtlQ3ScrollView::cachedSizeHint() const
2786 {
2787     return d->use_cached_size_hint ? d->cachedSizeHint : QSize();
2788 }
2789 
2790 // QT_END_NAMESPACE
2791 
2792 #include "moc_ktlq3scrollview.cpp"