25 #include <QGraphicsSceneResizeEvent>
26 #include <QGraphicsGridLayout>
27 #include <QGraphicsScene>
28 #include <QApplication>
33 #include <QPropertyAnimation>
34 #include <QSequentialAnimationGroup>
39 #include <kmimetype.h>
41 #include <kglobalsettings.h>
42 #include <kiconloader.h>
43 #include <ktextedit.h>
44 #include <ktextbrowser.h>
75 #define IGNORE_SUSPICIOUS_MOVES 1
92 class ScrollWidgetPrivate
102 ScrollWidgetPrivate(ScrollWidget *parent)
109 overflowBordersVisible(
true),
110 multitouchGesture(GestureNone)
114 ~ScrollWidgetPrivate()
118 void commonConstructor()
120 q->setFocusPolicy(Qt::StrongFocus);
121 q->setFiltersChildEvents(
true);
122 layout =
new QGraphicsGridLayout(q);
123 q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
124 layout->setContentsMargins(0, 0, 0, 0);
126 scrollingWidget->setFlag(QGraphicsItem::ItemHasNoContents);
127 scrollingWidget->installEventFilter(q);
128 layout->addItem(scrollingWidget, 0, 0);
130 borderSvg->setImagePath(
"widgets/scrollwidget");
132 adjustScrollbarsTimer =
new QTimer(q);
133 adjustScrollbarsTimer->setSingleShot(
true);
134 QObject::connect(adjustScrollbarsTimer, SIGNAL(timeout()), q, SLOT(adjustScrollbars()));
136 wheelTimer =
new QTimer(q);
137 wheelTimer->setSingleShot(
true);
139 verticalScrollBarPolicy = Qt::ScrollBarAsNeeded;
141 verticalScrollBar->setFocusPolicy(Qt::NoFocus);
142 layout->addItem(verticalScrollBar, 0, 1);
143 verticalScrollBar->nativeWidget()->setMinimum(0);
144 verticalScrollBar->nativeWidget()->setMaximum(100);
145 QObject::connect(verticalScrollBar, SIGNAL(valueChanged(
int)), q, SLOT(verticalScroll(
int)));
147 horizontalScrollBarPolicy = Qt::ScrollBarAsNeeded;
149 verticalScrollBar->setFocusPolicy(Qt::NoFocus);
151 layout->addItem(horizontalScrollBar, 1, 0);
152 horizontalScrollBar->nativeWidget()->setMinimum(0);
153 horizontalScrollBar->nativeWidget()->setMaximum(100);
154 QObject::connect(horizontalScrollBar, SIGNAL(valueChanged(
int)), q, SLOT(horizontalScroll(
int)));
156 layout->setColumnSpacing(0, 0);
157 layout->setColumnSpacing(1, 0);
158 layout->setRowSpacing(0, 0);
159 layout->setRowSpacing(1, 0);
163 fixupAnimation.groupX = 0;
164 fixupAnimation.startX = 0;
165 fixupAnimation.endX = 0;
166 fixupAnimation.groupY = 0;
167 fixupAnimation.startY = 0;
168 fixupAnimation.endY = 0;
169 fixupAnimation.snapX = 0;
170 fixupAnimation.snapY = 0;
171 directMoveAnimation = 0;
175 alignment = Qt::AlignLeft | Qt::AlignTop;
177 hasContentsProperty =
false;
178 hasOffsetProperty =
false;
179 hasXProperty =
false;
180 hasYProperty =
false;
183 void adjustScrollbars()
189 const bool verticalVisible = widget.data()->size().height() > q->size().height();
190 const bool horizontalVisible = widget.data()->size().width() > q->size().width();
192 verticalScrollBar->nativeWidget()->setMaximum(qMax(0,
int((widget.data()->size().height() - scrollingWidget->size().height())/10)));
193 verticalScrollBar->nativeWidget()->setPageStep(
int(scrollingWidget->size().height())/10);
195 if (verticalScrollBarPolicy == Qt::ScrollBarAlwaysOff ||
197 if (layout->count() > 2 && layout->itemAt(2) == verticalScrollBar) {
199 }
else if (layout->count() > 1 && layout->itemAt(1) == verticalScrollBar) {
202 verticalScrollBar->hide();
203 }
else if (!verticalScrollBar->isVisible()) {
204 layout->addItem(verticalScrollBar, 0, 1);
205 verticalScrollBar->show();
208 horizontalScrollBar->nativeWidget()->setMaximum(qMax(0,
int((widget.data()->size().width() - scrollingWidget->size().width())/10)));
209 horizontalScrollBar->nativeWidget()->setPageStep(
int(scrollingWidget->size().width())/10);
211 if (horizontalScrollBarPolicy == Qt::ScrollBarAlwaysOff ||
212 !horizontalVisible) {
213 if (layout->count() > 2 && layout->itemAt(2) == horizontalScrollBar) {
215 }
else if (layout->count() > 1 && layout->itemAt(1) == horizontalScrollBar) {
218 horizontalScrollBar->hide();
219 }
else if (!horizontalScrollBar->isVisible()) {
220 layout->addItem(horizontalScrollBar, 1, 0);
221 horizontalScrollBar->show();
224 if (widget && !topBorder && verticalVisible) {
226 topBorder->setSvg(borderSvg);
227 topBorder->setElementID(
"border-top");
228 topBorder->setZValue(900);
229 topBorder->resize(topBorder->effectiveSizeHint(Qt::PreferredSize));
230 topBorder->setVisible(overflowBordersVisible);
233 bottomBorder->setSvg(borderSvg);
234 bottomBorder->setElementID(
"border-bottom");
235 bottomBorder->setZValue(900);
236 bottomBorder->resize(bottomBorder->effectiveSizeHint(Qt::PreferredSize));
237 bottomBorder->setVisible(overflowBordersVisible);
238 }
else if (topBorder && widget && !verticalVisible) {
241 bottomBorder->hide();
242 topBorder->deleteLater();
243 bottomBorder->deleteLater();
249 if (widget && !leftBorder && horizontalVisible) {
251 leftBorder->setSvg(borderSvg);
252 leftBorder->setElementID(
"border-left");
253 leftBorder->setZValue(900);
254 leftBorder->resize(leftBorder->effectiveSizeHint(Qt::PreferredSize));
255 leftBorder->setVisible(overflowBordersVisible);
258 rightBorder->setSvg(borderSvg);
259 rightBorder->setElementID(
"border-right");
260 rightBorder->setZValue(900);
261 rightBorder->resize(rightBorder->effectiveSizeHint(Qt::PreferredSize));
262 rightBorder->setVisible(overflowBordersVisible);
263 }
else if (leftBorder && widget && !horizontalVisible) {
266 leftBorder->deleteLater();
267 rightBorder->deleteLater();
275 topBorder->resize(q->size().width(), topBorder->size().height());
276 bottomBorder->resize(q->size().width(), bottomBorder->size().height());
277 bottomBorder->setPos(0, q->size().height() - topBorder->size().height());
280 leftBorder->resize(leftBorder->size().width(), q->size().height());
281 rightBorder->resize(rightBorder->size().width(), q->size().height());
282 rightBorder->setPos(q->size().width() - rightBorder->size().width(), 0);
285 QSizeF widgetSize = widget.data()->size();
286 if (widget.data()->sizePolicy().expandingDirections() &
Qt::Horizontal) {
288 widgetSize.setWidth(scrollingWidget->size().width());
290 if (widget.data()->sizePolicy().expandingDirections() &
Qt::Vertical) {
291 widgetSize.setHeight(scrollingWidget->size().height());
293 widget.data()->resize(widgetSize);
298 void verticalScroll(
int value)
305 widget.data()->setPos(QPoint(widget.data()->pos().x(), -value*10));
309 void horizontalScroll(
int value)
316 widget.data()->setPos(QPoint(-value*10, widget.data()->pos().y()));
320 void adjustClipping()
326 const bool clip = widget.data()->size().width() > scrollingWidget->size().width() || widget.data()->size().height() > scrollingWidget->size().height();
328 scrollingWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, clip);
331 qreal overShootDistance(qreal velocity, qreal size)
const
336 velocity = qAbs(velocity);
343 void animateMoveTo(
const QPointF &pos)
345 qreal duration = 800;
346 QPointF start = q->scrollPosition();
347 QSizeF threshold = q->viewportGeometry().size();
348 QPointF diff = pos - start;
351 if (qAbs(diff.x()) < threshold.width() ||
352 qAbs(diff.y()) < threshold.height())
355 fixupAnimation.groupX->stop();
356 fixupAnimation.groupY->stop();
357 fixupAnimation.snapX->stop();
358 fixupAnimation.snapY->stop();
360 directMoveAnimation->setStartValue(start);
361 directMoveAnimation->setEndValue(pos);
362 directMoveAnimation->setDuration(duration);
363 directMoveAnimation->start();
366 void flick(QPropertyAnimation *anim,
373 qreal deceleration = 500;
374 qreal maxDistance = -1;
379 maxDistance = qAbs(minExtent - val + (hasOvershoot?overShootDistance(velocity,size):0));
381 deceleration = -deceleration;
384 maxDistance = qAbs(maxExtent - val) + (hasOvershoot?overShootDistance(velocity,size):0);
387 if (maxDistance > 0) {
395 qreal duration = qAbs(v / deceleration);
396 qreal diffY = v * duration + (0.5 * deceleration * duration * duration);
399 qreal endY = startY + diffY;
403 endY = startY + maxDistance;
406 endY = startY - maxDistance;
408 duration = qAbs((endY-startY)/ (-v/2));
417 qDebug()<<
"XXX velocity = "<<v <<
", target = "<< target
418 <<
", maxDist = "<<maxDistance;
419 qDebug()<<
"duration = "<<duration<<
" secs, ("
420 << (duration * 1000) <<
" msecs)";
421 qDebug()<<
"startY = "<<startY;
422 qDebug()<<
"endY = "<<endY;
423 qDebug()<<
"overshoot = "<<overShootDistance(v, size);
424 qDebug()<<
"avg velocity = "<< ((endY-startY)/duration);
427 anim->setStartValue(startY);
428 anim->setEndValue(endY);
429 anim->setDuration(duration * 1000);
432 if (anim == flickAnimationX)
438 void flickX(qreal velocity)
440 flick(flickAnimationX, velocity, widgetX(), minXExtent(), maxXExtent(),
441 q->viewportGeometry().width());
443 void flickY(qreal velocity)
445 flick(flickAnimationY, velocity, widgetY(),minYExtent(), maxYExtent(),
446 q->viewportGeometry().height());
448 void fixup(QAnimationGroup *group,
449 QPropertyAnimation *start, QPropertyAnimation *end,
450 qreal val, qreal minExtent, qreal maxExtent)
452 if (val > minExtent || maxExtent > minExtent) {
453 if (!qFuzzyCompare(val, minExtent)) {
456 if (hasXProperty && hasYProperty) {
458 minExtent = -minExtent;
460 qreal dist = minExtent - val;
461 start->setStartValue(val);
462 start->setEndValue(minExtent - dist/2);
463 end->setStartValue(minExtent - dist/2);
464 end->setEndValue(minExtent);
469 QObject *obj = start->targetObject();
470 obj->setProperty(start->propertyName(), minExtent);
473 }
else if (val < maxExtent) {
475 if (hasXProperty && hasYProperty) {
477 maxExtent = -maxExtent;
479 qreal dist = maxExtent - val;
480 start->setStartValue(val);
481 start->setEndValue(maxExtent - dist/2);
482 end->setStartValue(maxExtent - dist/2);
483 end->setEndValue(maxExtent);
488 QObject *obj = start->targetObject();
489 obj->setProperty(start->propertyName(), maxExtent);
491 }
else if (end == fixupAnimation.endX && snapSize.width() > 1 &&
492 q->contentsSize().width() > q->viewportGeometry().width()) {
493 int target = snapSize.width() * round(val/snapSize.width());
494 fixupAnimation.snapX->setStartValue(val);
495 fixupAnimation.snapX->setEndValue(target);
497 fixupAnimation.snapX->start();
498 }
else if (end == fixupAnimation.endY && snapSize.height() > 1 &&
499 q->contentsSize().height() > q->viewportGeometry().height()) {
500 int target = snapSize.height() * round(val/snapSize.height());
501 fixupAnimation.snapY->setStartValue(val);
502 fixupAnimation.snapY->setEndValue(target);
504 fixupAnimation.snapY->start();
509 fixup(fixupAnimation.groupX, fixupAnimation.startX, fixupAnimation.endX,
510 widgetX(), minXExtent(), maxXExtent());
514 fixup(fixupAnimation.groupY, fixupAnimation.startY, fixupAnimation.endY,
515 widgetY(), minYExtent(), maxYExtent());
518 void makeRectVisible()
524 QRectF viewRect = scrollingWidget->boundingRect();
526 QRectF mappedRect = QRectF(QPointF(qBound((qreal)0.0, rectToBeVisible.x(), widget.data()->size().width() - rectToBeVisible.width()),
527 qBound((qreal)0.0, rectToBeVisible.y(), widget.data()->size().height() - rectToBeVisible.height())),
528 rectToBeVisible.size());
529 mappedRect = widget.data()->mapToItem(scrollingWidget, mappedRect).boundingRect();
531 if (viewRect.contains(mappedRect)) {
537 if (mappedRect.top() < 0) {
538 delta.setY(-mappedRect.top());
539 }
else if (mappedRect.bottom() > viewRect.bottom()) {
540 delta.setY(viewRect.bottom() - mappedRect.bottom());
543 if (mappedRect.left() < 0) {
544 delta.setX(-mappedRect.left());
545 }
else if (mappedRect.right() > viewRect.right()) {
546 delta.setX(viewRect.right() - mappedRect.right());
549 animateMoveTo(q->scrollPosition() - delta);
552 void makeItemVisible(QGraphicsItem *itemToBeVisible)
558 QRectF rect(widget.data()->mapFromScene(itemToBeVisible->scenePos()), itemToBeVisible->boundingRect().size());
559 rectToBeVisible = rect;
564 void makeItemVisible()
566 if (widgetToBeVisible) {
567 makeItemVisible(widgetToBeVisible.data());
571 void stopAnimations()
573 flickAnimationX->stop();
574 flickAnimationY->stop();
575 fixupAnimation.groupX->stop();
576 fixupAnimation.groupY->stop();
579 void setWidgetX(qreal x)
582 widget.data()->setProperty(
"scrollPositionX", -x);
584 widget.data()->setX(x);
586 void setWidgetY(qreal y)
589 widget.data()->setProperty(
"scrollPositionY", -y);
591 widget.data()->setY(y);
593 qreal widgetX()
const
596 return -widget.data()->property(
"scrollPositionX").toReal();
598 return widget.data()->x();
600 qreal widgetY()
const
603 return -widget.data()->property(
"scrollPositionY").toReal();
605 return widget.data()->y();
608 void handleKeyPressEvent(QKeyEvent *event)
610 if (!widget.data()) {
615 QPointF start = q->scrollPosition();
620 switch (event->key()) {
623 end += QPointF(-step, 0);
628 end += QPointF(step, 0);
633 end += QPointF(0, -step);
638 end += QPointF(0, step);
646 fixupAnimation.groupX->stop();
647 fixupAnimation.groupY->stop();
648 fixupAnimation.snapX->stop();
649 fixupAnimation.snapY->stop();
650 directMoveAnimation->setStartValue(start);
651 directMoveAnimation->setEndValue(end);
652 directMoveAnimation->setDuration(200);
653 directMoveAnimation->start();
656 void handleMousePressEvent(QGraphicsSceneMouseEvent *event)
659 lastPosTime = QTime::currentTime();
660 pressPos =
event->scenePos();
661 pressScrollPos = -q->scrollPosition();
662 pressTime = QTime::currentTime();
663 velocity = QPointF();
667 void handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
669 if (lastPosTime.isNull())
671 bool rejectY =
false;
672 bool rejectX =
false;
676 int dy = int(event->scenePos().y() - pressPos.y());
677 if (qAbs(dy) > KGlobalSettings::dndEventDelay() || elapsed(pressTime) > 200) {
678 qreal newY = dy + pressScrollPos.y();
679 const qreal minY = minYExtent();
680 const qreal maxY = maxYExtent();
682 newY = minY + (newY - minY) / 2;
683 if (newY < maxY && maxY - minY <= 0)
684 newY = maxY + (newY - maxY) / 2;
685 if (!hasOvershoot && (newY > minY || newY < maxY)) {
688 else if (newY < maxY)
693 if (!rejectY && stealEvent) {
694 setWidgetY(qRound(newY));
697 if (qAbs(dy) > KGlobalSettings::dndEventDelay())
703 int dx = int(event->scenePos().x() - pressPos.x());
704 if (qAbs(dx) > KGlobalSettings::dndEventDelay() || elapsed(pressTime) > 200) {
705 qreal newX = dx + pressScrollPos.x();
706 const qreal minX = minXExtent();
707 const qreal maxX = maxXExtent();
709 newX = minX + (newX - minX) / 2;
710 if (newX < maxX && maxX - minX <= 0)
711 newX = maxX + (newX - maxX) / 2;
712 if (!hasOvershoot && (newX > minX || newX < maxX)) {
715 else if (newX < maxX)
720 if (!rejectX && stealEvent) {
721 setWidgetX(qRound(newX));
725 if (qAbs(dx) > KGlobalSettings::dndEventDelay())
730 if (!lastPos.isNull()) {
731 qreal msecs = qreal(restart(lastPosTime));
732 qreal elapsed = msecs / 1000.;
733 #if IGNORE_SUSPICIOUS_MOVES
739 qreal diff =
event->scenePos().y() - lastPos.y();
741 velocity.setY( velocity.y() + (diff / elapsed) );
742 velocity.setY( velocity.y() / 2 );
746 qreal diff =
event->scenePos().x() - lastPos.x();
748 velocity.setX( velocity.x() + (diff / elapsed) );
749 velocity.setX( velocity.x() / 2 );
751 #if IGNORE_SUSPICIOUS_MOVES
756 if (rejectX) velocity.setX(0);
757 if (rejectY) velocity.setY(0);
759 lastPos =
event->scenePos();
762 void handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
765 if (lastPosTime.isNull())
768 if (elapsed(lastPosTime) > 100) {
770 velocity = QPointF();
773 if (qAbs(velocity.y()) > 10 &&
775 qreal vVelocity = velocity.y();
784 if (qAbs(velocity.x()) > 10 &&
786 qreal hVelocity = velocity.x();
795 lastPosTime = QTime();
798 void handleWheelEvent(QGraphicsSceneWheelEvent *event)
801 if (!widget.data() || wheelTimer->isActive()) {
805 QPointF start = q->scrollPosition();
816 qreal step = -
event->delta()/3;
819 Qt::Orientation orientation =
event->orientation();
821 if (!canYFlick() && canXFlick()) {
822 end += QPointF(step, 0);
823 }
else if (canYFlick()) {
824 end += QPointF(0, step);
829 if (canYFlick() && !canXFlick()) {
830 end += QPointF(0, step);
831 }
else if (canXFlick()) {
832 end += QPointF(step, 0);
838 fixupAnimation.groupX->stop();
839 fixupAnimation.groupY->stop();
840 fixupAnimation.snapX->stop();
841 fixupAnimation.snapY->stop();
842 directMoveAnimation->setStartValue(start);
843 directMoveAnimation->setEndValue(end);
844 directMoveAnimation->setDuration(200);
845 directMoveAnimation->start();
846 wheelTimer->start(50);
849 qreal minXExtent()
const
851 if (alignment & Qt::AlignLeft)
854 qreal vWidth = q->viewportGeometry().width();
855 qreal cWidth = q->contentsSize().width();
856 if (cWidth < vWidth) {
857 if (alignment & Qt::AlignRight)
858 return vWidth - cWidth;
859 else if (alignment & Qt::AlignHCenter)
860 return vWidth / 2 - cWidth / 2;
867 qreal maxXExtent()
const
869 return q->viewportGeometry().width() -
870 q->contentsSize().width();
873 qreal minYExtent()
const
875 if (alignment & Qt::AlignTop)
878 qreal vHeight = q->viewportGeometry().height();
879 qreal cHeight = q->contentsSize().height();
880 if (cHeight < vHeight) {
881 if (alignment & Qt::AlignBottom)
882 return vHeight - cHeight;
883 else if (alignment & Qt::AlignVCenter)
884 return vHeight / 2 - cHeight / 2;
891 qreal maxYExtent()
const
893 return q->viewportGeometry().height() -
894 q->contentsSize().height();
897 bool canXFlick()
const
900 return q->contentsSize().width() > q->viewportGeometry().width();
903 bool canYFlick()
const
905 return q->contentsSize().height() > q->viewportGeometry().height();
908 int elapsed(
const QTime &t)
const
910 int n = t.msecsTo(QTime::currentTime());
916 int restart(QTime &t)
const
918 QTime time = QTime::currentTime();
919 int n = t.msecsTo(time);
926 void createFlickAnimations()
929 QString xProp = QString::fromLatin1(
"x");
930 QString yProp = QString::fromLatin1(
"y");
933 xProp = QString::fromLatin1(
"scrollPositionX");
935 yProp = QString::fromLatin1(
"scrollPositionY");
937 flickAnimationX =
new QPropertyAnimation(widget.data(),
938 xProp.toLatin1(), widget.data());
939 flickAnimationY =
new QPropertyAnimation(widget.data(),
940 yProp.toLatin1(), widget.data());
941 QObject::connect(flickAnimationX, SIGNAL(finished()),
943 QObject::connect(flickAnimationY, SIGNAL(finished()),
946 QObject::connect(flickAnimationX,
947 SIGNAL(stateChanged(QAbstractAnimation::State,
948 QAbstractAnimation::State)),
949 q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
950 QAbstractAnimation::State)));
951 QObject::connect(flickAnimationY,
952 SIGNAL(stateChanged(QAbstractAnimation::State,
953 QAbstractAnimation::State)),
954 q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
955 QAbstractAnimation::State)));
957 flickAnimationX->setEasingCurve(QEasingCurve::OutCirc);
958 flickAnimationY->setEasingCurve(QEasingCurve::OutCirc);
961 fixupAnimation.groupX =
new QSequentialAnimationGroup(widget.data());
962 fixupAnimation.groupY =
new QSequentialAnimationGroup(widget.data());
963 fixupAnimation.startX =
new QPropertyAnimation(widget.data(),
964 xProp.toLatin1(), widget.data());
965 fixupAnimation.startY =
new QPropertyAnimation(widget.data(),
966 yProp.toLatin1(), widget.data());
967 fixupAnimation.endX =
new QPropertyAnimation(widget.data(),
968 xProp.toLatin1(), widget.data());
969 fixupAnimation.endY =
new QPropertyAnimation(widget.data(),
970 yProp.toLatin1(), widget.data());
971 fixupAnimation.groupX->addAnimation(
972 fixupAnimation.startX);
973 fixupAnimation.groupY->addAnimation(
974 fixupAnimation.startY);
975 fixupAnimation.groupX->addAnimation(
976 fixupAnimation.endX);
977 fixupAnimation.groupY->addAnimation(
978 fixupAnimation.endY);
980 fixupAnimation.startX->setEasingCurve(QEasingCurve::InQuad);
981 fixupAnimation.endX->setEasingCurve(QEasingCurve::OutQuint);
982 fixupAnimation.startY->setEasingCurve(QEasingCurve::InQuad);
983 fixupAnimation.endY->setEasingCurve(QEasingCurve::OutQuint);
985 fixupAnimation.snapX =
new QPropertyAnimation(widget.data(),
986 xProp.toLatin1(), widget.data());
987 fixupAnimation.snapY =
new QPropertyAnimation(widget.data(),
988 yProp.toLatin1(), widget.data());
989 fixupAnimation.snapX->setEasingCurve(QEasingCurve::InOutQuad);
990 fixupAnimation.snapY->setEasingCurve(QEasingCurve::InOutQuad);
992 QObject::connect(fixupAnimation.groupX,
993 SIGNAL(stateChanged(QAbstractAnimation::State,
994 QAbstractAnimation::State)),
995 q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
996 QAbstractAnimation::State)));
997 QObject::connect(fixupAnimation.groupY,
998 SIGNAL(stateChanged(QAbstractAnimation::State,
999 QAbstractAnimation::State)),
1000 q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
1001 QAbstractAnimation::State)));
1003 directMoveAnimation =
new QPropertyAnimation(q,
1006 QObject::connect(directMoveAnimation, SIGNAL(finished()),
1008 QObject::connect(directMoveAnimation, SIGNAL(finished()),
1010 QObject::connect(directMoveAnimation,
1011 SIGNAL(stateChanged(QAbstractAnimation::State,
1012 QAbstractAnimation::State)),
1013 q, SIGNAL(scrollStateChanged(QAbstractAnimation::State,
1014 QAbstractAnimation::State)));
1015 directMoveAnimation->setEasingCurve(QEasingCurve::OutCirc);
1019 void deleteFlickAnimations()
1021 if (flickAnimationX)
1022 flickAnimationX->stop();
1023 if (flickAnimationY)
1024 flickAnimationY->stop();
1025 delete flickAnimationX;
1026 delete flickAnimationY;
1027 delete fixupAnimation.groupX;
1028 delete fixupAnimation.groupY;
1029 delete directMoveAnimation;
1030 delete fixupAnimation.snapX;
1031 delete fixupAnimation.snapY;
1036 if (horizontalScrollBarPolicy != Qt::ScrollBarAlwaysOff) {
1037 horizontalScrollBar->blockSignals(
true);
1038 horizontalScrollBar->setValue(-widget.data()->pos().x()/10.);
1039 horizontalScrollBar->blockSignals(
false);
1045 if (verticalScrollBarPolicy != Qt::ScrollBarAlwaysOff) {
1046 verticalScrollBar->blockSignals(
true);
1047 verticalScrollBar->setValue(-widget.data()->pos().y()/10.);
1048 verticalScrollBar->blockSignals(
false);
1054 QWeakPointer<QGraphicsWidget> widget;
1060 QGraphicsGridLayout *layout;
1061 ScrollBar *verticalScrollBar;
1062 Qt::ScrollBarPolicy verticalScrollBarPolicy;
1063 ScrollBar *horizontalScrollBar;
1064 Qt::ScrollBarPolicy horizontalScrollBarPolicy;
1066 QWeakPointer<QGraphicsWidget> widgetToBeVisible;
1067 QRectF rectToBeVisible;
1068 QPointF dragHandleClicked;
1070 QTimer *adjustScrollbarsTimer;
1074 QPointF pressScrollPos;
1079 QPropertyAnimation *flickAnimationX;
1080 QPropertyAnimation *flickAnimationY;
1082 QAnimationGroup *groupX;
1083 QPropertyAnimation *startX;
1084 QPropertyAnimation *endX;
1086 QAnimationGroup *groupY;
1087 QPropertyAnimation *startY;
1088 QPropertyAnimation *endY;
1090 QPropertyAnimation *snapX;
1091 QPropertyAnimation *snapY;
1093 QPropertyAnimation *directMoveAnimation;
1097 bool overflowBordersVisible;
1099 Qt::Alignment alignment;
1101 Gesture multitouchGesture;
1103 bool hasContentsProperty;
1104 bool hasOffsetProperty;
1112 d(new ScrollWidgetPrivate(this))
1114 d->commonConstructor();
1119 d(new ScrollWidgetPrivate(this))
1121 d->commonConstructor();
1131 if (d->widget && d->widget.data() !=
widget) {
1132 d->deleteFlickAnimations();
1133 d->widget.data()->removeEventFilter(
this);
1134 delete d->widget.data();
1140 d->hasContentsProperty = widget->property(
"contentsSize").isValid();
1141 d->hasOffsetProperty = widget->property(
"scrollPosition").isValid();
1142 d->hasXProperty = widget->property(
"scrollPositionX").isValid();
1143 d->hasYProperty = widget->property(
"scrollPositionY").isValid();
1144 d->createFlickAnimations();
1146 connect(widget, SIGNAL(xChanged()),
this, SLOT(setScrollX()));
1147 connect(widget, SIGNAL(yChanged()),
this, SLOT(setScrollY()));
1148 widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
1149 widget->setParentItem(d->scrollingWidget);
1150 widget->setPos(d->minXExtent(), d->minYExtent());
1151 widget->installEventFilter(
this);
1152 d->adjustScrollbarsTimer->start(200);
1158 return d->widget.data();
1164 d->horizontalScrollBarPolicy = policy;
1170 return d->horizontalScrollBarPolicy;
1176 d->verticalScrollBarPolicy = policy;
1181 return d->verticalScrollBarPolicy;
1186 return d->overflowBordersVisible;
1191 if (d->overflowBordersVisible == visible) {
1195 d->overflowBordersVisible = visible;
1196 d->adjustScrollbars();
1205 d->rectToBeVisible = rect;
1206 d->makeRectVisible();
1211 if (!d->widget || !item) {
1215 QGraphicsItem *parentOfItem = item->parentItem();
1216 while (parentOfItem != d->widget.data()) {
1217 if (!parentOfItem) {
1221 parentOfItem = parentOfItem->parentItem();
1227 d->widgetToBeVisible =
widget;
1230 QTimer::singleShot(0,
this, SLOT(makeItemVisible()));
1232 d->makeItemVisible(item);
1236 #ifndef KDE_NO_DEPRECATED
1244 #ifndef KDE_NO_DEPRECATED
1259 return d->scrollingWidget->boundingRect();
1265 if (d->hasContentsProperty) {
1266 QVariant var = d->widget.data()->property(
"contentsSize");
1267 return var.toSizeF();
1269 return d->widget.data()->size();
1277 if (d->hasOffsetProperty)
1278 d->widget.data()->setProperty(
"scrollPosition", position);
1280 d->widget.data()->setPos(-position.toPoint());
1287 if (d->hasOffsetProperty) {
1288 QVariant var = d->widget.data()->property(
"scrollPosition");
1289 return var.toPointF();
1291 return -d->widget.data()->pos();
1310 d->verticalScrollBar->setStyleSheet(styleSheet);
1311 d->horizontalScrollBar->setStyleSheet(styleSheet);
1316 return d->styleSheet;
1329 d->widget.data()->setFocus();
1337 QGraphicsWidget::resizeEvent(event);
1341 d->adjustScrollbarsTimer->start(200);
1345 d->topBorder->resize(event->newSize().width(), d->topBorder->size().height());
1346 d->bottomBorder->resize(event->newSize().width(), d->bottomBorder->size().height());
1347 d->bottomBorder->setPos(0, event->newSize().height() - d->bottomBorder->size().height());
1349 if (d->leftBorder) {
1350 d->leftBorder->resize(d->leftBorder->size().width(),
event->newSize().height());
1351 d->rightBorder->resize(d->rightBorder->size().width(),
event->newSize().height());
1352 d->rightBorder->setPos(event->newSize().width() - d->rightBorder->size().width(), 0);
1355 QGraphicsWidget::resizeEvent(event);
1360 d->handleKeyPressEvent(event);
1369 d->handleMouseMoveEvent(event);
1372 return QGraphicsWidget::mouseMoveEvent(event);
1379 }
else if (!d->canYFlick() && !d->canXFlick()) {
1384 d->handleMousePressEvent(event);
1386 if (event->button() == Qt::LeftButton) {
1389 QGraphicsWidget::mousePressEvent(event);
1399 d->handleMouseReleaseEvent(event);
1407 }
else if (!d->canYFlick() && !d->canXFlick()) {
1411 d->handleWheelEvent(event);
1421 if (watched == d->scrollingWidget && (event->type() == QEvent::GraphicsSceneResize ||
1422 event->type() == QEvent::Move)) {
1424 }
else if (watched == d->widget.data() &&
event->type() == QEvent::GraphicsSceneResize) {
1425 d->stopAnimations();
1426 d->adjustScrollbarsTimer->start(200);
1429 QPointF newPos = d->widget.data()->pos();
1431 newPos.setX(d->minXExtent());
1434 newPos.setY(d->minYExtent());
1437 if (d->widget.data()->geometry().right() < 0) {
1438 newPos.setX(-d->widget.data()->geometry().width()+
viewportGeometry().width());
1440 if (d->widget.data()->geometry().bottom() < 0) {
1441 newPos.setY(-d->widget.data()->geometry().height()+
viewportGeometry().height());
1443 d->widget.data()->setPos(newPos);
1445 }
else if (watched == d->widget.data() &&
event->type() == QEvent::GraphicsSceneMove) {
1446 d->horizontalScrollBar->blockSignals(
true);
1447 d->verticalScrollBar->blockSignals(
true);
1448 d->horizontalScrollBar->setValue(-d->widget.data()->pos().x()/10);
1449 d->verticalScrollBar->setValue(-d->widget.data()->pos().y()/10);
1450 d->horizontalScrollBar->blockSignals(
false);
1451 d->verticalScrollBar->blockSignals(
false);
1459 if (!d->widget || which == Qt::MaximumSize) {
1460 return QGraphicsWidget::sizeHint(which, constraint);
1462 }
else if (which == Qt::MinimumSize) {
1463 return QSizeF(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous);
1466 QSizeF hint = d->widget.data()->effectiveSizeHint(which, constraint);
1467 if (d->horizontalScrollBar && d->horizontalScrollBar->isVisible()) {
1468 hint += QSize(0, d->horizontalScrollBar->size().height());
1470 if (d->verticalScrollBar && d->verticalScrollBar->isVisible()) {
1471 hint += QSize(d->verticalScrollBar->size().width(), 0);
1481 if (!d->widget.data() ||
1482 (!d->scrollingWidget->isAncestorOf(i) && i != d->scrollingWidget) ||
1483 i == d->horizontalScrollBar || i == d->verticalScrollBar) {
1487 if (i->isWidget()) {
1489 if (label && (label->
nativeWidget()->textInteractionFlags() & Qt::TextSelectableByMouse)) {
1494 if (textEdit && (textEdit->
nativeWidget()->textInteractionFlags() & Qt::TextSelectableByMouse)) {
1499 if (textBrowser && (textBrowser->
nativeWidget()->textInteractionFlags() & Qt::TextSelectableByMouse)) {
1504 bool stealThisEvent = d->stealEvent;
1506 stealThisEvent &= (e->type() == QEvent::GraphicsSceneMousePress ||
1507 e->type() == QEvent::GraphicsSceneMouseRelease);
1509 qDebug()<<
"sceneEventFilter = " <<i<<
", "
1510 <<QTime::currentTime().toString(QString::fromLatin1(
"hh:mm:ss.zzz"));
1512 switch (e->type()) {
1513 case QEvent::GraphicsSceneMousePress:
1514 d->handleMousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(e));
1516 case QEvent::GraphicsSceneMouseMove:
1517 d->handleMouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(e));
1519 case QEvent::GraphicsSceneMouseRelease:
1520 d->handleMouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(e));
1524 case QEvent::TouchUpdate: {
1525 QList<QTouchEvent::TouchPoint> touchPoints =
static_cast<QTouchEvent *
>(e)->touchPoints();
1526 if (touchPoints.count() == 2) {
1527 const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
1528 const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
1529 const QLineF line0(touchPoint0.lastPos(), touchPoint1.lastPos());
1530 const QLineF line1(touchPoint0.pos(), touchPoint1.pos());
1531 const QLineF startLine(touchPoint0.startPos(), touchPoint1.startPos());
1532 const QPointF point = line1.pointAt(0.5);
1533 const QPointF lastPoint = line0.pointAt(0.5);
1535 if (d->multitouchGesture == ScrollWidgetPrivate::GestureNone) {
1536 d->multitouchGesture = ScrollWidgetPrivate::GestureUndefined;
1538 if (d->multitouchGesture == ScrollWidgetPrivate::GestureUndefined) {
1539 const int zoomDistance = qAbs(line1.length() - startLine.length());
1540 const int dragDistance = (startLine.pointAt(0.5) - point).manhattanLength();
1542 if (zoomDistance - dragDistance > 30) {
1543 d->multitouchGesture = ScrollWidgetPrivate::GestureZoom;
1544 }
else if (dragDistance - zoomDistance > 30) {
1545 d->multitouchGesture = ScrollWidgetPrivate::GestureScroll;
1549 if (d->multitouchGesture == ScrollWidgetPrivate::GestureScroll) {
1550 QGraphicsSceneMouseEvent fakeEvent;
1551 fakeEvent.setPos(point);
1552 fakeEvent.setLastPos(lastPoint);
1553 d->handleMouseMoveEvent(&fakeEvent);
1554 }
else if (d->multitouchGesture == ScrollWidgetPrivate::GestureZoom) {
1555 if (d->widget && d->widget.data()->property(
"zoomFactor").isValid()) {
1556 qreal scaleFactor = 1;
1557 if (line0.length() > 0) {
1558 scaleFactor = line1.length() / line0.length();
1561 qreal zoom = d->widget.data()->property(
"zoomFactor").toReal();
1562 d->widget.data()->setProperty(
"zoomFactor", zoom * scaleFactor);
1573 return QGraphicsWidget::sceneEventFilter(i, e);
1578 d->alignment = align;
1579 if (d->widget.data() &&
1580 d->widget.data()->isVisible()) {
1581 d->widget.data()->setPos(d->minXExtent(),
1588 return d->alignment;
1593 d->hasOvershoot = enable;
1598 return d->hasOvershoot;
1604 #include <scrollwidget.moc>
The applet is constrained horizontally, but can expand vertically.
KTextBrowser nativeWidget
Provides a plasma-themed KTextBrowser.
The applet is constrained vertically, but can expand horizontally.
Provides a plasma-themed QLabel.
Provides a plasma-themed KTextEdit.
A theme aware image-centric SVG class.