From d99d5fbea76a79346761c0d8ce98a0719e5790d2 Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Sat, 27 Aug 2011 20:12:03 +0200 Subject: [PATCH] Improve the autoscrolling for the rubberband selection This modifications will also allow to do an autoscrolling in an easy way for drag and drop operations (not fully implemented yet). --- src/kitemviews/kitemlistcontainer.cpp | 7 +++ src/kitemviews/kitemlistcontroller.cpp | 2 + src/kitemviews/kitemlistview.cpp | 82 ++++++++++++++++++-------- src/kitemviews/kitemlistview.h | 20 +++++-- 4 files changed, 83 insertions(+), 28 deletions(-) diff --git a/src/kitemviews/kitemlistcontainer.cpp b/src/kitemviews/kitemlistcontainer.cpp index ec759bdb3..0d2637da6 100644 --- a/src/kitemviews/kitemlistcontainer.cpp +++ b/src/kitemviews/kitemlistcontainer.cpp @@ -120,7 +120,14 @@ void KItemListContainer::scrollContentsBy(int dx, int dy) return; } + const QScrollBar* scrollBar = (view->scrollOrientation() == Qt::Vertical) + ? verticalScrollBar() : horizontalScrollBar(); const qreal currentOffset = view->offset(); + if (static_cast(currentOffset) == scrollBar->value()) { + // The current offset is already synchronous to the scrollbar + return; + } + qreal offsetDiff = (view->scrollOrientation() == Qt::Vertical) ? dy : dx; const bool animRunning = (m_smoothScrollingAnimation->state() == QAbstractAnimation::Running); diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index ddae06c17..78c0a3594 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -306,6 +306,7 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const rubberBand->setEndPosition(startPos); rubberBand->setActive(true); connect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged())); + m_view->setAutoScroll(true); } return false; @@ -365,6 +366,7 @@ bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, con disconnect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged())); rubberBand->setActive(false); m_oldSelection.clear(); + m_view->setAutoScroll(false); if (rubberBand->startPosition() != rubberBand->endPosition()) { clearSelection = false; diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 3435e3f65..a35752a47 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -43,7 +43,6 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : QGraphicsWidget(parent), - m_autoScrollMarginEnabled(false), m_grouped(false), m_activeTransactions(0), m_itemSize(), @@ -62,8 +61,10 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : m_layoutTimer(0), m_oldOffset(0), m_oldMaximumOffset(0), + m_skipAutoScrollForRubberBand(false), m_rubberBand(0), - m_mousePos() + m_mousePos(), + m_autoScrollTimer(0) { setAcceptHoverEvents(true); @@ -193,6 +194,26 @@ QHash KItemListView::visibleRoles() const return m_visibleRoles; } +void KItemListView::setAutoScroll(bool enabled) +{ + if (enabled && !m_autoScrollTimer) { + m_autoScrollTimer = new QTimer(this); + m_autoScrollTimer->setInterval(1000 / 60); // 60 frames per second + m_autoScrollTimer->setSingleShot(false); + connect(m_autoScrollTimer, SIGNAL(timeout()), this, SLOT(triggerAutoScrolling())); + m_autoScrollTimer->start(); + } else if (!enabled && m_autoScrollTimer) { + delete m_autoScrollTimer; + m_autoScrollTimer = 0; + } + +} + +bool KItemListView::autoScroll() const +{ + return m_autoScrollTimer != 0; +} + KItemListController* KItemListView::controller() const { return m_controller; @@ -463,6 +484,10 @@ void KItemListView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { m_mousePos = transform().map(event->pos()); QGraphicsWidget::mouseMoveEvent(event); + + if (m_autoScrollTimer && !m_autoScrollTimer->isActive()) { + m_autoScrollTimer->start(); + } } void KItemListView::dragEnterEvent(QGraphicsSceneDragDropEvent* event) @@ -755,29 +780,21 @@ void KItemListView::slotLayoutTimerFinished() doLayout(Animation, 0, 0); } -void KItemListView::slotRubberBandStartPosChanged() +void KItemListView::slotRubberBandPosChanged() { update(); } -void KItemListView::slotRubberBandEndPosChanged() -{ - // The autoscrolling is triggered asynchronously otherwise it - // might be possible to have an endless recursion: The autoscrolling - // might adjust the position which might result in updating the - // rubberband end-position. - QTimer::singleShot(0, this, SLOT(triggerAutoScrolling())); - update(); -} - void KItemListView::slotRubberBandActivationChanged(bool active) { if (active) { - connect(m_rubberBand, SIGNAL(startPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandStartPosChanged())); - connect(m_rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandEndPosChanged())); + connect(m_rubberBand, SIGNAL(startPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandPosChanged())); + connect(m_rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandPosChanged())); + m_skipAutoScrollForRubberBand = true; } else { - disconnect(m_rubberBand, SIGNAL(startPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandStartPosChanged())); - disconnect(m_rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandEndPosChanged())); + disconnect(m_rubberBand, SIGNAL(startPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandPosChanged())); + disconnect(m_rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandPosChanged())); + m_skipAutoScrollForRubberBand = false; } update(); @@ -785,6 +802,10 @@ void KItemListView::slotRubberBandActivationChanged(bool active) void KItemListView::triggerAutoScrolling() { + if (!m_autoScrollTimer) { + return; + } + int pos = 0; int visibleSize = 0; if (scrollOrientation() == Qt::Vertical) { @@ -797,13 +818,17 @@ void KItemListView::triggerAutoScrolling() const int inc = calculateAutoScrollingIncrement(pos, visibleSize); if (inc == 0) { - // The mouse position is not above an autoscroll margin + // The mouse position is not above an autoscroll margin (the autoscroll timer + // will be restarted in mouseMoveEvent()) + m_autoScrollTimer->stop(); return; } - if (m_rubberBand->isActive()) { + if (m_rubberBand->isActive() && m_skipAutoScrollForRubberBand) { // If a rubberband selection is ongoing the autoscrolling may only get triggered - // if the direction of the rubberband is similar to the autoscroll direction. + // if the direction of the rubberband is similar to the autoscroll direction. This + // prevents that starting to create a rubberband within the autoscroll margins starts + // an autoscrolling. const qreal minDiff = 4; // Ignore any autoscrolling if the rubberband is very small const qreal diff = (scrollOrientation() == Qt::Vertical) @@ -812,11 +837,22 @@ void KItemListView::triggerAutoScrolling() if (qAbs(diff) < minDiff || (inc < 0 && diff > 0) || (inc > 0 && diff < 0)) { // The rubberband direction is different from the scroll direction (e.g. the rubberband has // been moved up although the autoscroll direction might be down) + m_autoScrollTimer->stop(); return; } } - emit scrollTo(offset() + inc); + // As soon as the autoscrolling has been triggered at least once despite having an active rubberband, + // the autoscrolling may not get skipped anymore until a new rubberband is created + m_skipAutoScrollForRubberBand = false; + + setOffset(offset() + inc); + + if (!m_autoScrollTimer->isActive()) { + // Trigger the autoscroll timer which will periodically call + // triggerAutoScrolling() + m_autoScrollTimer->start(); + } } void KItemListView::setController(KItemListController* controller) @@ -1230,8 +1266,8 @@ int KItemListView::calculateAutoScrollingIncrement(int pos, int size) int inc = 0; const int minSpeed = 4; - const int maxSpeed = 768; - const int speedLimiter = 48; + const int maxSpeed = 128; + const int speedLimiter = 96; const int autoScrollBorder = 64; if (pos < autoScrollBorder) { diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 344221e40..9977e3639 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -89,6 +89,14 @@ public: void setVisibleRoles(const QHash& roles); QHash visibleRoles() const; + /** + * If set to true an automatic scrolling is done as soon as the + * mouse is moved near the borders of the view. Per default + * the automatic scrolling is turned off. + */ + void setAutoScroll(bool enabled); + bool autoScroll() const; + /** * @return Controller of the item-list. The controller gets * initialized by KItemListController::setView() and will @@ -124,6 +132,7 @@ public: void setStyleOption(const KItemListStyleOption& option); const KItemListStyleOption& styleOption() const; + /** @reimp */ virtual void setGeometry(const QRectF& rect); int itemAt(const QPointF& pos) const; @@ -207,13 +216,13 @@ private slots: KItemListViewAnimation::AnimationType type); void slotLayoutTimerFinished(); - void slotRubberBandStartPosChanged(); - void slotRubberBandEndPosChanged(); + void slotRubberBandPosChanged(); void slotRubberBandActivationChanged(bool active); /** - * Emits the signal scrollTo() with the corresponding target offset if the current - * mouse position is above the autoscroll-margin. + * Triggers the autoscrolling if autoScroll() is enabled by checking the + * current mouse position. If the mouse position is within the autoscroll + * margins a timer will be started that periodically triggers the autoscrolling. */ void triggerAutoScrolling(); @@ -289,7 +298,6 @@ private: static int calculateAutoScrollingIncrement(int pos, int size); private: - bool m_autoScrollMarginEnabled; bool m_grouped; int m_activeTransactions; // Counter for beginTransaction()/endTransaction() @@ -314,9 +322,11 @@ private: qreal m_oldOffset; qreal m_oldMaximumOffset; + bool m_skipAutoScrollForRubberBand; KItemListRubberBand* m_rubberBand; QPointF m_mousePos; + QTimer* m_autoScrollTimer; friend class KItemListController; }; -- 2.47.3