}
}
- doLayout(Animation);
+ doLayout(NoAnimation);
onScrollOrientationChanged(orientation, previousOrientation);
emit scrollOrientationChanged(orientation, previousOrientation);
return;
}
+ // Skip animations when the number of rows or columns
+ // are changed in the grid layout. Although the animation
+ // engine can handle this usecase, it looks obtrusive.
+ const bool animate = !changesItemGridLayout(m_layouter->size(), itemSize);
+
m_itemSize = itemSize;
if (itemSize.isEmpty()) {
}
m_sizeHintResolver->clearCache();
- doLayout(Animation);
+ doLayout(animate ? Animation : NoAnimation);
onItemSizeChanged(itemSize, previousSize);
}
}
updateVisibleRolesSizes();
- doLayout(Animation);
+ doLayout(NoAnimation);
onVisibleRolesChanged(roles, previousRoles);
}
m_layouter->setSize(newSize);
doLayout(Animation);
} else {
- // The item size is not dynamic and most probably the geometry change results
- // in animated position changes of the items. Trigger an asynchronous relayout
- // with m_layoutTimer to prevent performance bottlenecks.
+ const bool animate = !changesItemGridLayout(newSize, m_layouter->itemSize());
m_layouter->setSize(newSize);
- if (!m_layoutTimer->isActive()) {
- m_layoutTimer->start();
+
+ if (animate) {
+ // Trigger an asynchronous relayout with m_layoutTimer to prevent
+ // performance bottlenecks. If the timer is exceeded, an animated layout
+ // will be triggered.
+ if (!m_layoutTimer->isActive()) {
+ m_layoutTimer->start();
+ }
+ } else {
+ m_layoutTimer->stop();
+ doLayout(NoAnimation);
}
}
}
if (m_activeTransactions == 0) {
onTransactionEnd();
- doLayout(Animation);
+ doLayout(NoAnimation);
}
}
}
if (!hasMultipleRanges) {
- doLayout(Animation, index, count);
+ doLayout(animateChangedItemCount(count) ? Animation : NoAnimation, index, count);
}
}
continue;
}
- if (m_model->count() == 0) {
- // For performance reasons no animation is done when all items have
- // been removed.
+ if (m_model->count() == 0 || hasMultipleRanges || !animateChangedItemCount(count)) {
+ // Remove the widget without animation
recycleWidget(widget);
} else {
// Animate the removing of the items. Special case: When removing an item there
// geometry update if necessary.
const int activeTransactions = m_activeTransactions;
m_activeTransactions = 0;
- doLayout(Animation, index, -count);
+ doLayout(animateChangedItemCount(count) ? Animation : NoAnimation, index, -count);
m_activeTransactions = activeTransactions;
}
}
Q_ASSERT(m_visibleGroups.isEmpty());
}
- doLayout(Animation);
+ doLayout(NoAnimation);
}
void KItemListView::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous)
Q_UNUSED(previous);
if (m_grouped) {
updateVisibleGroupHeaders();
- doLayout(Animation);
+ doLayout(NoAnimation);
}
}
Q_UNUSED(previous);
if (m_grouped) {
updateVisibleGroupHeaders();
- doLayout(Animation);
+ doLayout(NoAnimation);
}
}
widget->setVisibleRolesSizes(m_stretchedVisibleRolesSizes);
}
- doLayout(Animation);
+ doLayout(NoAnimation);
}
}
const int lastVisibleIndex = m_layouter->lastVisibleIndex();
- QList<int> reusableItems = recycleInvisibleItems(firstVisibleIndex, lastVisibleIndex);
+ QList<int> reusableItems = recycleInvisibleItems(firstVisibleIndex, lastVisibleIndex, hint);
// Assure that for each visible item a KItemListWidget is available. KItemListWidget
// instances from invisible items are reused. If no reusable items are
applyNewPos = false;
}
} else if (m_animation->isStarted(widget, KItemListViewAnimation::MovingAnimation)) {
- applyNewPos = false;
+ if (animate) {
+ applyNewPos = false;
+ } else {
+ m_animation->stop(widget);
+ }
}
if (animate) {
emitOffsetChanges();
}
-QList<int> KItemListView::recycleInvisibleItems(int firstVisibleIndex, int lastVisibleIndex)
+QList<int> KItemListView::recycleInvisibleItems(int firstVisibleIndex,
+ int lastVisibleIndex,
+ LayoutAnimationHint hint)
{
// Determine all items that are completely invisible and might be
- // reused for items that just got (at least partly) visible.
- // Items that do e.g. an animated moving of their position are not
- // marked as invisible: This assures that a scrolling inside the view
- // can be done without breaking an animation.
+ // reused for items that just got (at least partly) visible. If the
+ // animation hint is set to 'Animation' items that do e.g. an animated
+ // moving of their position are not marked as invisible: This assures
+ // that a scrolling inside the view can be done without breaking an animation.
QList<int> items;
QHashIterator<int, KItemListWidget*> it(m_visibleItems);
while (it.hasNext()) {
it.next();
+
KItemListWidget* widget = it.value();
const int index = widget->index();
const bool invisible = (index < firstVisibleIndex) || (index > lastVisibleIndex);
- if (invisible && !m_animation->isStarted(widget)) {
- widget->setVisible(false);
- items.append(index);
- if (m_grouped) {
- recycleGroupHeaderForWidget(widget);
+ if (invisible) {
+ if (m_animation->isStarted(widget)) {
+ if (hint == NoAnimation) {
+ // Stopping the animation will call KItemListView::slotAnimationFinished()
+ // and the widget will be recycled if necessary there.
+ m_animation->stop(widget);
+ }
+ } else {
+ widget->setVisible(false);
+ items.append(index);
+
+ if (m_grouped) {
+ recycleGroupHeaderForWidget(widget);
+ }
}
}
}
return false;
}
- bool startMovingAnim = m_itemSize.isEmpty();
+ bool startMovingAnim = m_itemSize.isEmpty() || widget->size() != itemBounds.size();
if (!startMovingAnim) {
// When having a grid the moving-animation should only be started, if it is done within
// one row in the vertical scroll-orientation or one column in the horizontal scroll-orientation.
// Otherwise instead of a moving-animation a create-animation on the new position will be used
// instead. This is done to prevent overlapping (and confusing) moving-animations.
-
- int zoomDiff = 0;
- if (widget->size() != itemBounds.size()) {
- // The item-size has been increased or decreased
- const bool zoomOut = (widget->size().width() >= itemBounds.size().width()) &&
- (widget->size().height() >= itemBounds.size().height());
- zoomDiff = zoomOut ? -1 : +1;
- }
-
const qreal xMax = m_itemSize.width();
const qreal yMax = m_itemSize.height();
- qreal xDiff = oldPos.x() - newPos.x();
- qreal yDiff = oldPos.y() - newPos.y();
+ qreal xDiff = qAbs(oldPos.x() - newPos.x());
+ qreal yDiff = qAbs(oldPos.y() - newPos.y());
if (scrollOrientation() == Qt::Vertical) {
- if (zoomDiff != 0) {
- // Skip moving animations that changed the row
- startMovingAnim = (zoomDiff > 0 && xDiff < xMax) ||
- (zoomDiff < 0 && -xDiff < xMax);
- } else {
- xDiff = qAbs(xDiff);
- yDiff = qAbs(yDiff);
- startMovingAnim = (xDiff > yDiff && yDiff < yMax);
- }
+ startMovingAnim = (xDiff > yDiff && yDiff < yMax);
} else {
- if (zoomDiff != 0) {
- // Skip moving animations that changed the column
- startMovingAnim = (zoomDiff > 0 && yDiff < yMax) ||
- (zoomDiff < 0 && -yDiff < yMax);
- } else {
- xDiff = qAbs(xDiff);
- yDiff = qAbs(yDiff);
- startMovingAnim = (yDiff > xDiff && xDiff < xMax);
- }
+ startMovingAnim = (yDiff > xDiff && xDiff < xMax);
}
}
return m_header ? m_header->geometry() : QRectF();
}
+bool KItemListView::changesItemGridLayout(const QSizeF& newGridSize, const QSizeF& newItemSize) const
+{
+ if (newItemSize.isEmpty() || newGridSize.isEmpty()) {
+ return false;
+ }
+
+ if (m_layouter->scrollOrientation() == Qt::Vertical) {
+ const qreal itemWidth = m_layouter->itemSize().width();
+ if (itemWidth > 0) {
+ const int oldColumnCount = m_layouter->size().width() / itemWidth;
+ const int newColumnCount = newGridSize.width() / newItemSize.width();
+ return oldColumnCount != newColumnCount;
+ }
+ } else {
+ const qreal itemHeight = m_layouter->itemSize().height();
+ if (itemHeight > 0) {
+ const int oldRowCount = m_layouter->size().height() / itemHeight;
+ const int newRowCount = newGridSize.height() / newItemSize.height();
+ return oldRowCount != newRowCount;
+ }
+ }
+
+ return false;
+}
+
+bool KItemListView::animateChangedItemCount(int changedItemCount) const
+{
+ if (m_layouter->size().isEmpty() || m_layouter->itemSize().isEmpty()) {
+ return false;
+ }
+
+ const int maximum = (scrollOrientation() == Qt::Vertical)
+ ? m_layouter->size().width() / m_layouter->itemSize().width()
+ : m_layouter->size().height() / m_layouter->itemSize().height();
+ // Only animate if up to 2/3 of a row or column are inserted or removed
+ return changedItemCount <= maximum * 2 / 3;
+}
+
int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc)
{
int inc = 0;