From 3596419631a942b0522e035117321b65c66d2ac0 Mon Sep 17 00:00:00 2001 From: Paul Wisbey Date: Fri, 12 Dec 2014 10:11:51 +0000 Subject: [PATCH] Fix ItemView insert/remove when outside the current visible range [problem] Items are not always repositioned correctly after an insert/remove [cause] Inserting/removing before the currently visible items is not supported [solution] Add additional logic to the InsertItem method Change-Id: I3754506048e1bfe1544cb24a2421e66e8052b37a --- .../scrollable/item-view/item-view-impl.cpp | 89 +++++++++++++++++----- .../controls/scrollable/item-view/item-view-impl.h | 7 +- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp b/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp index 231f85c..345a247 100644 --- a/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp +++ b/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp @@ -686,21 +686,42 @@ void ItemView::InsertItem( Item newItem, float durationSeconds ) { mAddingItems = true; - SetupActor( newItem, durationSeconds ); - Self().Add( newItem.second ); + Actor displacedActor; + ItemPoolIter afterDisplacedIter = mItemPool.end(); ItemPoolIter foundIter = mItemPool.find( newItem.first ); if( mItemPool.end() != foundIter ) { - Actor moveMe = foundIter->second; + SetupActor( newItem, durationSeconds ); + Self().Add( newItem.second ); + + displacedActor = foundIter->second; foundIter->second = newItem.second; + afterDisplacedIter = ++foundIter; + } + else + { + // Inserting before the existing item range? + ItemPoolIter iter = mItemPool.begin(); + if( iter != mItemPool.end() && + iter->first > newItem.first ) + { + displacedActor = iter->second; + mItemPool.erase( iter++ ); // iter is still valid after the erase + + afterDisplacedIter = iter; + } + } + + if( displacedActor ) + { // Move the existing actors to make room - for( ItemPoolIter iter = ++foundIter; mItemPool.end() != iter; ++iter ) + for( ItemPoolIter iter = afterDisplacedIter; mItemPool.end() != iter; ++iter ) { Actor temp = iter->second; - iter->second = moveMe; - moveMe = temp; + iter->second = displacedActor; + displacedActor = temp; iter->second.RemoveConstraints(); mActiveLayout->ApplyConstraints(iter->second, iter->first, durationSeconds, mScrollPositionObject, Self() ); @@ -708,16 +729,12 @@ void ItemView::InsertItem( Item newItem, float durationSeconds ) // Create last item ItemId lastId = mItemPool.rbegin()->first; - Item lastItem( lastId + 1, moveMe ); + Item lastItem( lastId + 1, displacedActor ); mItemPool.insert( lastItem ); lastItem.second.RemoveConstraints(); mActiveLayout->ApplyConstraints(lastItem.second, lastItem.first, durationSeconds, mScrollPositionObject, Self() ); } - else - { - mItemPool.insert( newItem ); - } CalculateDomainSize(Self().GetCurrentSize()); @@ -786,16 +803,18 @@ void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds void ItemView::RemoveItem( unsigned int itemId, float durationSeconds ) { - bool actorRemoved = RemoveActor( itemId ); - if( actorRemoved ) + bool actorsReordered = RemoveActor( itemId ); + if( actorsReordered ) { ReapplyAllConstraints( durationSeconds ); + + OnItemsRemoved(); } } void ItemView::RemoveItems( const ItemIdContainer& itemIds, float durationSeconds ) { - bool actorRemoved( false ); + bool actorsReordered( false ); // Remove from highest id to lowest set sortedItems; @@ -808,27 +827,44 @@ void ItemView::RemoveItems( const ItemIdContainer& itemIds, float durationSecond { if( RemoveActor( *iter ) ) { - actorRemoved = true; + actorsReordered = true; } } - if( actorRemoved ) + if( actorsReordered ) { ReapplyAllConstraints( durationSeconds ); + + OnItemsRemoved(); } } bool ItemView::RemoveActor(unsigned int itemId) { - bool removed( false ); - - const ItemPoolIter removeIter = mItemPool.find( itemId ); + bool reordered( false ); + ItemPoolIter removeIter = mItemPool.find( itemId ); if( removeIter != mItemPool.end() ) { ReleaseActor(itemId, removeIter->second); + } + else + { + // Removing before the existing item range? + ItemPoolIter iter = mItemPool.begin(); + if( iter != mItemPool.end() && + iter->first > itemId ) + { + // In order to decrement the first visible item ID + mItemPool.insert( Item(iter->first - 1, Actor()) ); + + removeIter = mItemPool.begin(); + } + } - removed = true; + if( removeIter != mItemPool.end() ) + { + reordered = true; // Adjust the remaining item IDs, for example if item 2 is removed: // Initial actors: After insert: @@ -850,7 +886,7 @@ bool ItemView::RemoveActor(unsigned int itemId) } } - return removed; + return reordered; } void ItemView::ReplaceItem( Item replacementItem, float durationSeconds ) @@ -1099,8 +1135,19 @@ void ItemView::ReapplyAllConstraints( float durationSeconds ) actor.RemoveConstraints(); mActiveLayout->ApplyConstraints(actor, id, durationSeconds, mScrollPositionObject, Self()); } +} +void ItemView::OnItemsRemoved() +{ CalculateDomainSize(Self().GetCurrentSize()); + + // Adjust scroll-position after an item is removed + if( mActiveLayout ) + { + float firstItemScrollPosition = ClampFirstItemPosition(GetCurrentLayoutPosition(0), Self().GetCurrentSize(), *mActiveLayout); + + mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition ); + } } float ItemView::ClampFirstItemPosition(float targetPosition, const Vector3& targetSize, ItemLayout& layout) diff --git a/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h b/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h index dba4629..51bb3ae 100644 --- a/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h +++ b/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h @@ -289,7 +289,7 @@ private: /** * Remove an Actor if found in the ItemPool. * @param[in] itemId The item to remove. - * @return True if an actor was removed. + * @return True if the remaining actors were reordered. */ bool RemoveActor( unsigned int itemId ); @@ -399,6 +399,11 @@ private: void ReapplyAllConstraints( float durationSeconds ); /** + * Helper to relayout after item(s) are removed. + */ + void OnItemsRemoved(); + + /** * Helper to remove items outside a given range. * @param[in] range The range of required items. */ -- 2.7.4