1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt3Support module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "ktlq3scrollview.h"
43 
44 #include <QWidget>
45 #include <QScrollBar>
46 #include <QPainter>
47 #include <QPixmap>
48 #include <QCursor>
49 // #include "q3ptrdict.h"
50 #include <QHash>
51 #include <QApplication>
52 #include <QTimer>
53 #include <QStyle>
54 // #include "q3ptrlist.h"
55 #include <QDragEnterEvent>
56 #include <QDragLeaveEvent>
57 #include <QContextMenuEvent>
58 //#include "q3listview.h"
59 // #ifdef Q_WS_MAC      // 2018.10.18 - do not depend on internal headers
60 // # include "private/qt_mac_p.h"
61 // #endif
62 
63 // QT_BEGIN_NAMESPACE
64 
65 // using namespace Qt;
66 
67 static const int coord_limit = 4000;
68 static const int autoscroll_margin = 16;
69 static const int initialScrollTime = 30;
70 static const int initialScrollAccel = 5;
71 
72 struct QSVChildRec {
QSVChildRecQSVChildRec73     QSVChildRec(QWidget* c, int xx, int yy) :
74         child(c),
75         x(xx), y(yy)
76     {
77     }
78 
79     void hideOrShow(KtlQ3ScrollView* sv, QWidget* clipped_viewport);
moveToQSVChildRec80     void moveTo(KtlQ3ScrollView* sv, int xx, int yy, QWidget* clipped_viewport)
81     {
82         if (x != xx || y != yy) {
83             x = xx;
84             y = yy;
85             hideOrShow(sv,clipped_viewport);
86         }
87     }
88     QWidget* child;
89     int x, y;
90 };
91 
hideOrShow(KtlQ3ScrollView * sv,QWidget * clipped_viewport)92 void QSVChildRec::hideOrShow(KtlQ3ScrollView* sv, QWidget* clipped_viewport)
93 {
94     if (clipped_viewport) {
95         if (x+child->width() < sv->contentsX()+clipped_viewport->x()
96              || x > sv->contentsX()+clipped_viewport->width()
97              || y+child->height() < sv->contentsY()+clipped_viewport->y()
98              || y > sv->contentsY()+clipped_viewport->height()) {
99             child->move(clipped_viewport->width(),
100                         clipped_viewport->height());
101         } else {
102             child->move(x-sv->contentsX()-clipped_viewport->x(),
103                         y-sv->contentsY()-clipped_viewport->y());
104         }
105     } else {
106         child->move(x-sv->contentsX(), y-sv->contentsY());
107     }
108 }
109 
110 // QT_BEGIN_INCLUDE_NAMESPACE
111 
112 // QT_END_INCLUDE_NAMESPACE
113 
114 class KtlQ3ScrollViewData {
115 public:
KtlQ3ScrollViewData(KtlQ3ScrollView * parent,int vpwflags)116     KtlQ3ScrollViewData(KtlQ3ScrollView* parent, int vpwflags) :
117         hbar(new QScrollBar(Qt::Horizontal, parent /*, "qt_hbar"*/)),
118         vbar(new QScrollBar(Qt::Vertical, parent /*, "qt_vbar" */)),
119         viewport(new KtlQAbstractScrollAreaWidget(parent, "qt_viewport", QFlag(vpwflags))),
120         clipped_viewport(nullptr),
121         flags(vpwflags),
122         vx(0), vy(0), vwidth(1), vheight(1),
123 #ifndef QT_NO_DRAGANDDROP
124         autoscroll_timer(parent /* , "scrollview autoscroll timer" */),
125         drag_autoscroll(true),
126 #endif
127         scrollbar_timer(parent /*, "scrollview scrollbar timer" */),
128         inresize(false), use_cached_size_hint(true)
129     {
130         hbar->setObjectName("qt_hbar");
131         vbar->setObjectName("qt_vbar");
132 #ifndef QT_NO_DRAGANDDROP
133         autoscroll_timer.setObjectName("scrollview autoscroll timer");
134 #endif
135         scrollbar_timer.setObjectName("scrollview scrollbar timer");
136         l_marg = r_marg = t_marg = b_marg = 0;
137         viewport->ensurePolished();
138         vMode = KtlQ3ScrollView::Auto;
139         hMode = KtlQ3ScrollView::Auto;
140         corner = nullptr;
141         // vbar->setSteps(20, 1/*set later*/);
142         vbar->setSingleStep(20); vbar->setPageStep(1);
143         //hbar->setSteps(20, 1/*set later*/);
144         hbar->setSingleStep(20); hbar->setPageStep(1);
145         policy = KtlQ3ScrollView::Default;
146         signal_choke = false;
147         static_bg = false;
148         fake_scroll = false;
149         hbarPressed = false;
150         vbarPressed = false;
151         hbar->setLayoutDirection(Qt::LeftToRight);
152     }
153     ~KtlQ3ScrollViewData();
154 
rec(QWidget * w)155     QSVChildRec* rec(QWidget* w) { return /* childDict.find(w); */ childDict.value(w);   }
156     QSVChildRec* ancestorRec(QWidget* w);
addChildRec(QWidget * w,int x,int y)157     QSVChildRec* addChildRec(QWidget* w, int x, int y)
158     {
159         QSVChildRec *r = new QSVChildRec(w,x,y);
160         children.append(r);
161         childDict.insert(w, r);
162         return r;
163     }
deleteChildRec(QSVChildRec * r)164     void deleteChildRec(QSVChildRec* r)
165     {
166         childDict.remove(r->child);
167         //children.removeRef(r);
168         children.removeAll(r);
169         delete r;
170     }
171 
172     void hideOrShowAll(KtlQ3ScrollView* sv, bool isScroll = false);
173     void moveAllBy(int dx, int dy);
174     bool anyVisibleChildren();
175     void autoMove(KtlQ3ScrollView* sv);
176     void autoResize(KtlQ3ScrollView* sv);
177     void autoResizeHint(KtlQ3ScrollView* sv);
178     void viewportResized(int w, int h);
179 
180     QScrollBar*  hbar;
181     QScrollBar*  vbar;
182     bool hbarPressed;
183     bool vbarPressed;
184     KtlQAbstractScrollAreaWidget*    viewport;
185     KtlQClipperWidget*     clipped_viewport;
186     int         flags;
187     //Q3PtrList<QSVChildRec>       children;
188     QList<QSVChildRec*>          children;
189     //Q3PtrDict<QSVChildRec>       childDict; // 2018.10.07
190     QHash< QWidget*, QSVChildRec* > childDict;
191     QWidget*    corner;
192     int         vx, vy, vwidth, vheight; // for drawContents-style usage
193     int         l_marg, r_marg, t_marg, b_marg;
194     KtlQ3ScrollView::ResizePolicy policy;
195     KtlQ3ScrollView::ScrollBarMode  vMode;
196     KtlQ3ScrollView::ScrollBarMode  hMode;
197 #ifndef QT_NO_DRAGANDDROP
198     QPoint cpDragStart;
199     QTimer autoscroll_timer;
200     int autoscroll_time;
201     int autoscroll_accel;
202     bool drag_autoscroll;
203 #endif
204     QTimer scrollbar_timer;
205 
206     uint static_bg : 1;
207     uint fake_scroll : 1;
208 
209     // This variable allows ensureVisible to move the contents then
210     // update both the sliders.  Otherwise, updating the sliders would
211     // cause two image scrolls, creating ugly flashing.
212     //
213     uint signal_choke : 1;
214 
215     // This variables indicates in updateScrollBars() that we are
216     // in a resizeEvent() and thus don't want to flash scroll bars
217     uint inresize : 1;
218     uint use_cached_size_hint : 1;
219     QSize cachedSizeHint;
220 
contentsX() const221     inline int contentsX() const { return -vx; }
contentsY() const222     inline int contentsY() const { return -vy; }
contentsWidth() const223     inline int contentsWidth() const { return vwidth; }
224 };
225 
~KtlQ3ScrollViewData()226 inline KtlQ3ScrollViewData::~KtlQ3ScrollViewData()
227 {
228     //children.setAutoDelete(true); // 2018.12.08
229     for (QList<QSVChildRec*>::iterator it = children.begin();
230             it != children.end(); ++it) {
231         QSVChildRec *r = *it;
232         delete r;
233     }
234     children.removeAll(nullptr);
235 }
236 
ancestorRec(QWidget * w)237 QSVChildRec* KtlQ3ScrollViewData::ancestorRec(QWidget* w)
238 {
239     if (clipped_viewport) {
240         while (w->parentWidget() != clipped_viewport) {
241             w = w->parentWidget();
242             if (!w) return nullptr;
243         }
244     } else {
245         while (w->parentWidget() != viewport) {
246             w = w->parentWidget();
247             if (!w) return nullptr;
248         }
249     }
250     return rec(w);
251 }
252 
hideOrShowAll(KtlQ3ScrollView * sv,bool isScroll)253 void KtlQ3ScrollViewData::hideOrShowAll(KtlQ3ScrollView* sv, bool isScroll)
254 {
255     if (!clipped_viewport)
256         return;
257     if (clipped_viewport->x() <= 0
258          && clipped_viewport->y() <= 0
259          && clipped_viewport->width()+clipped_viewport->x() >=
260          viewport->width()
261          && clipped_viewport->height()+clipped_viewport->y() >=
262          viewport->height()) {
263         // clipped_viewport still covers viewport
264         if(static_bg) {
265             //clipped_viewport->repaint(true); // 2018.11.30
266             clipped_viewport->repaint();
267         }
268         else if ((!isScroll && !clipped_viewport->testAttribute(Qt::WA_StaticContents)) || static_bg)
269             clipped_viewport->update();
270     } else {
271         // Re-center
272         int nx = (viewport->width() - clipped_viewport->width()) / 2;
273         int ny = (viewport->height() - clipped_viewport->height()) / 2;
274         clipped_viewport->move(nx,ny);
275         clipped_viewport->update();
276     }
277     //for (QSVChildRec *r = children.first(); r; r=children.next()) {   // 2018.12.08
278     //    r->hideOrShow(sv, clipped_viewport);
279     //}
280     for (QList<QSVChildRec*>::iterator it = children.begin();
281             it != children.end(); ++it) {
282         QSVChildRec *r = *it;
283         r->hideOrShow(sv, clipped_viewport);
284     }
285 }
286 
moveAllBy(int dx,int dy)287 void KtlQ3ScrollViewData::moveAllBy(int dx, int dy)
288 {
289     if (clipped_viewport && !static_bg) {
290         clipped_viewport->move(clipped_viewport->x()+dx,
291                                 clipped_viewport->y()+dy);
292     } else {
293         //for (QSVChildRec *r = children.first(); r; r=children.next()) { // 2018.12.07
294         //    r->child->move(r->child->x()+dx,r->child->y()+dy);
295         //}
296         for (QList<QSVChildRec*>::iterator it = children.begin();
297                 it != children.end(); ++it) {
298             QSVChildRec *r = *it;
299             r->child->move(r->child->x()+dx,r->child->y()+dy);
300         }
301 
302         if (static_bg) {
303             //viewport->repaint(true); // 2018.11.30
304             viewport->repaint();
305         }
306     }
307 }
308 
anyVisibleChildren()309 bool KtlQ3ScrollViewData::anyVisibleChildren()
310 {
311     //for (QSVChildRec *r = children.first(); r; r=children.next()) {   // 2018.12.08
312     //    if (r->child->isVisible()) return true;
313     //}
314     for (QList<QSVChildRec*>::iterator it = children.begin();
315             it != children.end(); ++it) {
316         QSVChildRec *r = *it;
317         if (r->child->isVisible()) return true;
318     }
319     return false;
320 }
321 
autoMove(KtlQ3ScrollView * sv)322 void KtlQ3ScrollViewData::autoMove(KtlQ3ScrollView* sv)
323 {
324     if (policy == KtlQ3ScrollView::AutoOne) {
325         QSVChildRec* r = children.first();
326         if (r)
327             sv->setContentsPos(-r->child->x(),-r->child->y());
328     }
329 }
330 
autoResize(KtlQ3ScrollView * sv)331 void KtlQ3ScrollViewData::autoResize(KtlQ3ScrollView* sv)
332 {
333     if (policy == KtlQ3ScrollView::AutoOne) {
334         QSVChildRec* r = children.first();
335         if (r)
336             sv->resizeContents(r->child->width(),r->child->height());
337     }
338 }
339 
autoResizeHint(KtlQ3ScrollView * sv)340 void KtlQ3ScrollViewData::autoResizeHint(KtlQ3ScrollView* sv)
341 {
342     if (policy == KtlQ3ScrollView::AutoOne) {
343         QSVChildRec* r = children.first();
344         if (r) {
345             QSize s = r->child->sizeHint();
346             if (s.isValid())
347                 r->child->resize(s);
348         }
349     } else if (policy == KtlQ3ScrollView::AutoOneFit) {
350         QSVChildRec* r = children.first();
351         if (r) {
352             QSize sh = r->child->sizeHint();
353             sh = sh.boundedTo(r->child->maximumSize());
354             sv->resizeContents(sh.width(), sh.height());
355         }
356     }
357 }
358 
viewportResized(int w,int h)359 void KtlQ3ScrollViewData::viewportResized(int w, int h)
360 {
361     if (policy == KtlQ3ScrollView::AutoOneFit) {
362         QSVChildRec* r = children.first();
363         if (r) {
364             QSize sh = r->child->sizeHint();
365             sh = sh.boundedTo(r->child->maximumSize());
366             r->child->resize(qMax(w,sh.width()), qMax(h,sh.height()));
367         }
368 
369     }
370 }
371 
372 
373 /*!
374     \class KtlQ3ScrollView
375     \brief The KtlQ3ScrollView widget provides a scrolling area with on-demand scroll bars.
376 
377     \compat
378 
379     The KtlQ3ScrollView is a large canvas - potentially larger than the
380     coordinate system normally supported by the underlying window
381     system. This is important because it is quite easy to go beyond
382     these limitations (e.g. many web pages are more than 32000 pixels
383     high). Additionally, the KtlQ3ScrollView can have QWidgets positioned
384     on it that scroll around with the drawn content. These sub-widgets
385     can also have positions outside the normal coordinate range (but
386     they are still limited in size).
387 
388     To provide content for the widget, inherit from KtlQ3ScrollView,
389     reimplement drawContents() and use resizeContents() to set the
390     size of the viewed area. Use addChild() and moveChild() to
391     position widgets on the view.
392 
393     To use KtlQ3ScrollView effectively it is important to understand its
394     widget structure in the three styles of use: a single large child
395     widget, a large panning area with some widgets and a large panning
396     area with many widgets.
397 
398     \section1 Using One Big Widget
399 
400     \img qscrollview-vp2.png
401 
402     The first, simplest usage of KtlQ3ScrollView (depicted above), is
403     appropriate for scrolling areas that are never more than about
404     4000 pixels in either dimension (this is about the maximum
405     reliable size on X11 servers). In this usage, you just make one
406     large child in the KtlQ3ScrollView. The child should be a child of the
407     viewport() of the scrollview and be added with addChild():
408     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 0
409     You can go on to add arbitrary child widgets to the single child
410     in the scrollview as you would with any widget:
411     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 1
412 
413     Here the KtlQ3ScrollView has four children: the viewport(), the
414     verticalScrollBar(), the horizontalScrollBar() and a small
415     cornerWidget(). The viewport() has one child: the QWidget. The
416     QWidget has the three QLabel objects as child widgets. When the view
417     is scrolled, the QWidget is moved; its children move with it as
418     child widgets normally do.
419 
420     \section1 Using a Very Big View with Some Widgets
421 
422     \img qscrollview-vp.png
423 
424     The second usage of KtlQ3ScrollView (depicted above) is appropriate
425     when few, if any, widgets are on a very large scrolling area that
426     is potentially larger than 4000 pixels in either dimension. In
427     this usage you call resizeContents() to set the size of the area
428     and reimplement drawContents() to paint the contents. You may also
429     add some widgets by making them children of the viewport() and
430     adding them with addChild() (this is the same as the process for
431     the single large widget in the previous example):
432     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 2
433     Here, the KtlQ3ScrollView has the same four children: the viewport(),
434     the verticalScrollBar(), the horizontalScrollBar() and a small
435     cornerWidget(). The viewport() has the three QLabel objects as
436     child widgets. When the view is scrolled, the scrollview moves the
437     child widgets individually.
438 
439     \section1 Using a Very Big View with Many Widgets
440 
441     \img qscrollview-cl.png
442 
443     The final usage of KtlQ3ScrollView (depicted above) is appropriate
444     when many widgets are on a very large scrolling area that is
445     potentially larger than 4000 pixels in either dimension. In this
446     usage you call resizeContents() to set the size of the area and
447     reimplement drawContents() to paint the contents. You then call
448     enableClipper(true) and add widgets, again by making them children
449     of the viewport(), and adding them with addChild():
450     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 3
451 
452     Here, the KtlQ3ScrollView has four children:  the clipper() (not the
453     viewport() this time), the verticalScrollBar(), the
454     horizontalScrollBar() and a small cornerWidget(). The clipper()
455     has one child: the viewport(). The viewport() has the same three
456     labels as child widgets. When the view is scrolled the viewport()
457     is moved; its children move with it as child widgets normally do.
458 
459     \target allviews
460     \section1 Details Relevant for All Views
461 
462     Normally you will use the first or third method if you want any
463     child widgets in the view.
464 
465     Note that the widget you see in the scrolled area is the
466     viewport() widget, not the KtlQ3ScrollView itself. So to turn mouse
467     tracking on, for example, use viewport()->setMouseTracking(true).
468 
469     To enable drag-and-drop, you would setAcceptDrops(true) on the
470     KtlQ3ScrollView (because drag-and-drop events propagate to the
471     parent). But to work out the logical position in the view, you
472     would need to map the drop co-ordinate from being relative to the
473     KtlQ3ScrollView to being relative to the contents; use the function
474     viewportToContents() for this.
475 
476     To handle mouse events on the scrolling area, subclass scrollview
477     as you would subclass other widgets, but rather than
478     reimplementing mousePressEvent(), reimplement
479     contentsMousePressEvent() instead. The contents specific event
480     handlers provide translated events in the coordinate system of the
481     scrollview. If you reimplement mousePressEvent(), you'll get
482     called only when part of the KtlQ3ScrollView is clicked: and the only
483     such part is the "corner" (if you don't set a cornerWidget()) and
484     the frame; everything else is covered up by the viewport, clipper
485     or scroll bars.
486 
487     When you construct a KtlQ3ScrollView, some of the window flags apply
488     to the viewport() instead of being sent to the QWidget constructor
489     for the KtlQ3ScrollView.
490 
491     \list
492 
493     \i An image-manipulation widget would use \c
494     WNoAutoErase|WStaticContents because the widget draws all pixels
495     itself, and when its size increases, it only needs a paint event
496     for the new part because the old part remains unchanged.
497 
498     \i A scrolling game widget in which the background scrolls as the
499     characters move might use \c WNoAutoErase (in addition to \c
500     WStaticContents) so that the window system background does not
501     flash in and out during scrolling.
502 
503     \i A word processing widget might use \c WNoAutoErase and repaint
504     itself line by line to get a less-flickery resizing. If the widget
505     is in a mode in which no text justification can take place, it
506     might use \c WStaticContents too, so that it would only get a
507     repaint for the newly visible parts.
508 
509     \endlist
510 
511     Child widgets may be moved using addChild() or moveChild(). Use
512     childX() and childY() to get the position of a child widget.
513 
514     A widget may be placed in the corner between the vertical and
515     horizontal scroll bars with setCornerWidget(). You can get access
516     to the scroll bars using horizontalScrollBar() and
517     verticalScrollBar(), and to the viewport with viewport(). The
518     scroll view can be scrolled using scrollBy(), ensureVisible(),
519     setContentsPos() or center().
520 
521     The visible area is given by visibleWidth() and visibleHeight(),
522     and the contents area by contentsWidth() and contentsHeight(). The
523     contents may be repainted using one of the repaintContents() or
524     updateContents() functions.
525 
526     Coordinate conversion is provided by contentsToViewport() and
527     viewportToContents().
528 
529     The contentsMoving() signal is emitted just before the contents
530     are moved to a new position.
531 
532     \warning KtlQ3ScrollView currently does not erase the background when
533     resized, i.e. you must always clear the background manually in
534     scrollview subclasses. This will change in a future version of Qt
535     and we recommend specifying the \c WNoAutoErase flag explicitly.
536 */
537 
538 
539 /*!
540     \enum KtlQ3ScrollView::ResizePolicy
541 
542     This enum type is used to control a KtlQ3ScrollView's reaction to
543     resize events.
544 
545     \value Default  the KtlQ3ScrollView selects one of the other settings
546     automatically when it has to. In this version of Qt, KtlQ3ScrollView
547     changes to \c Manual if you resize the contents with
548     resizeContents() and to \c AutoOne if a child is added.
549 
550     \value Manual  the contents stays the size set by resizeContents().
551 
552     \value AutoOne  if there is only one child widget the contents stays
553     the size of that widget. Otherwise the behavior is undefined.
554 
555     \value AutoOneFit if there is only one child widget the contents stays
556     the size of that widget's sizeHint(). If the scrollview is resized
557     larger than the child's sizeHint(), the child will be resized to
558     fit. If there is more than one child, the behavior is undefined.
559 
560 */
561 //####  The widget will be resized to its sizeHint() when a LayoutHint event
562 //#### is received
563 
564 /*!
565     Constructs a KtlQ3ScrollView called \a name with parent \a parent and
566     widget flags \a f.
567 
568     The widget flags \c WStaticContents, \c WNoAutoErase and \c
569     WPaintClever are propagated to the viewport() widget. The other
570     widget flags are propagated to the parent constructor as usual.
571 */
572 
KtlQ3ScrollView(QWidget * parent,const char * name,Qt::WindowFlags f)573 KtlQ3ScrollView::KtlQ3ScrollView(QWidget *parent, const char *name, Qt::WindowFlags f) :
574     KtlQ3Frame(parent, name, f & (~Qt::WA_StaticContents) /*& (~Qt::WNoAutoErase) & (~Qt::WResizeNoErase) */ )
575 {
576     Qt::WindowFlags flags = /* Qt::WResizeNoErase |  (f&Qt::WPaintClever)
577         | (f&Qt::WRepaintNoErase) | */ (f&Qt::WA_StaticContents);
578     d = new KtlQ3ScrollViewData(this, flags);
579 
580 #ifndef QT_NO_DRAGANDDROP
581     connect(&d->autoscroll_timer, SIGNAL(timeout()),
582              this, SLOT(doDragAutoScroll()));
583 #endif
584 
585     connect(d->hbar, SIGNAL(valueChanged(int)),
586         this, SLOT(hslide(int)));
587     connect(d->vbar, SIGNAL(valueChanged(int)),
588         this, SLOT(vslide(int)));
589 
590     connect(d->hbar, SIGNAL(sliderPressed()), this, SLOT(hbarIsPressed()));
591     connect(d->hbar, SIGNAL(sliderReleased()), this, SLOT(hbarIsReleased()));
592     connect(d->vbar, SIGNAL(sliderPressed()), this, SLOT(vbarIsPressed()));
593     connect(d->vbar, SIGNAL(sliderReleased()), this, SLOT(vbarIsReleased()));
594 
595 
596     d->viewport->installEventFilter(this);
597 
598     connect(&d->scrollbar_timer, SIGNAL(timeout()),
599              this, SLOT(updateScrollBars()));
600 
601     setFrameStyle(KtlQ3Frame::StyledPanel | KtlQ3Frame::Sunken);
602     setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
603     setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
604 }
605 
606 
607 /*!
608     Destroys the KtlQ3ScrollView. Any children added with addChild() will
609     be deleted.
610 */
~KtlQ3ScrollView()611 KtlQ3ScrollView::~KtlQ3ScrollView()
612 {
613     // Be careful not to get all those useless events...
614     if (d->clipped_viewport)
615         d->clipped_viewport->removeEventFilter(this);
616     else
617         d->viewport->removeEventFilter(this);
618 
619     // order is important
620     // ~QWidget may cause a WM_ERASEBKGND on Windows
621     delete d->vbar;
622     d->vbar = nullptr;
623     delete d->hbar;
624     d->hbar = nullptr;
625     delete d->viewport;
626     d->viewport = nullptr;
627     delete d;
628     d = nullptr;
629 }
630 
631 /*!
632     \fn void KtlQ3ScrollView::horizontalSliderPressed()
633 
634     This signal is emitted whenever the user presses the horizontal slider.
635 */
636 /*!
637     \fn void KtlQ3ScrollView::horizontalSliderReleased()
638 
639     This signal is emitted whenever the user releases the horizontal slider.
640 */
641 /*!
642     \fn void KtlQ3ScrollView::verticalSliderPressed()
643 
644     This signal is emitted whenever the user presses the vertical slider.
645 */
646 /*!
647     \fn void KtlQ3ScrollView::verticalSliderReleased()
648 
649     This signal is emitted whenever the user releases the vertical slider.
650 */
hbarIsPressed()651 void KtlQ3ScrollView::hbarIsPressed()
652 {
653     d->hbarPressed = true;
654     emit(horizontalSliderPressed());
655 }
656 
hbarIsReleased()657 void KtlQ3ScrollView::hbarIsReleased()
658 {
659     d->hbarPressed = false;
660     emit(horizontalSliderReleased());
661 }
662 
663 /*!
664     Returns true if horizontal slider is pressed by user; otherwise returns false.
665 */
isHorizontalSliderPressed()666 bool KtlQ3ScrollView::isHorizontalSliderPressed()
667 {
668     return d->hbarPressed;
669 }
670 
vbarIsPressed()671 void KtlQ3ScrollView::vbarIsPressed()
672 {
673     d->vbarPressed = true;
674     emit(verticalSliderPressed());
675 }
676 
vbarIsReleased()677 void KtlQ3ScrollView::vbarIsReleased()
678 {
679     d->vbarPressed = false;
680     emit(verticalSliderReleased());
681 }
682 
683 /*!
684     Returns true if vertical slider is pressed by user; otherwise returns false.
685 */
isVerticalSliderPressed()686 bool KtlQ3ScrollView::isVerticalSliderPressed()
687 {
688     return d->vbarPressed;
689 }
690 
691 /*!
692     \internal
693 */
styleChange(QStyle & old)694 void KtlQ3ScrollView::styleChange(QStyle& old)
695 {
696     //QWidget::styleChange(old); // 2019.04.14
697     updateScrollBars();
698     d->cachedSizeHint = QSize();
699 }
700 
701 /*!
702     \internal
703 */
fontChange(const QFont & old)704 void KtlQ3ScrollView::fontChange(const QFont &old)
705 {
706     //QWidget::fontChange(old); // 2019.04.14
707     updateScrollBars();
708     d->cachedSizeHint = QSize();
709 }
710 
hslide(int pos)711 void KtlQ3ScrollView::hslide(int pos)
712 {
713     if (!d->signal_choke) {
714         moveContents(-pos, -d->contentsY());
715         QApplication::syncX();
716     }
717 }
718 
vslide(int pos)719 void KtlQ3ScrollView::vslide(int pos)
720 {
721     if (!d->signal_choke) {
722         moveContents(-d->contentsX(), -pos);
723         QApplication::syncX();
724     }
725 }
726 
727 /*!
728     Called when the horizontal scroll bar geometry changes. This is
729     provided as a protected function so that subclasses can do
730     interesting things such as providing extra buttons in some of the
731     space normally used by the scroll bars.
732 
733     The default implementation simply gives all the space to \a hbar.
734     The new geometry is given by \a x, \a y, \a w and \a h.
735 
736     \sa setVBarGeometry()
737 */
setHBarGeometry(QScrollBar & hbar,int x,int y,int w,int h)738 void KtlQ3ScrollView::setHBarGeometry(QScrollBar& hbar,
739     int x, int y, int w, int h)
740 {
741     hbar.setGeometry(x, y, w, h);
742 }
743 
744 /*!
745     Called when the vertical scroll bar geometry changes. This is
746     provided as a protected function so that subclasses can do
747     interesting things such as providing extra buttons in some of the
748     space normally used by the scroll bars.
749 
750     The default implementation simply gives all the space to \a vbar.
751     The new geometry is given by \a x, \a y, \a w and \a h.
752 
753     \sa setHBarGeometry()
754 */
setVBarGeometry(QScrollBar & vbar,int x,int y,int w,int h)755 void KtlQ3ScrollView::setVBarGeometry(QScrollBar& vbar,
756     int x, int y, int w, int h)
757 {
758     vbar.setGeometry(x, y, w, h);
759 }
760 
761 
762 /*!
763     Returns the viewport size for size (\a x, \a y).
764 
765     The viewport size depends on (\a x, \a y) (the size of the contents),
766     the size of this widget and the modes of the horizontal and
767     vertical scroll bars.
768 
769     This function permits widgets that can trade vertical and
770     horizontal space for each other to control scroll bar appearance
771     better. For example, a word processor or web browser can control
772     the width of the right margin accurately, whether or not there
773     needs to be a vertical scroll bar.
774 */
775 
viewportSize(int x,int y) const776 QSize KtlQ3ScrollView::viewportSize(int x, int y) const
777 {
778     int fw = frameWidth();
779     int lmarg = fw+d->l_marg;
780     int rmarg = fw+d->r_marg;
781     int tmarg = fw+d->t_marg;
782     int bmarg = fw+d->b_marg;
783 
784     int w = width();
785     int h = height();
786 
787     bool needh, needv;
788     bool showh, showv;
789     int hsbExt = horizontalScrollBar()->sizeHint().height();
790     int vsbExt = verticalScrollBar()->sizeHint().width();
791 
792     if (d->policy != AutoOne || d->anyVisibleChildren()) {
793         // Do we definitely need the scroll bar?
794         needh = w-lmarg-rmarg < x;
795         needv = h-tmarg-bmarg < y;
796 
797         // Do we intend to show the scroll bar?
798         if (d->hMode == AlwaysOn)
799             showh = true;
800         else if (d->hMode == AlwaysOff)
801             showh = false;
802         else
803             showh = needh;
804 
805         if (d->vMode == AlwaysOn)
806             showv = true;
807         else if (d->vMode == AlwaysOff)
808             showv = false;
809         else
810             showv = needv;
811 
812         // Given other scroll bar will be shown, NOW do we need one?
813         if (showh && h-vsbExt-tmarg-bmarg < y) {
814             if (d->vMode == Auto)
815                 showv=true;
816         }
817         if (showv && w-hsbExt-lmarg-rmarg < x) {
818             if (d->hMode == Auto)
819                 showh=true;
820         }
821     } else {
822         // Scroll bars not needed, only show scroll bar that are always on.
823         showh = d->hMode == AlwaysOn;
824         showv = d->vMode == AlwaysOn;
825     }
826 
827     return QSize(w-lmarg-rmarg - (showv ? vsbExt : 0),
828                   h-tmarg-bmarg - (showh ? hsbExt : 0));
829 }
830 
831 
832 /*!
833     Updates scroll bars: all possibilities are considered. You should
834     never need to call this in your code.
835 */
updateScrollBars()836 void KtlQ3ScrollView::updateScrollBars()
837 {
838     if(!horizontalScrollBar() && !verticalScrollBar())
839         return;
840 
841     // I support this should use viewportSize()... but it needs
842     // so many of the temporary variables from viewportSize.  hm.
843     int fw = frameWidth();
844     int lmarg = fw+d->l_marg;
845     int rmarg = fw+d->r_marg;
846     int tmarg = fw+d->t_marg;
847     int bmarg = fw+d->b_marg;
848 
849     int w = width();
850     int h = height();
851 
852     int portw, porth;
853 
854     bool needh;
855     bool needv;
856     bool showh;
857     bool showv;
858     bool showc = false;
859 
860     int hsbExt = horizontalScrollBar()->sizeHint().height();
861     int vsbExt = verticalScrollBar()->sizeHint().width();
862 
863     QSize oldVisibleSize(visibleWidth(), visibleHeight());
864 
865     if (d->policy != AutoOne || d->anyVisibleChildren()) {
866         // Do we definitely need the scroll bar?
867         needh = w-lmarg-rmarg < d->contentsWidth();
868         if (d->inresize)
869             needh  = !horizontalScrollBar()->isHidden();
870         needv = h-tmarg-bmarg < contentsHeight();
871 
872         // Do we intend to show the scroll bar?
873         if (d->hMode == AlwaysOn)
874             showh = true;
875         else if (d->hMode == AlwaysOff)
876             showh = false;
877         else
878             showh = needh;
879 
880         if (d->vMode == AlwaysOn)
881             showv = true;
882         else if (d->vMode == AlwaysOff)
883             showv = false;
884         else
885             showv = needv;
886 
887 #ifdef Q_WS_MAC
888         bool mac_need_scroll = false;
889         if(!parentWidget()) {
890             mac_need_scroll = true;
891         } else {
892             QWidget *tlw = window();
893 // #ifndef QT_MAC_USE_COCOA           // 2018.10.18 - do not depend on internal headers
894 //             QPoint tlw_br = QPoint(tlw->width(), tlw->height()),
895 //                     my_br = qt_mac_posInWindow(this) + QPoint(w, h);
896 //             if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3)
897 // #endif
898                 mac_need_scroll = true;
899         }
900         if(mac_need_scroll) {
901 // #ifndef QT_MAC_USE_COCOA           // 2018.10.18 - do not depend on internal headers
902 //             WindowAttributes attr;
903 //             GetWindowAttributes((WindowPtr)handle(), &attr);
904 //             mac_need_scroll = (attr & kWindowResizableAttribute);
905 // #endif
906         }
907         if(mac_need_scroll) {
908             showc = true;
909             if(d->vMode == Auto)
910                 showv = true;
911             if(d->hMode == Auto)
912                 showh = true;
913         }
914 #endif
915 
916         // Given other scroll bar will be shown, NOW do we need one?
917         if (showh && h-vsbExt-tmarg-bmarg < contentsHeight()) {
918             needv=true;
919             if (d->vMode == Auto)
920                 showv=true;
921         }
922         if (showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth()) {
923             needh=true;
924             if (d->hMode == Auto)
925                 showh=true;
926         }
927     } else {
928         // Scrollbars not needed, only show scroll bar that are always on.
929         needh = needv = false;
930         showh = d->hMode == AlwaysOn;
931         showv = d->vMode == AlwaysOn;
932     }
933 
934     bool sc = d->signal_choke;
935     d->signal_choke=true;
936 
937     // Hide unneeded scroll bar, calculate viewport size
938     if (showh) {
939         porth=h-hsbExt-tmarg-bmarg;
940     } else {
941         if (!needh)
942             d->hbar->setValue(0);
943         d->hbar->hide();
944         porth=h-tmarg-bmarg;
945     }
946     if (showv) {
947         portw=w-vsbExt-lmarg-rmarg;
948     } else {
949         if (!needv)
950             d->vbar->setValue(0);
951         d->vbar->hide();
952         portw=w-lmarg-rmarg;
953     }
954 
955     // Configure scroll bars that we will show
956     if (needv) {
957         d->vbar->setRange(0, contentsHeight()-porth);
958         //d->vbar->setSteps(KtlQ3ScrollView::d->vbar->lineStep(), porth); // 2018.11.30
959         d->vbar->setSingleStep(KtlQ3ScrollView::d->vbar->singleStep());
960         d->vbar->setPageStep(porth);
961     } else {
962         d->vbar->setRange(0, 0);
963     }
964     if (needh) {
965         d->hbar->setRange(0, qMax(0, d->contentsWidth()-portw));
966         //d->hbar->setSteps(KtlQ3ScrollView::d->hbar->lineStep(), portw); // 2018.11.30
967         d->hbar->setSingleStep(KtlQ3ScrollView::d->hbar->singleStep());
968         d->hbar->setPageStep(portw);
969     } else {
970         d->hbar->setRange(0, 0);
971     }
972 
973     // Position the scroll bars, viewport and corner widget.
974     int bottom;
975     bool reverse = QApplication::layoutDirection() == Qt::RightToLeft;
976     int xoffset = (reverse && (showv || cornerWidget())) ? vsbExt : 0;
977     int xpos = reverse ? 0 : w - vsbExt;
978     bool frameContentsOnly =
979         style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
980 
981     if(! frameContentsOnly) {
982         if (reverse)
983             xpos += fw;
984         else
985             xpos -= fw;
986     }
987     if (showh) {
988         int right = (showc || showv || cornerWidget()) ? w-vsbExt : w;
989         if (! frameContentsOnly)
990             setHBarGeometry(*d->hbar, fw + xoffset, h-hsbExt-fw,
991                              right-fw-fw, hsbExt);
992         else
993             setHBarGeometry(*d->hbar, 0 + xoffset, h-hsbExt, right,
994                              hsbExt);
995         bottom=h-hsbExt;
996     } else {
997         bottom=h;
998     }
999     if (showv) {
1000         clipper()->setGeometry(lmarg + xoffset, tmarg,
1001                                 w-vsbExt-lmarg-rmarg,
1002                                 bottom-tmarg-bmarg);
1003         d->viewportResized(w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg);
1004         if (! frameContentsOnly)
1005             changeFrameRect(QRect(0, 0, w, h));
1006         else
1007             changeFrameRect(QRect(xoffset, 0, w-vsbExt, bottom));
1008         if (showc || cornerWidget()) {
1009             if (! frameContentsOnly)
1010                 setVBarGeometry(*d->vbar, xpos,
1011                                  fw, vsbExt,
1012                                  h-hsbExt-fw-fw);
1013             else
1014                 setVBarGeometry(*d->vbar, xpos, 0,
1015                                  vsbExt,
1016                                  h-hsbExt);
1017         }
1018         else {
1019             if (! frameContentsOnly)
1020                 setVBarGeometry(*d->vbar, xpos,
1021                                  fw, vsbExt,
1022                                  bottom-fw-fw);
1023             else
1024                 setVBarGeometry(*d->vbar, xpos, 0,
1025                                  vsbExt, bottom);
1026         }
1027     } else {
1028         if (! frameContentsOnly)
1029             changeFrameRect(QRect(0, 0, w, h));
1030         else
1031             changeFrameRect(QRect(0, 0, w, bottom));
1032         clipper()->setGeometry(lmarg, tmarg,
1033                                 w-lmarg-rmarg, bottom-tmarg-bmarg);
1034         d->viewportResized(w-lmarg-rmarg, bottom-tmarg-bmarg);
1035     }
1036 
1037     QWidget *corner = d->corner;
1038     if (d->corner) {
1039         if (! frameContentsOnly)
1040             corner->setGeometry(xpos,
1041                                 h-hsbExt-fw,
1042                                 vsbExt,
1043                                 hsbExt);
1044         else
1045             corner->setGeometry(xpos,
1046                                 h-hsbExt,
1047                                 vsbExt,
1048                                 hsbExt);
1049     }
1050 
1051     d->signal_choke=sc;
1052 
1053     if (d->contentsX()+visibleWidth() > d->contentsWidth()) {
1054         int x;
1055 #if 0
1056         if (reverse)
1057             x =qMin(0,d->contentsWidth()-visibleWidth());
1058         else
1059 #endif
1060             x =qMax(0,d->contentsWidth()-visibleWidth());
1061         d->hbar->setValue(x);
1062         // Do it even if it is recursive
1063         moveContents(-x, -d->contentsY());
1064     }
1065     if (d->contentsY()+visibleHeight() > contentsHeight()) {
1066         int y=qMax(0,contentsHeight()-visibleHeight());
1067         d->vbar->setValue(y);
1068         // Do it even if it is recursive
1069         moveContents(-d->contentsX(), -y);
1070     }
1071 
1072     // Finally, show the scroll bars
1073     if (showh && (d->hbar->isHidden() || !d->hbar->isVisible()))
1074         d->hbar->show();
1075     if (showv && (d->vbar->isHidden() || !d->vbar->isVisible()))
1076         d->vbar->show();
1077 
1078     d->signal_choke=true;
1079     d->vbar->setValue(d->contentsY());
1080     d->hbar->setValue(d->contentsX());
1081     d->signal_choke=false;
1082 
1083     QSize newVisibleSize(visibleWidth(), visibleHeight());
1084     if (d->clipped_viewport && oldVisibleSize != newVisibleSize) {
1085         QResizeEvent e(newVisibleSize, oldVisibleSize);
1086         viewportResizeEvent(&e);
1087     }
1088 }
1089 
1090 
1091 /*!
1092     \reimp
1093 */
setVisible(bool visible)1094 void KtlQ3ScrollView::setVisible(bool visible)
1095 {
1096     if (visible && !isVisible()) {
1097         QWidget::setVisible(visible);
1098         updateScrollBars();
1099         d->hideOrShowAll(this);
1100     } else {
1101         QWidget::setVisible(visible);
1102     }
1103 }
1104 
1105 /*!
1106     \internal
1107  */
resize(int w,int h)1108 void KtlQ3ScrollView::resize(int w, int h)
1109 {
1110     QWidget::resize(w, h);
1111 }
1112 
1113 /*!
1114     \internal
1115 */
resize(const QSize & s)1116 void KtlQ3ScrollView::resize(const QSize& s)
1117 {
1118     resize(s.width(), s.height());
1119 }
1120 
1121 /*!
1122     \reimp
1123 */
resizeEvent(QResizeEvent * event)1124 void KtlQ3ScrollView::resizeEvent(QResizeEvent* event)
1125 {
1126     //KtlQ3Frame::resizeEvent();
1127 
1128 #if 0
1129     if (QApplication::reverseLayout()) {
1130         d->fake_scroll = true;
1131         scrollBy(-event->size().width() + event->oldSize().width(), 0);
1132         d->fake_scroll = false;
1133     }
1134 #endif
1135 
1136     bool inresize = d->inresize;
1137     d->inresize = true;
1138     updateScrollBars();
1139     d->inresize = inresize;
1140     //d->scrollbar_timer.start(0, true); // 2018.11.30
1141     d->scrollbar_timer.setSingleShot(true);
1142     d->scrollbar_timer.start(0);
1143 
1144     d->hideOrShowAll(this);
1145 }
1146 
1147 
1148 
1149 /*!
1150     \reimp
1151 */
mousePressEvent(QMouseEvent * e)1152 void  KtlQ3ScrollView::mousePressEvent(QMouseEvent * e)
1153 {
1154     e->ignore();
1155 }
1156 
1157 /*!
1158     \reimp
1159 */
mouseReleaseEvent(QMouseEvent * e)1160 void  KtlQ3ScrollView::mouseReleaseEvent(QMouseEvent *e)
1161 {
1162     e->ignore();
1163 }
1164 
1165 
1166 /*!
1167     \reimp
1168 */
mouseDoubleClickEvent(QMouseEvent * e)1169 void  KtlQ3ScrollView::mouseDoubleClickEvent(QMouseEvent *e)
1170 {
1171     e->ignore();
1172 }
1173 
1174 /*!
1175     \reimp
1176 */
mouseMoveEvent(QMouseEvent * e)1177 void  KtlQ3ScrollView::mouseMoveEvent(QMouseEvent *e)
1178 {
1179     e->ignore();
1180 }
1181 
1182 /*!
1183     \reimp
1184 */
1185 #ifndef QT_NO_WHEELEVENT
wheelEvent(QWheelEvent * e)1186 void KtlQ3ScrollView::wheelEvent(QWheelEvent *e)
1187 {
1188     /* QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()),
1189                     e->globalPos(), e->delta(), e->state());  - 2018.11.30*/
1190     QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()),
1191                     e->globalPos(), e->delta(), e->buttons(), e->modifiers());
1192     viewportWheelEvent(&ce);
1193     if (!ce.isAccepted()) {
1194         if (e->orientation() == Qt::Horizontal && horizontalScrollBar())
1195             horizontalScrollBar()->event(e);
1196         else  if (e->orientation() == Qt::Vertical && verticalScrollBar())
1197             verticalScrollBar()->event(e);
1198     } else {
1199         e->accept();
1200     }
1201 }
1202 #endif
1203 
1204 /*!
1205     \reimp
1206 */
contextMenuEvent(QContextMenuEvent * e)1207 void KtlQ3ScrollView::contextMenuEvent(QContextMenuEvent *e)
1208 {
1209     if (e->reason() != QContextMenuEvent::Keyboard) {
1210         e->ignore();
1211         return;
1212     }
1213 
1214     /* QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()),
1215                           e->globalPos(), e->state()); - 2018.11.30 */
1216     QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()),
1217                           e->globalPos(), e->modifiers());
1218     viewportContextMenuEvent(&ce);
1219     if (ce.isAccepted())
1220         e->accept();
1221     else
1222         e->ignore();
1223 }
1224 
vScrollBarMode() const1225 KtlQ3ScrollView::ScrollBarMode KtlQ3ScrollView::vScrollBarMode() const
1226 {
1227     return d->vMode;
1228 }
1229 
1230 
1231 /*!
1232     \enum KtlQ3ScrollView::ScrollBarMode
1233 
1234     This enum type describes the various modes of KtlQ3ScrollView's scroll
1235     bars.
1236 
1237     \value Auto  KtlQ3ScrollView shows a scroll bar when the content is
1238     too large to fit and not otherwise. This is the default.
1239 
1240     \value AlwaysOff  KtlQ3ScrollView never shows a scroll bar.
1241 
1242     \value AlwaysOn  KtlQ3ScrollView always shows a scroll bar.
1243 
1244     (The modes for the horizontal and vertical scroll bars are
1245     independent.)
1246 */
1247 
1248 
1249 /*!
1250     \property KtlQ3ScrollView::vScrollBarMode
1251     \brief the mode for the vertical scroll bar
1252 
1253     The default mode is KtlQ3ScrollView::Auto.
1254 
1255     \sa hScrollBarMode
1256 */
setVScrollBarMode(ScrollBarMode mode)1257 void  KtlQ3ScrollView::setVScrollBarMode(ScrollBarMode mode)
1258 {
1259     if (d->vMode != mode) {
1260         d->vMode = mode;
1261         updateScrollBars();
1262     }
1263 }
1264 
1265 
1266 /*!
1267     \property KtlQ3ScrollView::hScrollBarMode
1268     \brief the mode for the horizontal scroll bar
1269 
1270     The default mode is KtlQ3ScrollView::Auto.
1271 
1272     \sa vScrollBarMode
1273 */
hScrollBarMode() const1274 KtlQ3ScrollView::ScrollBarMode KtlQ3ScrollView::hScrollBarMode() const
1275 {
1276     return d->hMode;
1277 }
1278 
setHScrollBarMode(ScrollBarMode mode)1279 void KtlQ3ScrollView::setHScrollBarMode(ScrollBarMode mode)
1280 {
1281     if (d->hMode != mode) {
1282         d->hMode = mode;
1283         updateScrollBars();
1284     }
1285 }
1286 
1287 
1288 /*!
1289     Returns the widget in the corner between the two scroll bars.
1290 
1291     By default, no corner widget is present.
1292 */
cornerWidget() const1293 QWidget* KtlQ3ScrollView::cornerWidget() const
1294 {
1295     return d->corner;
1296 }
1297 
1298 /*!
1299     Sets the widget in the \a corner between the two scroll bars.
1300 
1301     You will probably also want to set at least one of the scroll bar
1302     modes to \c AlwaysOn.
1303 
1304     Passing 0 shows no widget in the corner.
1305 
1306     Any previous \a corner widget is hidden.
1307 
1308     You may call setCornerWidget() with the same widget at different
1309     times.
1310 
1311     All widgets set here will be deleted by the KtlQ3ScrollView when it is
1312     destroyed unless you separately reparent the widget after setting
1313     some other corner widget (or 0).
1314 
1315     Any \e newly set widget should have no current parent.
1316 
1317     By default, no corner widget is present.
1318 
1319     \sa setVScrollBarMode(), setHScrollBarMode()
1320 */
setCornerWidget(QWidget * corner)1321 void KtlQ3ScrollView::setCornerWidget(QWidget* corner)
1322 {
1323     QWidget* oldcorner = d->corner;
1324     if (oldcorner != corner) {
1325         if (oldcorner) oldcorner->hide();
1326         d->corner = corner;
1327         if (corner) corner->setParent(this);
1328         updateScrollBars();
1329         if (corner) corner->show();
1330     }
1331 }
1332 
1333 
setResizePolicy(ResizePolicy r)1334 void KtlQ3ScrollView::setResizePolicy(ResizePolicy r)
1335 {
1336     d->policy = r;
1337 }
1338 
1339 /*!
1340     \property KtlQ3ScrollView::resizePolicy
1341     \brief the resize policy
1342 
1343     The default is \c Default.
1344 
1345     \sa ResizePolicy
1346 */
resizePolicy() const1347 KtlQ3ScrollView::ResizePolicy KtlQ3ScrollView::resizePolicy() const
1348 {
1349     return d->policy;
1350 }
1351 
1352 /*!
1353     \internal
1354 */
setEnabled(bool enable)1355 void KtlQ3ScrollView::setEnabled(bool enable)
1356 {
1357     KtlQ3Frame::setEnabled(enable);
1358 }
1359 
1360 /*!
1361     Removes the \a child widget from the scrolled area. Note that this
1362     happens automatically if the \a child is deleted.
1363 */
removeChild(QWidget * child)1364 void KtlQ3ScrollView::removeChild(QWidget* child)
1365 {
1366     if (!d || !child) // First check in case we are destructing
1367         return;
1368 
1369     QSVChildRec *r = d->rec(child);
1370     if (r) d->deleteChildRec(r);
1371 }
1372 
1373 /*!
1374     \internal
1375 */
removeChild(QObject * child)1376 void KtlQ3ScrollView::removeChild(QObject* child)
1377 {
1378     // KtlQ3Frame::removeChild(child); // 2018.11.30
1379     if (child) {
1380         child->setParent(nullptr);
1381     }
1382 }
1383 
1384 /*!
1385     Inserts the widget, \a child, into the scrolled area positioned at
1386     (\a x, \a y). The position defaults to (0, 0). If the child is
1387     already in the view, it is just moved.
1388 
1389     You may want to call enableClipper(true) if you add a large number
1390     of widgets.
1391 */
addChild(QWidget * child,int x,int y)1392 void KtlQ3ScrollView::addChild(QWidget* child, int x, int y)
1393 {
1394     if (!child) {
1395 #if defined(QT_CHECK_NULL)
1396         qWarning("KtlQ3ScrollView::addChild(): Cannot add null child");
1397 #endif
1398         return;
1399     }
1400     child->ensurePolished();
1401     //child->setBackgroundOrigin(WidgetOrigin); // 2018.11.30 - does nothing in qt4
1402 
1403     if (child->parentWidget() == viewport()) {
1404         // May already be there
1405         QSVChildRec *r = d->rec(child);
1406         if (r) {
1407             r->moveTo(this,x,y,d->clipped_viewport);
1408             if (d->policy > Manual) {
1409                 d->autoResizeHint(this);
1410                 d->autoResize(this); // #### better to just deal with this one widget!
1411             }
1412             return;
1413         }
1414     }
1415 
1416     if (d->children.isEmpty() && d->policy != Manual) {
1417         if (d->policy == Default)
1418             setResizePolicy(AutoOne);
1419         child->installEventFilter(this);
1420     } else if (d->policy == AutoOne) {
1421         child->removeEventFilter(this); //#### ?????
1422         setResizePolicy(Manual);
1423     }
1424     if (child->parentWidget() != viewport()) {
1425             //child->reparent(viewport(), 0, QPoint(0,0), false); // 2018.11.30
1426             child->setParent(viewport());
1427             child->setGeometry(0, 0, child->width(), child->height());
1428     }
1429     d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport);
1430 
1431     if (d->policy > Manual) {
1432         d->autoResizeHint(this);
1433         d->autoResize(this); // #### better to just deal with this one widget!
1434     }
1435 }
1436 
1437 /*!
1438     Repositions the \a child widget to (\a x, \a y). This function is
1439     the same as addChild().
1440 */
moveChild(QWidget * child,int x,int y)1441 void KtlQ3ScrollView::moveChild(QWidget* child, int x, int y)
1442 {
1443     addChild(child,x,y);
1444 }
1445 
1446 /*!
1447     Returns the X position of the given \a child widget. Use this
1448     rather than QWidget::x() for widgets added to the view.
1449 
1450     This function returns 0 if \a child has not been added to the view.
1451 */
childX(QWidget * child)1452 int KtlQ3ScrollView::childX(QWidget* child)
1453 {
1454     QSVChildRec *r = d->rec(child);
1455     return r ? r->x : 0;
1456 }
1457 
1458 /*!
1459     Returns the Y position of the given \a child widget. Use this
1460     rather than QWidget::y() for widgets added to the view.
1461 
1462     This function returns 0 if \a child has not been added to the view.
1463 */
childY(QWidget * child)1464 int KtlQ3ScrollView::childY(QWidget* child)
1465 {
1466     QSVChildRec *r = d->rec(child);
1467     return r ? r->y : 0;
1468 }
1469 
1470 /*! \fn bool KtlQ3ScrollView::childIsVisible(QWidget*)
1471   \obsolete
1472 
1473   Returns true if \a child is visible. This is equivalent
1474   to child->isVisible().
1475 */
1476 
1477 /*! \fn void KtlQ3ScrollView::showChild(QWidget* child, bool y)
1478   \obsolete
1479 
1480   Sets the visibility of \a child. Equivalent to
1481   QWidget::show() or QWidget::hide().
1482 */
1483 
1484 /*!
1485     This event filter ensures the scroll bars are updated when a
1486     single contents widget is resized, shown, hidden or destroyed; it
1487     passes mouse events to the KtlQ3ScrollView. The event is in \a e and
1488     the object is in \a obj.
1489 */
1490 
eventFilter(QObject * obj,QEvent * e)1491 bool KtlQ3ScrollView::eventFilter(QObject *obj, QEvent *e)
1492 {
1493     bool disabled = !(qobject_cast<QWidget*>(obj)->isEnabled());
1494     if (!d)
1495         return false; // we are destructing
1496     if (obj == d->viewport || obj == d->clipped_viewport) {
1497         switch (e->type()) {
1498             /* Forward many events to viewport...() functions */
1499         case QEvent::Paint:
1500             viewportPaintEvent((QPaintEvent*)e);
1501             break;
1502         case QEvent::Resize:
1503             if (!d->clipped_viewport)
1504                 viewportResizeEvent((QResizeEvent *)e);
1505             break;
1506         case QEvent::MouseButtonPress:
1507             if (disabled)
1508                 return false;
1509             viewportMousePressEvent((QMouseEvent*)e);
1510             if (((QMouseEvent*)e)->isAccepted())
1511                 return true;
1512             break;
1513         case QEvent::MouseButtonRelease:
1514             if (disabled)
1515                 return false;
1516             viewportMouseReleaseEvent((QMouseEvent*)e);
1517             if (((QMouseEvent*)e)->isAccepted())
1518                 return true;
1519             break;
1520         case QEvent::MouseButtonDblClick:
1521             if (disabled)
1522                 return false;
1523             viewportMouseDoubleClickEvent((QMouseEvent*)e);
1524             if (((QMouseEvent*)e)->isAccepted())
1525                 return true;
1526             break;
1527         case QEvent::MouseMove:
1528             if (disabled)
1529                 return false;
1530             viewportMouseMoveEvent((QMouseEvent*)e);
1531             if (((QMouseEvent*)e)->isAccepted())
1532                 return true;
1533             break;
1534 #ifndef QT_NO_DRAGANDDROP
1535         case QEvent::DragEnter:
1536             if (disabled)
1537                 return false;
1538             viewportDragEnterEvent((QDragEnterEvent*)e);
1539             break;
1540         case QEvent::DragMove: {
1541             if (disabled)
1542                 return false;
1543             if (d->drag_autoscroll) {
1544                 QPoint vp = ((QDragMoveEvent*) e)->pos();
1545                 QRect inside_margin(autoscroll_margin, autoscroll_margin,
1546                                      visibleWidth() - autoscroll_margin * 2,
1547                                      visibleHeight() - autoscroll_margin * 2);
1548                 if (!inside_margin.contains(vp)) {
1549                     startDragAutoScroll();
1550                     // Keep sending move events
1551                     ((QDragMoveEvent*)e)->accept(QRect(0,0,0,0));
1552                 }
1553             }
1554             viewportDragMoveEvent((QDragMoveEvent*)e);
1555         } break;
1556         case QEvent::DragLeave:
1557             if (disabled)
1558                 return false;
1559             stopDragAutoScroll();
1560             viewportDragLeaveEvent((QDragLeaveEvent*)e);
1561             break;
1562         case QEvent::Drop:
1563             if (disabled)
1564                 return false;
1565             stopDragAutoScroll();
1566             viewportDropEvent((QDropEvent*)e);
1567             break;
1568 #endif // QT_NO_DRAGANDDROP
1569 #ifndef QT_NO_WHEELEVENT
1570         case QEvent::Wheel:
1571             if (disabled)
1572                 return false;
1573             break;
1574 #endif
1575         case QEvent::ContextMenu:
1576             if (disabled)
1577                 return false;
1578             viewportContextMenuEvent((QContextMenuEvent*)e);
1579             if (((QContextMenuEvent*)e)->isAccepted())
1580                 return true;
1581             break;
1582         case QEvent::ChildRemoved:
1583             removeChild((QWidget*)((QChildEvent*)e)->child());
1584             break;
1585         //case QEvent::LayoutHint:  // 2018.12.08 - deprecated
1586         //    d->autoResizeHint(this);
1587         //    break;
1588         default:
1589             break;
1590         }
1591     } else if (d && d->rec((QWidget*)obj)) {  // must be a child
1592         if (e->type() == QEvent::Resize)
1593             d->autoResize(this);
1594         else if (e->type() == QEvent::Move)
1595             d->autoMove(this);
1596     }
1597     return KtlQ3Frame::eventFilter(obj, e);  // always continue with standard event processing
1598 }
1599 
1600 /*!
1601     This event handler is called whenever the KtlQ3ScrollView receives a
1602     mousePressEvent(): the press position in \a e is translated to be a point
1603     on the contents.
1604 */
contentsMousePressEvent(QMouseEvent * e)1605 void KtlQ3ScrollView::contentsMousePressEvent(QMouseEvent* e)
1606 {
1607     e->ignore();
1608 }
1609 
1610 /*!
1611     This event handler is called whenever the KtlQ3ScrollView receives a
1612     mouseReleaseEvent(): the release position in \a e is translated to be a
1613     point on the contents.
1614 */
contentsMouseReleaseEvent(QMouseEvent * e)1615 void KtlQ3ScrollView::contentsMouseReleaseEvent(QMouseEvent* e)
1616 {
1617     e->ignore();
1618 }
1619 
1620 /*!
1621     This event handler is called whenever the KtlQ3ScrollView receives a
1622     mouseDoubleClickEvent(): the click position in \a e is translated to be a
1623     point on the contents.
1624 
1625     The default implementation generates a normal mouse press event.
1626 */
contentsMouseDoubleClickEvent(QMouseEvent * e)1627 void KtlQ3ScrollView::contentsMouseDoubleClickEvent(QMouseEvent* e)
1628 {
1629     contentsMousePressEvent(e);             // try mouse press event
1630 }
1631 
1632 /*!
1633     This event handler is called whenever the KtlQ3ScrollView receives a
1634     mouseMoveEvent(): the mouse position in \a e is translated to be a point
1635     on the contents.
1636 */
contentsMouseMoveEvent(QMouseEvent * e)1637 void KtlQ3ScrollView::contentsMouseMoveEvent(QMouseEvent* e)
1638 {
1639     e->ignore();
1640 }
1641 
1642 #ifndef QT_NO_DRAGANDDROP
1643 
1644 /*!
1645     This event handler is called whenever the KtlQ3ScrollView receives a
1646     dragEnterEvent(): 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 */
contentsDragEnterEvent(QDragEnterEvent *)1652 void KtlQ3ScrollView::contentsDragEnterEvent(QDragEnterEvent * /* event */)
1653 {
1654 }
1655 
1656 /*!
1657     This event handler is called whenever the KtlQ3ScrollView receives a
1658     dragMoveEvent(): the drag position is translated to be a point on
1659     the contents.
1660 
1661     The default implementation does nothing. The \a event parameter is
1662     ignored.
1663 */
contentsDragMoveEvent(QDragMoveEvent *)1664 void KtlQ3ScrollView::contentsDragMoveEvent(QDragMoveEvent * /* event */)
1665 {
1666 }
1667 
1668 /*!
1669     This event handler is called whenever the KtlQ3ScrollView receives a
1670     dragLeaveEvent(): the drag position is translated to be a point
1671     on the contents.
1672 
1673     The default implementation does nothing. The \a event parameter is
1674     ignored.
1675 */
contentsDragLeaveEvent(QDragLeaveEvent *)1676 void KtlQ3ScrollView::contentsDragLeaveEvent(QDragLeaveEvent * /* event */)
1677 {
1678 }
1679 
1680 /*!
1681     This event handler is called whenever the KtlQ3ScrollView receives a
1682     dropEvent(): the drop position is translated to be a point on the
1683     contents.
1684 
1685     The default implementation does nothing. The \a event parameter is
1686     ignored.
1687 */
1688 
contentsDropEvent(QDropEvent *)1689 void KtlQ3ScrollView::contentsDropEvent(QDropEvent * /* event */)
1690 {
1691 }
1692 
1693 #endif // QT_NO_DRAGANDDROP
1694 
1695 /*!
1696     This event handler is called whenever the KtlQ3ScrollView receives a
1697     wheelEvent() in \a{e}: the mouse position is translated to be a
1698     point on the contents.
1699 */
1700 #ifndef QT_NO_WHEELEVENT
contentsWheelEvent(QWheelEvent * e)1701 void KtlQ3ScrollView::contentsWheelEvent(QWheelEvent * e)
1702 {
1703     e->ignore();
1704 }
1705 #endif
1706 /*!
1707     This event handler is called whenever the KtlQ3ScrollView receives a
1708     contextMenuEvent() in \a{e}: the mouse position is translated to
1709     be a point on the contents.
1710 */
contentsContextMenuEvent(QContextMenuEvent * e)1711 void KtlQ3ScrollView::contentsContextMenuEvent(QContextMenuEvent *e)
1712 {
1713     e->ignore();
1714 }
1715 
1716 /*!
1717     This is a low-level painting routine that draws the viewport
1718     contents. Reimplement this if drawContents() is too high-level
1719     (for example, if you don't want to open a QPainter on the
1720     viewport). The paint event is passed in \a pe.
1721 */
viewportPaintEvent(QPaintEvent * pe)1722 void KtlQ3ScrollView::viewportPaintEvent(QPaintEvent* pe)
1723 {
1724     QWidget* vp = viewport();
1725 
1726     QPainter p(vp);
1727     QRect r = pe->rect();
1728 
1729     if (d->clipped_viewport) {
1730         QRect rr(
1731             -d->clipped_viewport->x(), -d->clipped_viewport->y(),
1732             d->viewport->width(), d->viewport->height()
1733            );
1734         r &= rr;
1735         if (r.isValid()) {
1736             int ex = r.x() + d->clipped_viewport->x() + d->contentsX();
1737             int ey = r.y() + d->clipped_viewport->y() + d->contentsY();
1738             int ew = r.width();
1739             int eh = r.height();
1740             drawContentsOffset(&p,
1741                 d->contentsX()+d->clipped_viewport->x(),
1742                 d->contentsY()+d->clipped_viewport->y(),
1743                 ex, ey, ew, eh);
1744         }
1745     } else {
1746         r &= d->viewport->rect();
1747         int ex = r.x() + d->contentsX();
1748         int ey = r.y() + d->contentsY();
1749         int ew = r.width();
1750         int eh = r.height();
1751         drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh);
1752     }
1753 }
1754 
1755 
1756 /*!
1757     To provide simple processing of events on the contents, this
1758     function receives all resize events sent to the viewport.
1759 
1760     The default implementation does nothing. The \a event parameter is
1761     ignored.
1762 
1763     \sa QWidget::resizeEvent()
1764 */
viewportResizeEvent(QResizeEvent *)1765 void KtlQ3ScrollView::viewportResizeEvent(QResizeEvent * /* event */)
1766 {
1767 }
1768 
1769 /*! \internal
1770 
1771   To provide simple processing of events on the contents, this
1772   function receives all mouse press events sent to the viewport,
1773   translates the event and calls contentsMousePressEvent().
1774 
1775   \sa contentsMousePressEvent(), QWidget::mousePressEvent()
1776 */
viewportMousePressEvent(QMouseEvent * e)1777 void KtlQ3ScrollView::viewportMousePressEvent(QMouseEvent* e)
1778 {
1779     /* QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1780         e->globalPos(), e->button(), e->state()); - 2018.11.30 */
1781     QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1782         e->globalPos(), e->button(), e->buttons(), e->modifiers());
1783     contentsMousePressEvent(&ce);
1784     if (!ce.isAccepted())
1785         e->ignore();
1786 }
1787 
1788 /*!\internal
1789 
1790   To provide simple processing of events on the contents, this function
1791   receives all mouse release events sent to the viewport, translates
1792   the event and calls contentsMouseReleaseEvent().
1793 
1794   \sa QWidget::mouseReleaseEvent()
1795 */
viewportMouseReleaseEvent(QMouseEvent * e)1796 void KtlQ3ScrollView::viewportMouseReleaseEvent(QMouseEvent* e)
1797 {
1798     /* QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1799         e->globalPos(), e->button(), e->state()); -- 2018.11.30 */
1800     QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1801         e->globalPos(), e->button(), e->buttons(), e->modifiers());
1802     contentsMouseReleaseEvent(&ce);
1803     if (!ce.isAccepted())
1804         e->ignore();
1805 }
1806 
1807 /*!\internal
1808 
1809   To provide simple processing of events on the contents, this function
1810   receives all mouse double click events sent to the viewport,
1811   translates the event and calls contentsMouseDoubleClickEvent().
1812 
1813   \sa QWidget::mouseDoubleClickEvent()
1814 */
viewportMouseDoubleClickEvent(QMouseEvent * e)1815 void KtlQ3ScrollView::viewportMouseDoubleClickEvent(QMouseEvent* e)
1816 {
1817     /* QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1818         e->globalPos(), e->button(), e->state());  - 2018.11.30 */
1819     QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1820         e->globalPos(), e->button(), e->buttons(), e->modifiers());
1821     contentsMouseDoubleClickEvent(&ce);
1822     if (!ce.isAccepted())
1823         e->ignore();
1824 }
1825 
1826 /*!\internal
1827 
1828   To provide simple processing of events on the contents, this function
1829   receives all mouse move events sent to the viewport, translates the
1830   event and calls contentsMouseMoveEvent().
1831 
1832   \sa QWidget::mouseMoveEvent()
1833 */
viewportMouseMoveEvent(QMouseEvent * e)1834 void KtlQ3ScrollView::viewportMouseMoveEvent(QMouseEvent* e)
1835 {
1836     QMouseEvent ce(e->type(), viewportToContents(e->pos()),
1837         e->globalPos(), e->button(), e->buttons(), e->modifiers());
1838     contentsMouseMoveEvent(&ce);
1839     if (!ce.isAccepted())
1840         e->ignore();
1841 }
1842 
1843 #ifndef QT_NO_DRAGANDDROP
1844 
1845 /*!\internal
1846 
1847   To provide simple processing of events on the contents, this function
1848   receives all drag enter events sent to the viewport, translates the
1849   event and calls contentsDragEnterEvent().
1850 
1851   \sa QWidget::dragEnterEvent()
1852 */
viewportDragEnterEvent(QDragEnterEvent * e)1853 void KtlQ3ScrollView::viewportDragEnterEvent(QDragEnterEvent* e)
1854 {
1855     //e->setPoint(viewportToContents(e->pos())); // 2018.11.30
1856     QDragEnterEvent ev(viewportToContents(e->pos()), e->possibleActions(),
1857                        e->mimeData(), e->mouseButtons(), e->keyboardModifiers());
1858     contentsDragEnterEvent(&ev);
1859     //e->setPoint(contentsToViewport(e->pos())); // 2018.11.30
1860 }
1861 
1862 /*!\internal
1863 
1864   To provide simple processing of events on the contents, this function
1865   receives all drag move events sent to the viewport, translates the
1866   event and calls contentsDragMoveEvent().
1867 
1868   \sa QWidget::dragMoveEvent()
1869 */
viewportDragMoveEvent(QDragMoveEvent * e)1870 void KtlQ3ScrollView::viewportDragMoveEvent(QDragMoveEvent* e)
1871 {
1872     //e->setPoint(viewportToContents(e->pos())); // 2018.11.30
1873     QDragMoveEvent ev(viewportToContents(e->pos()), e->possibleActions(),
1874                       e->mimeData(), e->mouseButtons(), e->keyboardModifiers());
1875     contentsDragMoveEvent(&ev);
1876     //e->setPoint(contentsToViewport(e->pos())); // 2018.11.30
1877 }
1878 
1879 /*!\internal
1880 
1881   To provide simple processing of events on the contents, this function
1882   receives all drag leave events sent to the viewport and calls
1883   contentsDragLeaveEvent().
1884 
1885   \sa QWidget::dragLeaveEvent()
1886 */
viewportDragLeaveEvent(QDragLeaveEvent * e)1887 void KtlQ3ScrollView::viewportDragLeaveEvent(QDragLeaveEvent* e)
1888 {
1889     contentsDragLeaveEvent(e);
1890 }
1891 
1892 /*!\internal
1893 
1894   To provide simple processing of events on the contents, this function
1895   receives all drop events sent to the viewport, translates the event
1896   and calls contentsDropEvent().
1897 
1898   \sa QWidget::dropEvent()
1899 */
viewportDropEvent(QDropEvent * e)1900 void KtlQ3ScrollView::viewportDropEvent(QDropEvent* e)
1901 {
1902     //e->setPoint(viewportToContents(e->pos())); // 2018.11.30
1903     QDropEvent ev(viewportToContents(e->pos()), e->possibleActions(),
1904                     e->mimeData(), e->mouseButtons(), e->keyboardModifiers());
1905     contentsDropEvent(&ev);
1906     //e->setPoint(contentsToViewport(e->pos())); // 2018.11.30
1907 }
1908 
1909 #endif // QT_NO_DRAGANDDROP
1910 
1911 /*!\internal
1912 
1913   To provide simple processing of events on the contents, this function
1914   receives all wheel events sent to the viewport, translates the
1915   event and calls contentsWheelEvent().
1916 
1917   \sa QWidget::wheelEvent()
1918 */
1919 #ifndef QT_NO_WHEELEVENT
viewportWheelEvent(QWheelEvent * e)1920 void KtlQ3ScrollView::viewportWheelEvent(QWheelEvent* e)
1921 {
1922     /*
1923        Different than standard mouse events, because wheel events might
1924        be sent to the focus widget if the widget-under-mouse doesn't want
1925        the event itself.
1926     */
1927     /* QWheelEvent ce(viewportToContents(e->pos()),
1928         e->globalPos(), e->delta(), e->state()); */
1929     QWheelEvent ce(viewportToContents(e->pos()),
1930         e->globalPos(), e->delta(), e->buttons(), e->modifiers());
1931     contentsWheelEvent(&ce);
1932     if (ce.isAccepted())
1933         e->accept();
1934     else
1935         e->ignore();
1936 }
1937 #endif
1938 
1939 /*! \internal
1940 
1941   To provide simple processing of events on the contents, this function
1942   receives all context menu events sent to the viewport, translates the
1943   event and calls contentsContextMenuEvent().
1944 */
viewportContextMenuEvent(QContextMenuEvent * e)1945 void KtlQ3ScrollView::viewportContextMenuEvent(QContextMenuEvent *e)
1946 {
1947     //QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state());
1948     QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->modifiers());
1949     contentsContextMenuEvent(&ce);
1950     if (ce.isAccepted())
1951         e->accept();
1952     else
1953         e->ignore();
1954 }
1955 
1956 /*!
1957     Returns the component horizontal scroll bar. It is made available
1958     to allow accelerators, autoscrolling, etc.
1959 
1960     It should not be used for other purposes.
1961 
1962     This function never returns 0.
1963 */
horizontalScrollBar() const1964 QScrollBar* KtlQ3ScrollView::horizontalScrollBar() const
1965 {
1966     return d->hbar;
1967 }
1968 
1969 /*!
1970     Returns the component vertical scroll bar. It is made available to
1971     allow accelerators, autoscrolling, etc.
1972 
1973     It should not be used for other purposes.
1974 
1975     This function never returns 0.
1976 */
verticalScrollBar() const1977 QScrollBar* KtlQ3ScrollView::verticalScrollBar() const {
1978     return d->vbar;
1979 }
1980 
1981 
1982 /*!
1983     Scrolls the content so that the point (\a x, \a y) is visible with at
1984     least 50-pixel margins (if possible, otherwise centered).
1985 */
ensureVisible(int x,int y)1986 void KtlQ3ScrollView::ensureVisible(int x, int y)
1987 {
1988     ensureVisible(x, y, 50, 50);
1989 }
1990 
1991 /*!
1992     \overload
1993 
1994     Scrolls the content so that the point (\a x, \a y) is visible with at
1995     least the \a xmargin and \a ymargin margins (if possible,
1996     otherwise centered).
1997 */
ensureVisible(int x,int y,int xmargin,int ymargin)1998 void KtlQ3ScrollView::ensureVisible(int x, int y, int xmargin, int ymargin)
1999 {
2000     int pw=visibleWidth();
2001     int ph=visibleHeight();
2002 
2003     int cx=-d->contentsX();
2004     int cy=-d->contentsY();
2005     int cw=d->contentsWidth();
2006     int ch=contentsHeight();
2007 
2008     if (pw < xmargin*2)
2009         xmargin=pw/2;
2010     if (ph < ymargin*2)
2011         ymargin=ph/2;
2012 
2013     if (cw <= pw) {
2014         xmargin=0;
2015         cx=0;
2016     }
2017     if (ch <= ph) {
2018         ymargin=0;
2019         cy=0;
2020     }
2021 
2022     if (x < -cx+xmargin)
2023         cx = -x+xmargin;
2024     else if (x >= -cx+pw-xmargin)
2025         cx = -x+pw-xmargin;
2026 
2027     if (y < -cy+ymargin)
2028         cy = -y+ymargin;
2029     else if (y >= -cy+ph-ymargin)
2030         cy = -y+ph-ymargin;
2031 
2032     if (cx > 0)
2033         cx=0;
2034     else if (cx < pw-cw && cw>pw)
2035         cx=pw-cw;
2036 
2037     if (cy > 0)
2038         cy=0;
2039     else if (cy < ph-ch && ch>ph)
2040         cy=ph-ch;
2041 
2042     setContentsPos(-cx, -cy);
2043 }
2044 
2045 /*!
2046     Scrolls the content so that the point (\a x, \a y) is in the top-left
2047     corner.
2048 */
setContentsPos(int x,int y)2049 void KtlQ3ScrollView::setContentsPos(int x, int y)
2050 {
2051 #if 0
2052     // bounds checking...
2053     if (QApplication::reverseLayout())
2054         if (x > d->contentsWidth() - visibleWidth()) x = d->contentsWidth() - visibleWidth();
2055     else
2056 #endif
2057         if (x < 0) x = 0;
2058     if (y < 0) y = 0;
2059     // Choke signal handling while we update BOTH sliders.
2060     d->signal_choke=true;
2061     moveContents(-x, -y);
2062     d->vbar->setValue(y);
2063     d->hbar->setValue(x);
2064     d->signal_choke=false;
2065 }
2066 
2067 /*!
2068     Scrolls the content by \a dx to the left and \a dy upwards.
2069 */
scrollBy(int dx,int dy)2070 void KtlQ3ScrollView::scrollBy(int dx, int dy)
2071 {
2072     setContentsPos(qMax(d->contentsX()+dx, 0), qMax(d->contentsY()+dy, 0));
2073 }
2074 
2075 /*!
2076     Scrolls the content so that the point (\a x, \a y) is in the center
2077     of visible area.
2078 */
center(int x,int y)2079 void KtlQ3ScrollView::center(int x, int y)
2080 {
2081     ensureVisible(x, y, 32000, 32000);
2082 }
2083 
2084 /*!
2085     \overload
2086 
2087     Scrolls the content so that the point (\a x, \a y) is visible with
2088     the \a xmargin and \a ymargin margins (as fractions of visible
2089     the area).
2090 
2091     For example:
2092     \list
2093     \i Margin 0.0 allows (x, y) to be on the edge of the visible area.
2094     \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area.
2095     \i Margin 1.0 ensures that (x, y) is in the center of the visible area.
2096     \endlist
2097 */
center(int x,int y,float xmargin,float ymargin)2098 void KtlQ3ScrollView::center(int x, int y, float xmargin, float ymargin)
2099 {
2100     int pw=visibleWidth();
2101     int ph=visibleHeight();
2102     ensureVisible(x, y, int(xmargin/2.0*pw+0.5), int(ymargin/2.0*ph+0.5));
2103 }
2104 
2105 
2106 /*!
2107     \fn void KtlQ3ScrollView::contentsMoving(int x, int y)
2108 
2109     This signal is emitted just before the contents are moved to
2110     position (\a x, \a y).
2111 
2112     \sa contentsX(), contentsY()
2113 */
2114 
2115 /*!
2116     Moves the contents by (\a x, \a y).
2117 */
moveContents(int x,int y)2118 void KtlQ3ScrollView::moveContents(int x, int y)
2119 {
2120     if (-x+visibleWidth() > d->contentsWidth())
2121 #if 0
2122         if(QApplication::reverseLayout())
2123             x=qMax(0,-d->contentsWidth()+visibleWidth());
2124         else
2125 #endif
2126             x=qMin(0,-d->contentsWidth()+visibleWidth());
2127     if (-y+visibleHeight() > contentsHeight())
2128         y=qMin(0,-contentsHeight()+visibleHeight());
2129 
2130     int dx = x - d->vx;
2131     int dy = y - d->vy;
2132 
2133     if (!dx && !dy)
2134         return; // Nothing to do
2135 
2136     emit contentsMoving(-x, -y);
2137 
2138     d->vx = x;
2139     d->vy = y;
2140 
2141     if (d->clipped_viewport || d->static_bg) {
2142         // Cheap move (usually)
2143         d->moveAllBy(dx,dy);
2144     } else if (/*dx && dy ||*/
2145          (qAbs(dy) * 5 > visibleHeight() * 4) ||
2146          (qAbs(dx) * 5 > visibleWidth() * 4)
2147        )
2148     {
2149         // Big move
2150         if (viewport()->updatesEnabled())
2151             viewport()->update();
2152         d->moveAllBy(dx,dy);
2153     } else if (!d->fake_scroll || d->contentsWidth() > visibleWidth()) {
2154         // Small move
2155         clipper()->scroll(dx,dy);
2156     }
2157     d->hideOrShowAll(this, true);
2158 }
2159 
2160 /*!
2161     \property KtlQ3ScrollView::contentsX
2162     \brief the X coordinate of the contents that are at the left edge of
2163     the viewport.
2164 */
contentsX() const2165 int KtlQ3ScrollView::contentsX() const
2166 {
2167     return d->contentsX();
2168 }
2169 
2170 /*!
2171     \property KtlQ3ScrollView::contentsY
2172     \brief the Y coordinate of the contents that are at the top edge of
2173     the viewport.
2174 */
contentsY() const2175 int KtlQ3ScrollView::contentsY() const
2176 {
2177     return d->contentsY();
2178 }
2179 
2180 /*!
2181     \property KtlQ3ScrollView::contentsWidth
2182     \brief the width of the contents area
2183 */
contentsWidth() const2184 int KtlQ3ScrollView::contentsWidth() const
2185 {
2186     return d->contentsWidth();
2187 }
2188 
2189 /*!
2190     \property KtlQ3ScrollView::contentsHeight
2191     \brief the height of the contents area
2192 */
contentsHeight() const2193 int KtlQ3ScrollView::contentsHeight() const
2194 {
2195     return d->vheight;
2196 }
2197 
2198 /*!
2199     Sets the size of the contents area to \a w pixels wide and \a h
2200     pixels high and updates the viewport accordingly.
2201 */
resizeContents(int w,int h)2202 void KtlQ3ScrollView::resizeContents(int w, int h)
2203 {
2204     int ow = d->vwidth;
2205     int oh = d->vheight;
2206     d->vwidth = w;
2207     d->vheight = h;
2208 
2209     d->scrollbar_timer.setSingleShot(true);
2210     d->scrollbar_timer.start(0 /*, true */ );
2211 
2212     if (d->children.isEmpty() && d->policy == Default)
2213         setResizePolicy(Manual);
2214 
2215     if (ow > w) {
2216         // Swap
2217         int t=w;
2218         w=ow;
2219         ow=t;
2220     }
2221     // Refresh area ow..w
2222     if (ow < visibleWidth() && w >= 0) {
2223         if (ow < 0)
2224             ow = 0;
2225         if (w > visibleWidth())
2226             w = visibleWidth();
2227         clipper()->update(d->contentsX()+ow, 0, w-ow, visibleHeight());
2228     }
2229 
2230     if (oh > h) {
2231         // Swap
2232         int t=h;
2233         h=oh;
2234         oh=t;
2235     }
2236     // Refresh area oh..h
2237     if (oh < visibleHeight() && h >= 0) {
2238         if (oh < 0)
2239             oh = 0;
2240         if (h > visibleHeight())
2241             h = visibleHeight();
2242         clipper()->update(0, d->contentsY()+oh, visibleWidth(), h-oh);
2243     }
2244 }
2245 
2246 /*!
2247     Calls update() on a rectangle defined by \a x, \a y, \a w, \a h,
2248     translated appropriately. If the rectangle is not visible, nothing
2249     is repainted.
2250 
2251     \sa repaintContents()
2252 */
updateContents(int x,int y,int w,int h)2253 void KtlQ3ScrollView::updateContents(int x, int y, int w, int h)
2254 {
2255     if (!isVisible() || !updatesEnabled())
2256         return;
2257 
2258     QWidget* vp = viewport();
2259 
2260     // Translate
2261     x -= d->contentsX();
2262     y -= d->contentsY();
2263 
2264     if (x < 0) {
2265         w += x;
2266         x = 0;
2267     }
2268     if (y < 0) {
2269         h += y;
2270         y = 0;
2271     }
2272 
2273     if (w < 0 || h < 0)
2274         return;
2275     if (x > visibleWidth() || y > visibleHeight())
2276         return;
2277 
2278     if (w > visibleWidth())
2279         w = visibleWidth();
2280     if (h > visibleHeight())
2281         h = visibleHeight();
2282 
2283     if (d->clipped_viewport) {
2284         // Translate clipper() to viewport()
2285         x -= d->clipped_viewport->x();
2286         y -= d->clipped_viewport->y();
2287     }
2288 
2289     vp->update(x, y, w, h);
2290 }
2291 
2292 /*!
2293     \overload
2294 
2295     Updates the contents in rectangle \a r
2296 */
updateContents(const QRect & r)2297 void KtlQ3ScrollView::updateContents(const QRect& r)
2298 {
2299     updateContents(r.x(), r.y(), r.width(), r.height());
2300 }
2301 
2302 /*!
2303     \overload
2304 */
updateContents()2305 void KtlQ3ScrollView::updateContents()
2306 {
2307     updateContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight());
2308 }
2309 
2310 /*!
2311     \overload
2312 
2313     Repaints the contents of rectangle \a r. If \a erase is true the
2314     background is cleared using the background color.
2315 */
repaintContents(const QRect & r,bool erase)2316 void KtlQ3ScrollView::repaintContents(const QRect& r, bool erase)
2317 {
2318     repaintContents(r.x(), r.y(), r.width(), r.height(), erase);
2319 }
2320 
2321 
2322 /*!
2323     \overload
2324 
2325     Repaints the contents. If \a erase is true the background is
2326     cleared using the background color.
2327 */
repaintContents(bool erase)2328 void KtlQ3ScrollView::repaintContents(bool erase)
2329 {
2330     repaintContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase);
2331 }
2332 
2333 
2334 /*!
2335     Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h,
2336     translated appropriately. If the rectangle is not visible, nothing
2337     is repainted. If \a erase is true the background is cleared using
2338     the background color.
2339 
2340     \sa updateContents()
2341 */
repaintContents(int x,int y,int w,int h,bool)2342 void KtlQ3ScrollView::repaintContents(int x, int y, int w, int h, bool /*erase*/)
2343 {
2344     if (!isVisible() || !updatesEnabled())
2345         return;
2346 
2347     QWidget* vp = viewport();
2348 
2349     // Translate logical to clipper()
2350     x -= d->contentsX();
2351     y -= d->contentsY();
2352 
2353     if (x < 0) {
2354         w += x;
2355         x = 0;
2356     }
2357     if (y < 0) {
2358         h += y;
2359         y = 0;
2360     }
2361 
2362     if (w < 0 || h < 0)
2363         return;
2364     if (w > visibleWidth())
2365         w = visibleWidth();
2366     if (h > visibleHeight())
2367         h = visibleHeight();
2368 
2369     if (d->clipped_viewport) {
2370         // Translate clipper() to viewport()
2371         x -= d->clipped_viewport->x();
2372         y -= d->clipped_viewport->y();
2373     }
2374 
2375     vp->update(x, y, w, h);
2376 }
2377 
2378 
2379 /*!
2380     For backward-compatibility only. It is easier to use
2381     drawContents(QPainter*,int,int,int,int).
2382 
2383     The default implementation translates the painter appropriately
2384     and calls drawContents(QPainter*,int,int,int,int). See
2385     drawContents() for an explanation of the parameters \a p, \a
2386     offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph.
2387 */
drawContentsOffset(QPainter * p,int offsetx,int offsety,int clipx,int clipy,int clipw,int cliph)2388 void KtlQ3ScrollView::drawContentsOffset(QPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph)
2389 {
2390     p->translate(-offsetx,-offsety);
2391     drawContents(p, clipx, clipy, clipw, cliph);
2392 }
2393 
2394 /*!
2395     \fn void KtlQ3ScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph)
2396 
2397     Reimplement this function if you are viewing a drawing area rather
2398     than a widget.
2399 
2400     The function should draw the rectangle (\a clipx, \a clipy, \a
2401     clipw, \a cliph) of the contents using painter \a p. The clip
2402     rectangle is in the scrollview's coordinates.
2403 
2404     For example:
2405     \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 4
2406 
2407     The clip rectangle and translation of the painter \a p is already
2408     set appropriately.
2409 */
drawContents(QPainter *,int,int,int,int)2410 void KtlQ3ScrollView::drawContents(QPainter*, int, int, int, int)
2411 {
2412 }
2413 
2414 
2415 /*!
2416     \reimp
2417 */
frameChanged()2418 void KtlQ3ScrollView::frameChanged()
2419 {
2420 //     // slight ugle-hack - the listview header needs readjusting when
2421 //     // changing the frame
2422 //     if (Q3ListView *lv = qobject_cast<Q3ListView *>(this))
2423 //         lv->triggerUpdate();
2424     KtlQ3Frame::frameChanged();
2425     updateScrollBars();
2426 }
2427 
2428 
2429 /*!
2430     Returns the viewport widget of the scrollview. This is the widget
2431     containing the contents widget or which is the drawing area.
2432 */
viewport() const2433 QWidget* KtlQ3ScrollView::viewport() const
2434 {
2435     if (d->clipped_viewport)
2436         return  d->clipped_viewport;
2437     return d->viewport;
2438 }
2439 
2440 /*!
2441     Returns the clipper widget. Contents in the scrollview are
2442     ultimately clipped to be inside the clipper widget.
2443 
2444     You should not need to use this function.
2445 
2446     \sa visibleWidth(), visibleHeight()
2447 */
clipper() const2448 QWidget* KtlQ3ScrollView::clipper() const
2449 {
2450     return d->viewport;
2451 }
2452 
2453 /*!
2454     \property KtlQ3ScrollView::visibleWidth
2455     \brief the horizontal amount of the content that is visible
2456 */
visibleWidth() const2457 int KtlQ3ScrollView::visibleWidth() const
2458 {
2459     return clipper()->width();
2460 }
2461 
2462 /*!
2463     \property KtlQ3ScrollView::visibleHeight
2464     \brief the vertical amount of the content that is visible
2465 */
visibleHeight() const2466 int KtlQ3ScrollView::visibleHeight() const
2467 {
2468     return clipper()->height();
2469 }
2470 
2471 
changeFrameRect(const QRect & r)2472 void KtlQ3ScrollView::changeFrameRect(const QRect& r)
2473 {
2474     QRect oldr = frameRect();
2475     if (oldr != r) {
2476         QRect cr = contentsRect();
2477         QRegion fr(frameRect());
2478         fr = fr.subtracted(contentsRect());
2479         setFrameRect(r);
2480         if (isVisible()) {
2481             cr = cr.intersected(contentsRect());
2482             fr = fr.united(frameRect());
2483             fr = fr.subtracted(cr);
2484             if (!fr.isEmpty())
2485                 update(fr);
2486         }
2487     }
2488 }
2489 
2490 
2491 /*!
2492     Sets the margins around the scrolling area to \a left, \a top, \a
2493     right and \a bottom. This is useful for applications such as
2494     spreadsheets with "locked" rows and columns. The marginal space is
2495     \e inside the frameRect() and is left blank; reimplement
2496     drawFrame() or put widgets in the unused area.
2497 
2498     By default all margins are zero.
2499 
2500     \sa frameChanged()
2501 */
setMargins(int left,int top,int right,int bottom)2502 void KtlQ3ScrollView::setMargins(int left, int top, int right, int bottom)
2503 {
2504     if (left == d->l_marg &&
2505          top == d->t_marg &&
2506          right == d->r_marg &&
2507          bottom == d->b_marg)
2508         return;
2509 
2510     d->l_marg = left;
2511     d->t_marg = top;
2512     d->r_marg = right;
2513     d->b_marg = bottom;
2514     updateScrollBars();
2515 }
2516 
2517 
2518 /*!
2519     Returns the left margin.
2520 
2521     \sa setMargins()
2522 */
leftMargin() const2523 int KtlQ3ScrollView::leftMargin() const
2524 {
2525     return d->l_marg;
2526 }
2527 
2528 
2529 /*!
2530     Returns the top margin.
2531 
2532     \sa setMargins()
2533 */
topMargin() const2534 int KtlQ3ScrollView::topMargin() const
2535 {
2536     return d->t_marg;
2537 }
2538 
2539 
2540 /*!
2541     Returns the right margin.
2542 
2543     \sa setMargins()
2544 */
rightMargin() const2545 int KtlQ3ScrollView::rightMargin() const
2546 {
2547     return d->r_marg;
2548 }
2549 
2550 
2551 /*!
2552     Returns the bottom margin.
2553 
2554     \sa setMargins()
2555 */
bottomMargin() const2556 int KtlQ3ScrollView::bottomMargin() const
2557 {
2558     return d->b_marg;
2559 }
2560 
2561 /*!
2562     \reimp
2563 */
focusNextPrevChild(bool next)2564 bool KtlQ3ScrollView::focusNextPrevChild(bool next)
2565 {
2566     //  Makes sure that the new focus widget is on-screen, if
2567     //  necessary by scrolling the scroll view.
2568     bool retval = KtlQ3Frame::focusNextPrevChild(next);
2569     if (retval) {
2570         QWidget *w = window()->focusWidget();
2571         if (isAncestorOf(w)) {
2572             QSVChildRec *r = d->ancestorRec(w);
2573            if (r && (r->child == w || w->isVisibleTo(r->child))) {
2574                 QPoint cp = r->child->mapToGlobal(QPoint(0, 0));
2575                 QPoint cr = w->mapToGlobal(QPoint(0, 0)) - cp;
2576                 ensureVisible(r->x + cr.x() + w->width()/2, r->y + cr.y() + w->height()/2,
2577                               w->width()/2, w->height()/2);
2578             }
2579         }
2580     }
2581     return retval;
2582 }
2583 
2584 
2585 
2586 /*!
2587     When a large numbers of child widgets are in a scrollview,
2588     especially if they are close together, the scrolling performance
2589     can suffer greatly. If \a y is true the scrollview will use an
2590     extra widget to group child widgets.
2591 
2592     Note that you may only call enableClipper() prior to adding
2593     widgets.
2594 */
enableClipper(bool y)2595 void KtlQ3ScrollView::enableClipper(bool y)        // note: this method as of 2018.11.30 is unused
2596 {
2597     if (!d->clipped_viewport == !y)
2598         return;
2599     if (d->children.count())
2600         qFatal("May only call KtlQ3ScrollView::enableClipper() before adding widgets");
2601     if (y) {
2602         d->clipped_viewport = new KtlQClipperWidget(clipper(), "qt_clipped_viewport", QFlag(d->flags));
2603         d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2,
2604                                          coord_limit,coord_limit);
2605         //d->clipped_viewport->setBackgroundMode(d->viewport->backgroundMode());
2606         d->clipped_viewport->setBackgroundRole(d->viewport->backgroundRole());
2607         //d->viewport->setBackgroundMode(NoBackground); // no exposures for this // 2018.11.30
2608         d->viewport->setAttribute(Qt::WA_NoSystemBackground); // hope this is the correct replacement for above
2609         d->viewport->removeEventFilter(this);
2610         d->clipped_viewport->installEventFilter(this);
2611         d->clipped_viewport->show();
2612     } else {
2613         delete d->clipped_viewport;
2614         d->clipped_viewport = nullptr;
2615     }
2616 }
2617 
2618 /*!
2619     Sets the scrollview to have a static background if \a y is true,
2620     or a scrolling background if \a y is false. By default, the
2621     background is scrolling.
2622 
2623     Be aware that this mode is quite slow, as a full repaint of the
2624     visible area has to be triggered on every contents move.
2625 
2626     \sa hasStaticBackground()
2627 */
setStaticBackground(bool y)2628 void  KtlQ3ScrollView::setStaticBackground(bool y)
2629 {
2630     d->static_bg = y;
2631 }
2632 
2633 /*!
2634     Returns true if KtlQ3ScrollView uses a static background; otherwise
2635     returns false.
2636 
2637     \sa setStaticBackground()
2638 */
hasStaticBackground() const2639 bool KtlQ3ScrollView::hasStaticBackground() const
2640 {
2641     return d->static_bg;
2642 }
2643 
2644 /*!
2645     \overload
2646 
2647     Returns the point \a p translated to a point on the viewport()
2648     widget.
2649 */
contentsToViewport(const QPoint & p) const2650 QPoint KtlQ3ScrollView::contentsToViewport(const QPoint& p) const
2651 {
2652     if (d->clipped_viewport) {
2653         return QPoint(p.x() - d->contentsX() - d->clipped_viewport->x(),
2654                        p.y() - d->contentsY() - d->clipped_viewport->y());
2655     } else {
2656         return QPoint(p.x() - d->contentsX(),
2657                        p.y() - d->contentsY());
2658     }
2659 }
2660 
2661 /*!
2662     \overload
2663 
2664     Returns the point on the viewport \a vp translated to a point in
2665     the contents.
2666 */
viewportToContents(const QPoint & vp) const2667 QPoint KtlQ3ScrollView::viewportToContents(const QPoint& vp) const
2668 {
2669     if (d->clipped_viewport) {
2670         return QPoint(vp.x() + d->contentsX() + d->clipped_viewport->x(),
2671                        vp.y() + d->contentsY() + d->clipped_viewport->y());
2672     } else {
2673         return QPoint(vp.x() + d->contentsX(),
2674                        vp.y() + d->contentsY());
2675     }
2676 }
2677 
2678 
2679 /*!
2680     Translates a point (\a x, \a y) in the contents to a point (\a vx,
2681     \a vy) on the viewport() widget.
2682 */
contentsToViewport(int x,int y,int & vx,int & vy) const2683 void KtlQ3ScrollView::contentsToViewport(int x, int y, int& vx, int& vy) const
2684 {
2685     const QPoint v = contentsToViewport(QPoint(x,y));
2686     vx = v.x();
2687     vy = v.y();
2688 }
2689 
2690 /*!
2691     Translates a point (\a vx, \a vy) on the viewport() widget to a
2692     point (\a x, \a y) in the contents.
2693 */
viewportToContents(int vx,int vy,int & x,int & y) const2694 void KtlQ3ScrollView::viewportToContents(int vx, int vy, int& x, int& y) const
2695 {
2696     const QPoint c = viewportToContents(QPoint(vx,vy));
2697     x = c.x();
2698     y = c.y();
2699 }
2700 
2701 /*!
2702     \reimp
2703 */
sizeHint() const2704 QSize KtlQ3ScrollView::sizeHint() const
2705 {
2706     if (d->use_cached_size_hint && d->cachedSizeHint.isValid())
2707         return d->cachedSizeHint;
2708 
2709     //constPolish(); // 2018.11.30
2710     ensurePolished();
2711     int f = 2 * frameWidth();
2712     int h = fontMetrics().height();
2713     QSize sz(f, f);
2714     if (d->policy > Manual) {
2715         QSVChildRec *r = d->children.first();
2716         if (r) {
2717             QSize cs = r->child->sizeHint();
2718             if (cs.isValid())
2719                 sz += cs.boundedTo(r->child->maximumSize());
2720             else
2721                 sz += r->child->size();
2722         }
2723     } else {
2724         sz += QSize(d->contentsWidth(), contentsHeight());
2725     }
2726     if (d->vMode == AlwaysOn)
2727         sz.setWidth(sz.width() + d->vbar->sizeHint().width());
2728     if (d->hMode == AlwaysOn)
2729         sz.setHeight(sz.height() + d->hbar->sizeHint().height());
2730     return sz.expandedTo(QSize(12 * h, 8 * h))
2731              .boundedTo(QSize(36 * h, 24 * h));
2732 }
2733 
2734 
2735 /*!
2736     \reimp
2737 */
minimumSizeHint() const2738 QSize KtlQ3ScrollView::minimumSizeHint() const
2739 {
2740     int h = fontMetrics().height();
2741     if (h < 10)
2742         h = 10;
2743     int f = 2 * frameWidth();
2744     return QSize((6 * h) + f, (4 * h) + f);
2745 }
2746 
2747 
2748 /*!
2749     \reimp
2750 
2751     (Implemented to get rid of a compiler warning.)
2752 */
drawContents(QPainter *)2753 void KtlQ3ScrollView::drawContents(QPainter *)
2754 {
2755 }
2756 
2757 #ifndef QT_NO_DRAGANDDROP
2758 
2759 /*!
2760   \internal
2761 */
startDragAutoScroll()2762 void KtlQ3ScrollView::startDragAutoScroll()
2763 {
2764     if (!d->autoscroll_timer.isActive()) {
2765         d->autoscroll_time = initialScrollTime;
2766         d->autoscroll_accel = initialScrollAccel;
2767         d->autoscroll_timer.start(d->autoscroll_time);
2768     }
2769 }
2770 
2771 
2772 /*!
2773   \internal
2774 */
stopDragAutoScroll()2775 void KtlQ3ScrollView::stopDragAutoScroll()
2776 {
2777     d->autoscroll_timer.stop();
2778 }
2779 
2780 
2781 /*!
2782   \internal
2783 */
doDragAutoScroll()2784 void KtlQ3ScrollView::doDragAutoScroll()
2785 {
2786     QPoint p = d->viewport->mapFromGlobal(QCursor::pos());
2787 
2788     if (d->autoscroll_accel-- <= 0 && d->autoscroll_time) {
2789         d->autoscroll_accel = initialScrollAccel;
2790         d->autoscroll_time--;
2791         d->autoscroll_timer.start(d->autoscroll_time);
2792     }
2793     int l = qMax(1, (initialScrollTime- d->autoscroll_time));
2794 
2795     int dx = 0, dy = 0;
2796     if (p.y() < autoscroll_margin) {
2797         dy = -l;
2798     } else if (p.y() > visibleHeight() - autoscroll_margin) {
2799         dy = +l;
2800     }
2801     if (p.x() < autoscroll_margin) {
2802         dx = -l;
2803     } else if (p.x() > visibleWidth() - autoscroll_margin) {
2804         dx = +l;
2805     }
2806     if (dx || dy) {
2807         scrollBy(dx,dy);
2808     } else {
2809         stopDragAutoScroll();
2810     }
2811 }
2812 
2813 
2814 /*!
2815     \property KtlQ3ScrollView::dragAutoScroll
2816     \brief whether autoscrolling in drag move events is enabled
2817 
2818     If this property is set to true (the default), the KtlQ3ScrollView
2819     automatically scrolls the contents in drag move events if the user
2820     moves the cursor close to a border of the view. Of course this
2821     works only if the viewport accepts drops. Specifying false
2822     disables this autoscroll feature.
2823 */
2824 
setDragAutoScroll(bool b)2825 void KtlQ3ScrollView::setDragAutoScroll(bool b)
2826 {
2827     d->drag_autoscroll = b;
2828 }
2829 
dragAutoScroll() const2830 bool KtlQ3ScrollView::dragAutoScroll() const
2831 {
2832     return d->drag_autoscroll;
2833 }
2834 
2835 #endif // QT_NO_DRAGANDDROP
2836 
2837 /*!\internal
2838  */
setCachedSizeHint(const QSize & sh) const2839 void KtlQ3ScrollView::setCachedSizeHint(const QSize &sh) const
2840 {
2841     if (isVisible() && !d->cachedSizeHint.isValid())
2842         d->cachedSizeHint = sh;
2843 }
2844 
2845 /*!\internal
2846  */
disableSizeHintCaching()2847 void KtlQ3ScrollView::disableSizeHintCaching()
2848 {
2849     d->use_cached_size_hint = false;
2850 }
2851 
2852 /*!\internal
2853  */
cachedSizeHint() const2854 QSize KtlQ3ScrollView::cachedSizeHint() const
2855 {
2856     return d->use_cached_size_hint ? d->cachedSizeHint : QSize();
2857 }
2858 
2859 // QT_END_NAMESPACE
2860