// INTERNAL INCLUDES
#include <dali/public-api/events/mouse-wheel-event.h>
#include <dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h>
+#include <dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h>
#include <dali-toolkit/internal/controls/scrollable/scroll-connector-impl.h>
using namespace std;
const float DEFAULT_MINIMUM_SWIPE_DISTANCE = 3.0f;
const float DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f;
-const int DEFAULT_REFRESH_INTERVAL_MILLISECONDS = 50; // 20 updates per second
+const float DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS = 20.0f; // 1 updates per 20 items
const int MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT = 500; // 0.5 second
const float DEFAULT_ANCHORING_DURATION = 1.0f; // 1 second
mAnimateOvershootOff(false),
mAnchoringEnabled(true),
mAnchoringDuration(DEFAULT_ANCHORING_DURATION),
- mRefreshIntervalMilliseconds(DEFAULT_REFRESH_INTERVAL_MILLISECONDS),
+ mRefreshIntervalLayoutPositions(DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS),
mRefreshOrderHint(true/*Refresh item 0 first*/),
mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED),
mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE),
mTotalPanDisplacement(Vector2::ZERO),
mScrollOvershoot(0.0f),
mIsFlicking(false),
- mGestureState(Gesture::Clear)
+ mGestureState(Gesture::Clear),
+ mAddingItems(false)
{
SetRequiresMouseWheelEvents(true);
SetKeyboardNavigationSupport(true);
mMouseWheelEventFinishedTimer = Timer::New( MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT );
mMouseWheelEventFinishedTimer.TickSignal().Connect( this, &ItemView::OnMouseWheelEventFinished );
+
+ SetRefreshInterval(mRefreshIntervalLayoutPositions);
}
ItemView::~ItemView()
mActiveLayout = NULL;
}
-
- CancelRefreshTimer();
}
void ItemView::SetDefaultAlphaFunction(AlphaFunction func)
return mDefaultAlphaFunction;
}
-bool ItemView::OnRefreshTick()
+void ItemView::OnRefreshNotification(PropertyNotification& source)
{
- // Short-circuit if there is no active layout
- if (!mActiveLayout)
+ if (mActiveLayout)
{
- return false;
- }
-
- ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, true/*reserve extra*/);
+ ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, true/*reserve extra*/);
+ RemoveActorsOutsideRange( range );
+ AddActorsWithinRange( range, 0.0f/*immediate*/ );
- RemoveActorsOutsideRange( range );
-
- AddActorsWithinRange( range, 0.0f/*immediate*/ );
-
- // Keep refreshing whilst the layout is moving
- return mScrollAnimation || (mGestureState == Gesture::Started || mGestureState == Gesture::Continuing);
+ Vector3 currentScrollPosition = GetCurrentScrollPosition();
+ mScrollUpdatedSignalV2.Emit( currentScrollPosition );
+ }
}
void ItemView::SetMinimumSwipeSpeed(float speed)
return mAnchoringDuration;
}
-void ItemView::SetRefreshInterval(unsigned int intervalMilliseconds)
+void ItemView::SetRefreshInterval(float intervalLayoutPositions)
{
- mRefreshIntervalMilliseconds = intervalMilliseconds;
+ mRefreshIntervalLayoutPositions = intervalLayoutPositions;
+
+ if(mRefreshNotification)
+ {
+ mScrollPositionObject.RemovePropertyNotification(mRefreshNotification);
+ }
+ mRefreshNotification = mScrollPositionObject.AddPropertyNotification( ScrollConnector::SCROLL_POSITION, StepCondition(mRefreshIntervalLayoutPositions, 0.0f) );
+ mRefreshNotification.NotifySignal().Connect( this, &ItemView::OnRefreshNotification );
}
-unsigned int ItemView::GetRefreshInterval() const
+float ItemView::GetRefreshInterval() const
{
- return mRefreshIntervalMilliseconds;
+ return mRefreshIntervalLayoutPositions;
}
Actor ItemView::GetItem(unsigned int itemId) const
void ItemView::InsertItem( Item newItem, float durationSeconds )
{
+ mAddingItems = true;
+
SetupActor( newItem, durationSeconds );
Self().Add( newItem.second );
{
mItemPool.insert( newItem );
}
+
+ CalculateDomainSize(Self().GetCurrentSize());
+
+ mAddingItems = false;
}
void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds )
{
+ mAddingItems = true;
+
// Insert from lowest id to highest
set<Item> sortedItems;
for( ConstItemIter iter = newItems.begin(); newItems.end() != iter; ++iter )
ApplyConstraints( iter->second, *mActiveLayout, iter->first, durationSeconds );
}
}
+
+ CalculateDomainSize(Self().GetCurrentSize());
+
+ mAddingItems = false;
}
void ItemView::RemoveItem( unsigned int itemId, float durationSeconds )
void ItemView::ReplaceItem( Item replacementItem, float durationSeconds )
{
+ mAddingItems = true;
+
SetupActor( replacementItem, durationSeconds );
Self().Add( replacementItem.second );
{
mItemPool.insert( replacementItem );
}
+
+ CalculateDomainSize(Self().GetCurrentSize());
+
+ mAddingItems = false;
}
void ItemView::ReplaceItems( const ItemContainer& replacementItems, float durationSeconds )
AddNewActor( itemId-1, durationSeconds );
}
}
+
+ // Total number of items may change dynamically.
+ // Always recalculate the domain size to reflect that.
+ CalculateDomainSize(Self().GetCurrentSize());
}
void ItemView::AddNewActor( unsigned int itemId, float durationSeconds )
{
+ mAddingItems = true;
+
if( mItemPool.end() == mItemPool.find( itemId ) )
{
Actor actor = mItemFactory.NewItem( itemId );
Self().Add( actor );
}
}
+
+ mAddingItems = false;
}
void ItemView::SetupActor( Item item, float durationSeconds )
return range.Intersection(available);
}
+void ItemView::OnChildAdd(Actor& child)
+{
+ if(!mAddingItems)
+ {
+ // We don't want to do this downcast check for any item added by ItemView itself.
+ Dali::Toolkit::ScrollBar scrollBar = Dali::Toolkit::ScrollBar::DownCast(child);
+ if(scrollBar)
+ {
+ // Set the scroll connector when scroll bar is being added
+ scrollBar.SetScrollConnector(mScrollConnector);
+ }
+ }
+}
+
bool ItemView::OnTouchEvent(const TouchEvent& event)
{
// Ignore events with multiple-touch points
mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
- StartRefreshTimer();
}
if (mMouseWheelEventFinishedTimer.IsRunning())
mScrollAnimation = DoAnchoring();
if (mScrollAnimation)
{
- StartRefreshTimer();
-
mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
mScrollAnimation.Play();
}
{
AnimateScrollOvershoot(0.0f);
}
-
- StartRefreshTimer();
}
break;
if (mScrollAnimation)
{
- StartRefreshTimer();
-
mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
mScrollAnimation.Play();
}
}
}
-void ItemView::StartRefreshTimer()
-{
- if (!mRefreshTimer)
- {
- mRefreshTimer = Timer::New( mRefreshIntervalMilliseconds );
- mRefreshTimer.TickSignal().Connect( this, &ItemView::OnRefreshTick );
- }
-
- if (!mRefreshTimer.IsRunning())
- {
- mRefreshTimer.Start();
- }
-}
-
-void ItemView::CancelRefreshTimer()
-{
- if (mRefreshTimer)
- {
- mRefreshTimer.Stop();
- }
-}
-
void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
{
Actor self = Self();
const Vector3 layoutSize = Self().GetCurrentSize();
float firstItemScrollPosition = ClampFirstItemPosition(mActiveLayout->GetItemScrollToPosition(itemId), layoutSize, *mActiveLayout);
- StartRefreshTimer();
-
if(durationSeconds > 0.0f)
{
RemoveAnimation(mScrollAnimation);
}
float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize);
+ self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
+
ItemLayout::Vector3Function lastItemPositionConstraint;
if (mActiveLayout->GetPositionConstraint(fabs(minLayoutPosition), lastItemPositionConstraint))
{
lastItemPosition = lastItemPositionConstraint(Vector3::ZERO, fabs(minLayoutPosition), 0.0f, layoutSize);
}
+ float domainSize;
+
if(IsHorizontal(mActiveLayout->GetOrientation()))
{
self.SetProperty(mPropertyPositionMin, Vector3(0.0f, firstItemPosition.x, 0.0f));
self.SetProperty(mPropertyPositionMax, Vector3(0.0f, lastItemPosition.x, 0.0f));
+ domainSize = fabs(firstItemPosition.x - lastItemPosition.x);
}
else
{
self.SetProperty(mPropertyPositionMin, Vector3(0.0f, firstItemPosition.y, 0.0f));
self.SetProperty(mPropertyPositionMax, Vector3(0.0f, lastItemPosition.y, 0.0f));
+ domainSize = fabs(firstItemPosition.y - lastItemPosition.y);
}
+ mScrollConnector.SetScrollDomain(minLayoutPosition, 0.0f, domainSize);
+
bool isLayoutScrollable = IsLayoutScrollable(layoutSize);
self.SetProperty(mPropertyCanScrollVertical, isLayoutScrollable);
self.SetProperty(mPropertyCanScrollHorizontal, false);
float firstItemScrollPosition = ClampFirstItemPosition(position.y, layoutSize, *mActiveLayout);
- StartRefreshTimer();
-
if(duration > 0.0f)
{
RemoveAnimation(mScrollAnimation);