From: Peter Penz Date: Thu, 18 Aug 2011 21:11:16 +0000 (+0200) Subject: Provide basic rubberband functionality X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/dbe2152912cc58f1d2bfba187175ec0e4b3e4761?hp=63e82a2b3bba25fbfaa3d283264cc0c61d11cfe8 Provide basic rubberband functionality This is just a rough draft: The rubberband gets visible and an automatic scrolling is done if the autoscroll-margins have been reached. However currently no items get selected yet. Currently the autoscrolling has a severe bug if the scrollbars are manually changed before or after a rubberband selection. --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31f5fa490..31d3f8928 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ set(dolphinprivate_LIB_SRCS kitemviews/kitemlistcontainer.cpp kitemviews/kitemlistcontroller.cpp kitemviews/kitemlistgroupheader.cpp + kitemviews/kitemlistrubberband.cpp kitemviews/kitemlistselectionmanager.cpp kitemviews/kitemlistsizehintresolver.cpp kitemviews/kitemliststyleoption.cpp diff --git a/src/kitemviews/kitemlistcontainer.cpp b/src/kitemviews/kitemlistcontainer.cpp index b8d05dc34..b01751e46 100644 --- a/src/kitemviews/kitemlistcontainer.cpp +++ b/src/kitemviews/kitemlistcontainer.cpp @@ -210,18 +210,32 @@ void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView* QGraphicsScene* scene = static_cast(viewport())->scene(); if (previous) { scene->removeItem(previous); - disconnect(previous, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars())); - disconnect(previous, SIGNAL(maximumOffsetChanged(int,int)), this, SLOT(updateScrollBars())); + disconnect(previous, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(updateScrollBars())); + disconnect(previous, SIGNAL(maximumOffsetChanged(qreal,qreal)), this, SLOT(updateScrollBars())); + disconnect(previous, SIGNAL(scrollTo(qreal)), this, SLOT(scrollTo(qreal))); m_viewOffsetAnimation->setTargetObject(0); } if (current) { scene->addItem(current); - connect(current, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars())); - connect(current, SIGNAL(maximumOffsetChanged(int,int)), this, SLOT(updateScrollBars())); + connect(current, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(updateScrollBars())); + connect(current, SIGNAL(maximumOffsetChanged(qreal,qreal)), this, SLOT(updateScrollBars())); + connect(current, SIGNAL(scrollTo(qreal)), this, SLOT(scrollTo(qreal))); m_viewOffsetAnimation->setTargetObject(current); } } +void KItemListContainer::scrollTo(qreal offset) +{ + const KItemListView* view = m_controller->view(); + if (!view) { + return; + } + + QScrollBar* scrollBar = (view->scrollOrientation() == Qt::Vertical) + ? verticalScrollBar() : horizontalScrollBar(); + scrollBar->setValue(offset); +} + void KItemListContainer::updateScrollBars() { const KItemListView* view = m_controller->view(); @@ -267,11 +281,6 @@ void KItemListContainer::updateScrollBars() scrollBar->setMaximum(maximum); scrollBar->setValue(value); - disconnect(view, SIGNAL(scrollTo(int)), - otherScrollBar, SLOT(setValue(int))); - connect(view, SIGNAL(scrollTo(int)), - scrollBar, SLOT(setValue(int))); - // Make sure that the other scroll bar is hidden otherScrollBar->setMaximum(0); otherScrollBar->setValue(0); @@ -316,7 +325,7 @@ void KItemListContainer::initialize() setViewport(graphicsView); m_viewOffsetAnimation = new QPropertyAnimation(this, "offset"); - m_viewOffsetAnimation->setDuration(500); + m_viewOffsetAnimation->setDuration(300); horizontalScrollBar()->installEventFilter(this); verticalScrollBar()->installEventFilter(this); diff --git a/src/kitemviews/kitemlistcontainer.h b/src/kitemviews/kitemlistcontainer.h index e71a7b083..0cda436d0 100644 --- a/src/kitemviews/kitemlistcontainer.h +++ b/src/kitemviews/kitemlistcontainer.h @@ -59,6 +59,7 @@ protected: private slots: void slotModelChanged(KItemModelBase* current, KItemModelBase* previous); void slotViewChanged(KItemListView* current, KItemListView* previous); + void scrollTo(qreal offset); void updateScrollBars(); private: diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index ef449f496..7331131a9 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -23,11 +23,11 @@ #include "kitemlistcontroller.h" #include "kitemlistview.h" +#include "kitemlistrubberband_p.h" #include "kitemlistselectionmanager.h" #include #include -#include #include @@ -80,11 +80,16 @@ void KItemListController::setView(KItemListView* view) } KItemListView* oldView = m_view; + if (oldView) { + disconnect(oldView, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(slotViewOffsetChanged(qreal,qreal))); + } + m_view = view; if (m_view) { m_view->setController(this); m_view->setModel(m_model); + connect(m_view, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(slotViewOffsetChanged(qreal,qreal))); } emit viewChanged(m_view, oldView); @@ -223,6 +228,10 @@ bool KItemListController::inputMethodEvent(QInputMethodEvent* event) bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform) { + if (!m_view) { + return false; + } + const QPointF pos = transform.map(event->pos()); m_pressedIndex = m_view->itemAt(pos); @@ -248,29 +257,40 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const switch (m_selectionBehavior) { case NoSelection: - return true; + break; + case SingleSelection: m_selectionManager->setSelected(m_pressedIndex); - return true; + break; + case MultiSelection: if (controlPressed) { m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle); m_selectionManager->beginAnchoredSelection(m_pressedIndex); - } - else { - if (shiftPressed && m_selectionManager->isAnchoredSelectionActive()) { - // The anchored selection is continued automatically by calling - // m_selectionManager->setCurrentItem(m_pressedIndex), see above -> nothing more to do here - return true; - } - + } else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) { // Select the pressed item and start a new anchored selection m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select); m_selectionManager->beginAnchoredSelection(m_pressedIndex); } + break; + + default: + Q_ASSERT(false); + break; } return true; + } else { + KItemListRubberBand* rubberBand = m_view->rubberBand(); + QPointF startPos = pos; + if (m_view->scrollOrientation() == Qt::Vertical) { + startPos.ry() += m_view->offset(); + } else { + startPos.rx() += m_view->offset(); + } + rubberBand->setStartPosition(startPos); + rubberBand->setEndPosition(startPos); + rubberBand->setActive(true); } return false; @@ -278,38 +298,55 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform) { - Q_UNUSED(event); - Q_UNUSED(transform); + if (!m_view) { + return false; + } + + KItemListRubberBand* rubberBand = m_view->rubberBand(); + if (rubberBand->isActive()) { + QPointF endPos = transform.map(event->pos()); + if (m_view->scrollOrientation() == Qt::Vertical) { + endPos.ry() += m_view->offset(); + } else { + endPos.rx() += m_view->offset(); + } + rubberBand->setEndPosition(endPos); + } + return false; } bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform) { - if (m_view) { - const QPointF pos = transform.map(event->pos()); - const int index = m_view->itemAt(pos); - const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier || event->modifiers() & Qt::ControlModifier; - - if (index >= 0 && index == m_pressedIndex) { - // The release event is done above the same item as the press event - bool emitItemClicked = true; - if (event->button() & Qt::LeftButton) { - if (m_view->isAboveExpansionToggle(index, pos)) { - emit itemExpansionToggleClicked(index); - emitItemClicked = false; - } - else if (shiftOrControlPressed) { - // The mouse click should only update the selection, not trigger the item - emitItemClicked = false; - } - } + if (!m_view) { + return false; + } + + m_view->rubberBand()->setActive(false); - if (emitItemClicked) { - emit itemClicked(index, event->button()); + const QPointF pos = transform.map(event->pos()); + const int index = m_view->itemAt(pos); + const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier || event->modifiers() & Qt::ControlModifier; + + if (index >= 0 && index == m_pressedIndex) { + // The release event is done above the same item as the press event + bool emitItemClicked = true; + if (event->button() & Qt::LeftButton) { + if (m_view->isAboveExpansionToggle(index, pos)) { + emit itemExpansionToggleClicked(index); + emitItemClicked = false; } - } else if (!shiftOrControlPressed) { - m_selectionManager->clearSelection(); + else if (shiftOrControlPressed) { + // The mouse click should only update the selection, not trigger the item + emitItemClicked = false; + } + } + + if (emitItemClicked) { + emit itemClicked(index, event->button()); } + } else if (!shiftOrControlPressed) { + m_selectionManager->clearSelection(); } m_pressedIndex = -1; @@ -480,4 +517,28 @@ bool KItemListController::processEvent(QEvent* event, const QTransform& transfor return false; } +void KItemListController::slotViewOffsetChanged(qreal current, qreal previous) +{ + if (!m_view) { + return; + } + + KItemListRubberBand* rubberBand = m_view->rubberBand(); + if (rubberBand->isActive()) { + const qreal diff = current - previous; + // TODO: Ideally just QCursor::pos() should be used as + // new end-position but it seems there is no easy way + // to have something like QWidget::mapFromGlobal() for QGraphicsWidget + // (... or I just missed an easy way to do the mapping) + QPointF endPos = rubberBand->endPosition(); + if (m_view->scrollOrientation() == Qt::Vertical) { + endPos.ry() += diff; + } else { + endPos.rx() += diff; + } + + rubberBand->setEndPosition(endPos); + } +} + #include "kitemlistcontroller.moc" diff --git a/src/kitemviews/kitemlistcontroller.h b/src/kitemviews/kitemlistcontroller.h index 092a7bc62..c4406a972 100644 --- a/src/kitemviews/kitemlistcontroller.h +++ b/src/kitemviews/kitemlistcontroller.h @@ -28,6 +28,7 @@ #include class KItemModelBase; +class KItemListRubberBandManager; class KItemListSelectionManager; class KItemListView; class QGraphicsSceneHoverEvent; @@ -119,6 +120,9 @@ signals: void modelChanged(KItemModelBase* current, KItemModelBase* previous); void viewChanged(KItemListView* current, KItemListView* previous); +private slots: + void slotViewOffsetChanged(qreal current, qreal previous); + private: SelectionBehavior m_selectionBehavior; KItemModelBase* m_model; diff --git a/src/kitemviews/kitemlistrubberband.cpp b/src/kitemviews/kitemlistrubberband.cpp new file mode 100644 index 000000000..b8605a7a1 --- /dev/null +++ b/src/kitemviews/kitemlistrubberband.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistrubberband_p.h" + +KItemListRubberBand::KItemListRubberBand(QObject* parent) : + QObject(parent), + m_active(false), + m_startPos(), + m_endPos() +{ +} + +KItemListRubberBand::~KItemListRubberBand() +{ +} + +void KItemListRubberBand::setStartPosition(const QPointF& pos) +{ + if (m_startPos != pos) { + const QPointF previous = m_startPos; + m_startPos = pos; + emit startPositionChanged(m_startPos, previous); + } +} + +QPointF KItemListRubberBand::startPosition() const +{ + return m_startPos; +} + +void KItemListRubberBand::setEndPosition(const QPointF& pos) +{ + if (m_endPos != pos) { + const QPointF previous = m_endPos; + m_endPos = pos; + emit endPositionChanged(m_endPos, previous); + } +} + +QPointF KItemListRubberBand::endPosition() const +{ + return m_endPos; +} + +void KItemListRubberBand::setActive(bool active) +{ + if (m_active != active) { + m_active = active; + emit activationChanged(active); + + if (!active) { + m_startPos = QPointF(); + m_endPos = QPointF(); + } + } +} + +bool KItemListRubberBand::isActive() const +{ + return m_active; +} + +#include "kitemlistrubberband_p.moc" diff --git a/src/kitemviews/kitemlistrubberband_p.h b/src/kitemviews/kitemlistrubberband_p.h new file mode 100644 index 000000000..aea58af46 --- /dev/null +++ b/src/kitemviews/kitemlistrubberband_p.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KITEMLISTRUBBERBAND_H +#define KITEMLISTRUBBERBAND_H + +#include +#include +#include + +/** + * @brief Manages the rubberband when selecting items. + */ +class LIBDOLPHINPRIVATE_EXPORT KItemListRubberBand : public QObject +{ + Q_OBJECT + +public: + explicit KItemListRubberBand(QObject* parent = 0); + virtual ~KItemListRubberBand(); + + void setStartPosition(const QPointF& pos); + QPointF startPosition() const; + + void setEndPosition(const QPointF& pos); + QPointF endPosition() const; + + void setActive(bool active); + bool isActive() const; + +signals: + void activationChanged(bool active); + void startPositionChanged(const QPointF& current, const QPointF& previous); + void endPositionChanged(const QPointF& current, const QPointF& previous); + +private: + bool m_active; + QPointF m_startPos; + QPointF m_endPos; +}; + +#endif + + diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index a88116800..3b6b4e2e9 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -24,6 +24,7 @@ #include "kitemlistcontroller.h" #include "kitemlistgroupheader.h" +#include "kitemlistrubberband_p.h" #include "kitemlistselectionmanager.h" #include "kitemlistsizehintresolver_p.h" #include "kitemlistviewlayouter_p.h" @@ -32,13 +33,17 @@ #include +#include #include +#include #include #include +#include #include KItemListView::KItemListView(QGraphicsWidget* parent) : QGraphicsWidget(parent), + m_autoScrollMarginEnabled(false), m_grouped(false), m_activeTransactions(0), m_itemSize(), @@ -56,7 +61,9 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : m_animation(0), m_layoutTimer(0), m_oldOffset(0), - m_oldMaximumOffset(0) + m_oldMaximumOffset(0), + m_rubberBand(0), + m_mousePos() { setAcceptHoverEvents(true); @@ -73,6 +80,9 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : m_layoutTimer->setInterval(300); m_layoutTimer->setSingleShot(true); connect(m_layoutTimer, SIGNAL(timeout()), this, SLOT(slotLayoutTimerFinished())); + + m_rubberBand = new KItemListRubberBand(this); + connect(m_rubberBand, SIGNAL(activationChanged(bool)), this, SLOT(slotRubberBandActivationChanged(bool))); } KItemListView::~KItemListView() @@ -348,6 +358,30 @@ bool KItemListView::isTransactionActive() const return m_activeTransactions > 0; } +void KItemListView::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + QGraphicsWidget::paint(painter, option, widget); + + if (m_rubberBand->isActive()) { + QRectF rubberBandRect = QRectF(m_rubberBand->startPosition(), + m_rubberBand->endPosition()).normalized(); + + const QPointF topLeft = rubberBandRect.topLeft(); + if (scrollOrientation() == Qt::Vertical) { + rubberBandRect.moveTo(topLeft.x(), topLeft.y() - offset()); + } else { + rubberBandRect.moveTo(topLeft.x() - offset(), topLeft.y()); + } + + QStyleOptionRubberBand opt; + opt.initFrom(widget); + opt.shape = QRubberBand::Rectangle; + opt.opaque = false; + opt.rect = rubberBandRect.toRect(); + style()->drawControl(QStyle::CE_RubberBand, &opt, painter); + } +} + void KItemListView::initializeItemListWidget(KItemListWidget* item) { Q_UNUSED(item); @@ -415,9 +449,16 @@ bool KItemListView::event(QEvent* event) void KItemListView::mousePressEvent(QGraphicsSceneMouseEvent* event) { + m_mousePos = transform().map(event->pos()); event->accept(); } +void KItemListView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + m_mousePos = transform().map(event->pos()); + QGraphicsWidget::mouseMoveEvent(event); +} + QList KItemListView::visibleItemListWidgets() const { return m_visibleItems.values(); @@ -436,7 +477,7 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) foreach (const KItemRange& range, itemRanges) { // range.index is related to the model before anything has been inserted. // As in each loop the current item-range gets inserted the index must - // be increased by the already previoulsy inserted items. + // be increased by the already previously inserted items. const int index = range.index + previouslyInsertedCount; const int count = range.count; if (index < 0 || count <= 0) { @@ -701,6 +742,30 @@ void KItemListView::slotLayoutTimerFinished() doLayout(Animation, 0, 0); } +void KItemListView::slotRubberBandStartPosChanged() +{ + update(); +} + +void KItemListView::slotRubberBandEndPosChanged() +{ + 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())); + } else { + disconnect(m_rubberBand, SIGNAL(startPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandStartPosChanged())); + disconnect(m_rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandEndPosChanged())); + } + + update(); +} + void KItemListView::setController(KItemListController* controller) { if (m_controller != controller) { @@ -756,6 +821,11 @@ void KItemListView::setModel(KItemModelBase* model) onModelChanged(model, previous); } +KItemListRubberBand* KItemListView::rubberBand() const +{ + return m_rubberBand; +} + void KItemListView::updateLayout() { doLayout(Animation, 0, 0); @@ -903,13 +973,13 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha void KItemListView::emitOffsetChanges() { - const int newOffset = m_layouter->offset(); + const qreal newOffset = m_layouter->offset(); if (m_oldOffset != newOffset) { emit offsetChanged(newOffset, m_oldOffset); m_oldOffset = newOffset; } - const int newMaximumOffset = m_layouter->maximumOffset(); + const qreal newMaximumOffset = m_layouter->maximumOffset(); if (m_oldMaximumOffset != newMaximumOffset) { emit maximumOffsetChanged(newMaximumOffset, m_oldMaximumOffset); m_oldMaximumOffset = newMaximumOffset; @@ -1102,6 +1172,40 @@ void KItemListView::updateWidgetProperties(KItemListWidget* widget, int index) widget->setData(m_model->data(index)); } +void KItemListView::triggerAutoScrolling() +{ + const int pos = (scrollOrientation() == Qt::Vertical) ? m_mousePos.y() : m_mousePos.x(); + const int inc = calculateAutoScrollingIncrement(pos, size().height()); + if (inc != 0) { + emit scrollTo(offset() + inc); + } +} + +int KItemListView::calculateAutoScrollingIncrement(int pos, int size) +{ + int inc = 0; + + const int minSpeed = 4; + const int maxSpeed = 768; + const int speedLimiter = 48; + const int autoScrollBorder = 64; + + if (pos < autoScrollBorder) { + inc = -minSpeed + qAbs(pos - autoScrollBorder) * (pos - autoScrollBorder) / speedLimiter; + if (inc < -maxSpeed) { + inc = -maxSpeed; + } + } else if (pos > size - autoScrollBorder) { + inc = minSpeed + qAbs(pos - size + autoScrollBorder) * (pos - size + autoScrollBorder) / speedLimiter; + if (inc > maxSpeed) { + inc = maxSpeed; + } + } + + return inc; +} + + KItemListCreatorBase::~KItemListCreatorBase() { qDeleteAll(m_recycleableWidgets); diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 974a9baaf..e874957de 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -37,6 +37,7 @@ class KItemListWidgetCreatorBase; class KItemListGroupHeader; class KItemListGroupHeaderCreatorBase; class KItemListSizeHintResolver; +class KItemListRubberBand; class KItemListViewAnimation; class KItemListViewLayouter; class KItemListWidget; @@ -142,10 +143,15 @@ public: void endTransaction(); bool isTransactionActive() const; + /** + * @reimp + */ + virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); + signals: - void offsetChanged(int current, int previous); - void maximumOffsetChanged(int current, int previous); - void scrollTo(int newOffset); + void offsetChanged(qreal current, qreal previous); + void maximumOffsetChanged(qreal current, qreal previous); + void scrollTo(qreal newOffset); protected: virtual void initializeItemListWidget(KItemListWidget* item); @@ -164,6 +170,7 @@ protected: virtual bool event(QEvent* event); virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event); QList visibleItemListWidgets() const; @@ -180,6 +187,10 @@ private slots: KItemListViewAnimation::AnimationType type); void slotLayoutTimerFinished(); + void slotRubberBandStartPosChanged(); + void slotRubberBandEndPosChanged(); + void slotRubberBandActivationChanged(bool active); + private: enum LayoutAnimationHint { @@ -196,6 +207,8 @@ private: void setController(KItemListController* controller); void setModel(KItemModelBase* model); + KItemListRubberBand* rubberBand() const; + void updateLayout(); void doLayout(LayoutAnimationHint hint, int changedIndex, int changedCount); void doGroupHeadersLayout(LayoutAnimationHint hint, int changedIndex, int changedCount); @@ -241,7 +254,22 @@ private: */ void updateWidgetProperties(KItemListWidget* widget, int index); + /** + * Emits the signal scrollTo() with the corresponding target offset if the current + * mouse position is above the autoscroll-margin. + */ + void triggerAutoScrolling(); + + /** + * Helper function for triggerAutoScrolling(). Returns the scroll increment + * that should be added to the offset() based on the available size \a size + * and the current mouse position \a pos. As soon as \a pos is inside + * the autoscroll-margin a value != 0 will be returned. + */ + static int calculateAutoScrollingIncrement(int pos, int size); + private: + bool m_autoScrollMarginEnabled; bool m_grouped; int m_activeTransactions; // Counter for beginTransaction()/endTransaction() @@ -263,8 +291,12 @@ private: KItemListViewAnimation* m_animation; QTimer* m_layoutTimer; // Triggers an asynchronous doLayout() call. - int m_oldOffset; - int m_oldMaximumOffset; + qreal m_oldOffset; + qreal m_oldMaximumOffset; + + KItemListRubberBand* m_rubberBand; + + QPointF m_mousePos; friend class KItemListController; };