X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Fscrollable%2Fitem-view%2Fitem-view-impl.cpp;h=a181c9a52bf9e5976d90322db65fb589150af0c7;hp=9ad835ff42b6cd17e25c0ee5cfd1f210d8993fc9;hb=be93fd772a1b1b09425ac0aaec1ea1b64e9a9e60;hpb=3bdbf66c314bb6036eb35ec0d2f1c9c32652f931 diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp index 9ad835f..939ab67 100644 --- a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,58 +19,54 @@ #include // EXTERNAL INCLUDES +#include // for strcmp #include +#include + #include #include -#include -#include -#include +#include +#include #include #include #include +#include // INTERNAL INCLUDES +#include #include +#include +#include +#include +#include +#include #include -#include using std::string; -using std::set; using namespace Dali; namespace // Unnamed namespace { -//Type registration - -DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL ) -DALI_TYPE_REGISTRATION_END() - const float DEFAULT_MINIMUM_SWIPE_SPEED = 1.0f; const float DEFAULT_MINIMUM_SWIPE_DISTANCE = 3.0f; -const float DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f; +const float DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f; const float DEFAULT_MINIMUM_SWIPE_DURATION = 0.45f; const float DEFAULT_MAXIMUM_SWIPE_DURATION = 2.6f; 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 int WHEEL_EVENT_FINISHED_TIME_OUT = 500; // 0.5 second const float DEFAULT_ANCHORING_DURATION = 1.0f; // 1 second const float MILLISECONDS_PER_SECONDS = 1000.0f; -const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f ); const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f; const Vector4 OVERSHOOT_OVERLAY_NINE_PATCH_BORDER(0.0f, 0.0f, 1.0f, 12.0f); const float DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION = 0.2f; -const string LAYOUT_POSITION_PROPERTY_NAME( "item-view-layout-position" ); -const string POSITION_PROPERTY_NAME( "item-view-position" ); -const string MINIMUM_LAYOUT_POSITION_PROPERTY_NAME( "item-view-minimum-layout-position" ); -const string SCROLL_SPEED_PROPERTY_NAME( "item-view-scroll-speed" ); -const string SCROLL_DIRECTION_PROPERTY_NAME( "item-view-scroll-direction" ); -const string OVERSHOOT_PROPERTY_NAME( "item-view-overshoot" ); +const unsigned int OVERSHOOT_SIZE_CONSTRAINT_TAG(42); /** * Local helper to convert pan distance (in actor coordinates) to the layout-specific scrolling direction @@ -86,37 +82,47 @@ float CalculateScrollDistance(Vector2 panDistance, Toolkit::ItemLayout& layout) } // Overshoot overlay constraints -void OvershootOverlaySizeConstraint( Vector3& current, const PropertyInputContainer& inputs ) +struct OvershootOverlaySizeConstraint { - const Vector3& parentScrollDirection = inputs[0]->GetVector3(); - const Vector3& parentSize = inputs[1]->GetVector3(); - const Toolkit::ControlOrientation::Type& parentOrientation = static_cast(parentScrollDirection.z); - - if(Toolkit::IsVertical(parentOrientation)) + OvershootOverlaySizeConstraint( float height ) + : mOvershootHeight( height ) { - current.width = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y; } - else + + void operator()( Vector3& current, const PropertyInputContainer& inputs ) { - current.width = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x; + const Vector2& parentScrollDirection = inputs[0]->GetVector2(); + const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast(inputs[1]->GetInteger()); + const Vector3& parentSize = inputs[2]->GetVector3(); + + if(Toolkit::IsVertical(layoutOrientation)) + { + current.width = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y; + } + else + { + current.width = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x; + } + + current.height = ( current.width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD ) ? mOvershootHeight : mOvershootHeight*0.5f; } - current.height = ( current.width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD ) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height*0.5f; -} + float mOvershootHeight; +}; void OvershootOverlayRotationConstraint( Quaternion& current, const PropertyInputContainer& inputs ) { - const Vector3& parentScrollDirection = inputs[0]->GetVector3(); - const float parentOvershoot = inputs[1]->GetFloat(); - const Toolkit::ControlOrientation::Type& parentOrientation = static_cast(parentScrollDirection.z); + const Vector2& parentScrollDirection = inputs[0]->GetVector2(); + const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast(inputs[1]->GetInteger()); + const float parentOvershoot = inputs[2]->GetFloat(); float multiplier = 0; - if(Toolkit::IsVertical(parentOrientation)) + if(Toolkit::IsVertical(layoutOrientation)) { if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1) { - if( (parentOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0) - || (parentOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) ) + if( (layoutOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0) + || (layoutOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) ) { multiplier = 0.5f; } @@ -139,8 +145,8 @@ void OvershootOverlayRotationConstraint( Quaternion& current, const PropertyInpu { if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1) { - if( (parentOrientation == Toolkit::ControlOrientation::Left && parentOvershoot > Math::MACHINE_EPSILON_0) - ||(parentOrientation == Toolkit::ControlOrientation::Right && parentOvershoot < Math::MACHINE_EPSILON_0) ) + if( (layoutOrientation == Toolkit::ControlOrientation::Left && parentOvershoot > Math::MACHINE_EPSILON_0) + ||(layoutOrientation == Toolkit::ControlOrientation::Right && parentOvershoot < Math::MACHINE_EPSILON_0) ) { multiplier = 1.0f; } @@ -166,18 +172,18 @@ void OvershootOverlayRotationConstraint( Quaternion& current, const PropertyInpu void OvershootOverlayPositionConstraint( Vector3& current, const PropertyInputContainer& inputs ) { const Vector3& parentSize = inputs[0]->GetVector3(); - const Vector3& parentScrollDirection = inputs[1]->GetVector3(); - const float parentOvershoot = inputs[2]->GetFloat(); - const Toolkit::ControlOrientation::Type& parentOrientation = static_cast(parentScrollDirection.z); + const Vector2& parentScrollDirection = inputs[1]->GetVector2(); + const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast(inputs[2]->GetInteger()); + const float parentOvershoot = inputs[3]->GetFloat(); Vector3 relativeOffset; - if(Toolkit::IsVertical(parentOrientation)) + if(Toolkit::IsVertical(layoutOrientation)) { if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1) { - if( (parentOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0) - || (parentOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) ) + if( (layoutOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0) + || (layoutOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) ) { relativeOffset = Vector3(1.0f, 0.0f, 0.0f); } @@ -200,8 +206,8 @@ void OvershootOverlayPositionConstraint( Vector3& current, const PropertyInputCo { if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1) { - if( (parentOrientation == Toolkit::ControlOrientation::Left && parentOvershoot < Math::MACHINE_EPSILON_0) - || (parentOrientation == Toolkit::ControlOrientation::Right && parentOvershoot > Math::MACHINE_EPSILON_0) ) + if( (layoutOrientation == Toolkit::ControlOrientation::Left && parentOvershoot < Math::MACHINE_EPSILON_0) + || (layoutOrientation == Toolkit::ControlOrientation::Right && parentOvershoot > Math::MACHINE_EPSILON_0) ) { relativeOffset = Vector3(0.0f, 0.0f, 0.0f); } @@ -229,24 +235,6 @@ void OvershootOverlayVisibilityConstraint( bool& current, const PropertyInputCon current = inputs[0]->GetBoolean(); } -/** - * Relative position Constraint - * Generates the relative position value of the item view based on the layout position, - * and it's relation to the layout domain. This is a value from 0.0f to 1.0f in each axis. - */ -void RelativePositionConstraint( Vector3& current, const PropertyInputContainer& inputs ) -{ - const Vector3& position = Vector3(0.0f, inputs[0]->GetFloat(), 0.0f); - const Vector3& min = inputs[1]->GetVector3(); - const Vector3& max = inputs[2]->GetVector3(); - - Vector3 domainSize = max - min; - - current.x = fabsf(domainSize.x) > Math::MACHINE_EPSILON_1 ? ((min.x - position.x) / fabsf(domainSize.x)) : 0.0f; - current.y = fabsf(domainSize.y) > Math::MACHINE_EPSILON_1 ? ((min.y - position.y) / fabsf(domainSize.y)) : 0.0f; - current.z = 0.0f; -} - } // unnamed namespace namespace Dali @@ -261,17 +249,70 @@ namespace Internal namespace // unnamed namespace { -bool FindById( const ItemContainer& items, ItemId id ) +//Type registration + +DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL) + +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeSpeed", FLOAT, MINIMUM_SWIPE_SPEED ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeDistance", FLOAT, MINIMUM_SWIPE_DISTANCE ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "wheelScrollDistanceStep", FLOAT, WHEEL_SCROLL_DISTANCE_STEP ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "snapToItemEnabled", BOOLEAN, SNAP_TO_ITEM_ENABLED ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "refreshInterval", FLOAT, REFRESH_INTERVAL ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "layout", ARRAY, LAYOUT ) + + +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutPosition", FLOAT, LAYOUT_POSITION) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollSpeed", FLOAT, SCROLL_SPEED) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "overshoot", FLOAT, OVERSHOOT) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollDirection", VECTOR2, SCROLL_DIRECTION) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutOrientation", INTEGER, LAYOUT_ORIENTATION) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollContentSize", FLOAT, SCROLL_CONTENT_SIZE) + +DALI_SIGNAL_REGISTRATION( Toolkit, ItemView, "layoutActivated", LAYOUT_ACTIVATED_SIGNAL ) + +DALI_ACTION_REGISTRATION( Toolkit, ItemView, "stopScrolling", ACTION_STOP_SCROLLING ) + +DALI_ACTION_REGISTRATION( Toolkit, ItemView, "enableRefresh", ACTION_ENABLE_REFRESH ) +DALI_ACTION_REGISTRATION( Toolkit, ItemView, "disableRefresh", ACTION_DISABLE_REFRESH ) + +DALI_TYPE_REGISTRATION_END() + +const ItemIter FindItemById( ItemContainer& items, ItemId id ) { - for( ConstItemIter iter = items.begin(); items.end() != iter; ++iter ) + for( ItemIter iter = items.begin(); items.end() != iter; ++iter ) { if( iter->first == id ) { - return true; + return iter; } } - return false; + return items.end(); +} + +void InsertToItemContainer( ItemContainer& items, Item item ) +{ + if( items.end() == FindItemById( items, item.first ) ) + { + ItemIter iterToInsert = std::lower_bound( items.begin(), items.end(), item ); + items.insert( iterToInsert, item ); + } +} + + +/** + * Helper to apply size constraint to mOvershootOverlay + * @param[in] overshootOverlay The overshootOverlay actor + * @param[in] The required height + */ +void ApplyOvershootSizeConstraint( Actor overshootOverlay, float height ) +{ + Constraint constraint = Constraint::New( overshootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint( height ) ); + constraint.AddSource( ParentSource( Dali::Toolkit::ItemView::Property::SCROLL_DIRECTION ) ); + constraint.AddSource( ParentSource( Dali::Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) ); + constraint.AddSource( ParentSource( Dali::Actor::Property::SIZE ) ); + constraint.SetTag( OVERSHOOT_SIZE_CONSTRAINT_TAG ); + constraint.Apply(); } } // unnamed namespace @@ -292,66 +333,45 @@ Dali::Toolkit::ItemView ItemView::New(ItemFactory& factory) } ItemView::ItemView(ItemFactory& factory) -: Scrollable(), +: Scrollable( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS | REQUIRES_WHEEL_EVENTS | REQUIRES_KEYBOARD_NAVIGATION_SUPPORT ) ), mItemFactory(factory), + mItemsParentOrigin(ParentOrigin::CENTER), + mItemsAnchorPoint(AnchorPoint::CENTER), + mTotalPanDisplacement(Vector2::ZERO), mActiveLayout(NULL), - mAnimatingOvershootOn(false), - mAnimateOvershootOff(false), - mAnchoringEnabled(true), mAnchoringDuration(DEFAULT_ANCHORING_DURATION), mRefreshIntervalLayoutPositions(0.0f), - mRefreshOrderHint(true/*Refresh item 0 first*/), mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED), mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE), - mMouseWheelScrollDistanceStep(0.0f), + mWheelScrollDistanceStep(0.0f), mScrollDistance(0.0f), mScrollSpeed(0.0f), - mTotalPanDisplacement(Vector2::ZERO), mScrollOvershoot(0.0f), - mIsFlicking(false), mGestureState(Gesture::Clear), + mAnimatingOvershootOn(false), + mAnimateOvershootOff(false), + mAnchoringEnabled(false), + mRefreshOrderHint(true/*Refresh item 0 first*/), + mIsFlicking(false), mAddingItems(false), - mPropertyPosition(Property::INVALID_INDEX), - mPropertyMinimumLayoutPosition(Property::INVALID_INDEX), - mPropertyScrollSpeed(Property::INVALID_INDEX), mRefreshEnabled(true), - mItemsParentOrigin( ParentOrigin::CENTER), - mItemsAnchorPoint( AnchorPoint::CENTER) + mRefreshNotificationEnabled(true), + mInAnimation(false) { - SetRequiresMouseWheelEvents(true); - SetKeyboardNavigationSupport(true); } void ItemView::OnInitialize() { Actor self = Self(); - // Disable size negotiation for item views - self.SetRelayoutEnabled( false ); - - mScrollConnector = Dali::Toolkit::ScrollConnector::New(); - mScrollPositionObject = mScrollConnector.GetScrollPositionObject(); - mScrollConnector.ScrollPositionChangedSignal().Connect( this, &ItemView::OnScrollPositionChanged ); - - mPropertyMinimumLayoutPosition = self.RegisterProperty(MINIMUM_LAYOUT_POSITION_PROPERTY_NAME, 0.0f); - mPropertyPosition = self.RegisterProperty(POSITION_PROPERTY_NAME, 0.0f); - mPropertyScrollSpeed = self.RegisterProperty(SCROLL_SPEED_PROPERTY_NAME, 0.0f); - - EnableScrollComponent(Toolkit::Scrollable::OvershootIndicator); - - Constraint constraint = Constraint::New( self, Toolkit::Scrollable::Property::SCROLL_RELATIVE_POSITION, RelativePositionConstraint ); - constraint.AddSource( LocalSource( mPropertyPosition ) ); - constraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) ); - constraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) ); - constraint.Apply(); - Vector2 stageSize = Stage::GetCurrent().GetSize(); - mMouseWheelScrollDistanceStep = stageSize.y * DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION; + mWheelScrollDistanceStep = stageSize.y * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION; + self.TouchSignal().Connect( this, &ItemView::OnTouch ); EnableGestureDetection(Gesture::Type(Gesture::Pan)); - mMouseWheelEventFinishedTimer = Timer::New( MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT ); - mMouseWheelEventFinishedTimer.TickSignal().Connect( this, &ItemView::OnMouseWheelEventFinished ); + mWheelEventFinishedTimer = Timer::New( WHEEL_EVENT_FINISHED_TIME_OUT ); + mWheelEventFinishedTimer.TickSignal().Connect( this, &ItemView::OnWheelEventFinished ); SetRefreshInterval(DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS); } @@ -360,11 +380,6 @@ ItemView::~ItemView() { } -Dali::Toolkit::ScrollConnector ItemView::GetScrollConnector() const -{ - return mScrollConnector; -} - unsigned int ItemView::GetLayoutCount() const { return mLayouts.size(); @@ -399,7 +414,7 @@ ItemLayoutPtr ItemView::GetActiveLayout() const float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const { - return mScrollConnector.GetScrollPosition() + static_cast( itemId ); + return Self().GetCurrentProperty< float >( Toolkit::ItemView::Property::LAYOUT_POSITION ) + static_cast( itemId ); } void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds) @@ -411,7 +426,7 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz Actor self = Self(); // The ItemView size should match the active layout size - self.SetSize(targetSize); + self.SetProperty( Actor::Property::SIZE, targetSize); mActiveLayoutTargetSize = targetSize; // Switch to the new layout @@ -419,7 +434,7 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz // Move the items to the new layout positions... - for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) + for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) { unsigned int itemId = iter->first; Actor actor = iter->second; @@ -427,19 +442,16 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz // Remove constraints from previous layout actor.RemoveConstraints(); - Vector3 size; - if(mActiveLayout->GetItemSize(itemId, targetSize, size)) - { - // resize immediately - actor.SetSize( size.GetVectorXY() ); - } + mActiveLayout->ApplyConstraints(actor, itemId, targetSize, Self() ); - mActiveLayout->ApplyConstraints(actor, itemId, durationSeconds, mScrollPositionObject, Self() ); + Vector3 size; + mActiveLayout->GetItemSize( itemId, targetSize, size ); + actor.SetProperty( Actor::Property::SIZE, size.GetVectorXY() ); } // Refresh the new layout ItemRange range = GetItemRange(*mActiveLayout, targetSize, GetCurrentLayoutPosition(0), false/* don't reserve extra*/); - AddActorsWithinRange( range, durationSeconds ); + AddActorsWithinRange( range, targetSize ); // Scroll to an appropriate layout position @@ -448,7 +460,6 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz float current = GetCurrentLayoutPosition(0); float minimum = ClampFirstItemPosition(current, targetSize, *mActiveLayout); - self.SetProperty(mPropertyPosition, GetScrollPosition(current, targetSize)); if (current < minimum) { @@ -465,21 +476,23 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz { RemoveAnimation(mScrollAnimation); mScrollAnimation = Animation::New(durationSeconds); - mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut ); - mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, targetSize), AlphaFunctions::EaseOut ); + mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, AlphaFunction::EASE_OUT ); mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnLayoutActivationScrollFinished); mScrollAnimation.Play(); } + else + { + // Emit the layout activated signal + mLayoutActivatedSignal.Emit(); + } - self.SetProperty(mPropertyMinimumLayoutPosition, mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize)); AnimateScrollOvershoot(0.0f); mScrollOvershoot = 0.0f; Radian scrollDirection(mActiveLayout->GetScrollDirection()); - float orientation = static_cast(mActiveLayout->GetOrientation()); - self.SetProperty(Toolkit::Scrollable::Property::SCROLL_DIRECTION, Vector3(sinf(scrollDirection), cosf(scrollDirection), orientation)); - - self.SetProperty(mPropertyScrollSpeed, mScrollSpeed); + self.SetProperty(Toolkit::ItemView::Property::SCROLL_DIRECTION, Vector2(sinf(scrollDirection), cosf(scrollDirection))); + self.SetProperty(Toolkit::ItemView::Property::LAYOUT_ORIENTATION, static_cast(mActiveLayout->GetOrientation())); + self.SetProperty(Toolkit::ItemView::Property::SCROLL_SPEED, mScrollSpeed); CalculateDomainSize(targetSize); } @@ -488,7 +501,7 @@ void ItemView::DeactivateCurrentLayout() { if (mActiveLayout) { - for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) + for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) { Actor actor = iter->second; actor.RemoveConstraints(); @@ -500,16 +513,22 @@ void ItemView::DeactivateCurrentLayout() void ItemView::OnRefreshNotification(PropertyNotification& source) { - if(mRefreshEnabled || mScrollAnimation) + if( mRefreshNotificationEnabled ) { - // Only refresh the cache during normal scrolling - DoRefresh(GetCurrentLayoutPosition(0), true); + // Cancel scroll animation to prevent any fighting of setting the scroll position property by scroll bar during fast scroll. + if(!mRefreshEnabled && mScrollAnimation) + { + RemoveAnimation(mScrollAnimation); + } + + // Only cache extra items when it is not a fast scroll + DoRefresh(GetCurrentLayoutPosition(0), mRefreshEnabled || mScrollAnimation); } } void ItemView::Refresh() { - for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter ) + for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter ) { ReleaseActor( iter->first, iter->second ); } @@ -524,9 +543,9 @@ void ItemView::DoRefresh(float currentLayoutPosition, bool cacheExtra) { ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, currentLayoutPosition, cacheExtra/*reserve extra*/); RemoveActorsOutsideRange( range ); - AddActorsWithinRange( range, 0.0f/*immediate*/ ); + AddActorsWithinRange( range, Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) ); - mScrollUpdatedSignal.Emit( Vector3(0.0f, currentLayoutPosition, 0.0f) ); + mScrollUpdatedSignal.Emit( Vector2(0.0f, currentLayoutPosition) ); } } @@ -550,14 +569,14 @@ float ItemView::GetMinimumSwipeDistance() const return mMinimumSwipeDistance; } -void ItemView::SetMouseWheelScrollDistanceStep(float step) +void ItemView::SetWheelScrollDistanceStep(float step) { - mMouseWheelScrollDistanceStep = step; + mWheelScrollDistanceStep = step; } -float ItemView::GetMouseWheelScrollDistanceStep() const +float ItemView::GetWheelScrollDistanceStep() const { - return mMouseWheelScrollDistanceStep; + return mWheelScrollDistanceStep; } void ItemView::SetAnchoring(bool enabled) @@ -586,11 +605,12 @@ void ItemView::SetRefreshInterval(float intervalLayoutPositions) { mRefreshIntervalLayoutPositions = intervalLayoutPositions; + Actor self = Self(); if(mRefreshNotification) { - mScrollPositionObject.RemovePropertyNotification(mRefreshNotification); + self.RemovePropertyNotification(mRefreshNotification); } - mRefreshNotification = mScrollPositionObject.AddPropertyNotification( ScrollConnector::SCROLL_POSITION, StepCondition(mRefreshIntervalLayoutPositions, 0.0f) ); + mRefreshNotification = self.AddPropertyNotification( Toolkit::ItemView::Property::LAYOUT_POSITION, StepCondition(mRefreshIntervalLayoutPositions, 0.0f) ); mRefreshNotification.NotifySignal().Connect( this, &ItemView::OnRefreshNotification ); } } @@ -609,10 +629,13 @@ Actor ItemView::GetItem(unsigned int itemId) const { Actor actor; - ConstItemPoolIter iter = mItemPool.find( itemId ); - if( iter != mItemPool.end() ) + for ( ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter ) { - actor = iter->second; + if( iter->first == itemId ) + { + actor = iter->second; + break; + } } return actor; @@ -622,7 +645,7 @@ unsigned int ItemView::GetItemId( Actor actor ) const { unsigned int itemId( 0 ); - for ( ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter ) + for ( ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter ) { if( iter->second == actor ) { @@ -637,14 +660,15 @@ unsigned int ItemView::GetItemId( Actor actor ) const void ItemView::InsertItem( Item newItem, float durationSeconds ) { mAddingItems = true; + Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); Actor displacedActor; - ItemPoolIter afterDisplacedIter = mItemPool.end(); + ItemIter afterDisplacedIter = mItemPool.end(); - ItemPoolIter foundIter = mItemPool.find( newItem.first ); + ItemIter foundIter = FindItemById( mItemPool, newItem.first ); if( mItemPool.end() != foundIter ) { - SetupActor( newItem, durationSeconds ); + SetupActor( newItem, layoutSize ); Self().Add( newItem.second ); displacedActor = foundIter->second; @@ -655,12 +679,12 @@ void ItemView::InsertItem( Item newItem, float durationSeconds ) else { // Inserting before the existing item range? - ItemPoolIter iter = mItemPool.begin(); + ItemIter iter = mItemPool.begin(); if( iter != mItemPool.end() && iter->first > newItem.first ) { displacedActor = iter->second; - mItemPool.erase( iter++ ); // iter is still valid after the erase + iter = mItemPool.erase( iter ); // iter is still valid after the erase afterDisplacedIter = iter; } @@ -669,30 +693,30 @@ void ItemView::InsertItem( Item newItem, float durationSeconds ) if( displacedActor ) { // Move the existing actors to make room - for( ItemPoolIter iter = afterDisplacedIter; mItemPool.end() != iter; ++iter ) + for( ItemIter iter = afterDisplacedIter; mItemPool.end() != iter; ++iter ) { Actor temp = iter->second; iter->second = displacedActor; displacedActor = temp; iter->second.RemoveConstraints(); - mActiveLayout->ApplyConstraints( iter->second, iter->first, durationSeconds, mScrollPositionObject, Self() ); + mActiveLayout->ApplyConstraints( iter->second, iter->first, layoutSize, Self() ); } // Create last item - ItemPool::reverse_iterator lastIter = mItemPool.rbegin(); + ItemContainer::reverse_iterator lastIter = mItemPool.rbegin(); if ( lastIter != mItemPool.rend() ) { ItemId lastId = lastIter->first; Item lastItem( lastId + 1, displacedActor ); - mItemPool.insert( lastItem ); + InsertToItemContainer( mItemPool, lastItem ); lastItem.second.RemoveConstraints(); - mActiveLayout->ApplyConstraints( lastItem.second, lastItem.first, durationSeconds, mScrollPositionObject, Self() ); + mActiveLayout->ApplyConstraints( lastItem.second, lastItem.first, layoutSize, Self() ); } } - CalculateDomainSize(Self().GetCurrentSize()); + CalculateDomainSize( layoutSize ); mAddingItems = false; } @@ -700,26 +724,24 @@ void ItemView::InsertItem( Item newItem, float durationSeconds ) void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds ) { mAddingItems = true; + Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); // Insert from lowest id to highest - std::set sortedItems; - for( ConstItemIter iter = newItems.begin(); newItems.end() != iter; ++iter ) - { - sortedItems.insert( *iter ); - } + ItemContainer sortedItems(newItems); + std::sort( sortedItems.begin(), sortedItems.end() ); - for( std::set::iterator iter = sortedItems.begin(); sortedItems.end() != iter; ++iter ) + for( ItemIter iter = sortedItems.begin(); sortedItems.end() != iter; ++iter ) { Self().Add( iter->second ); - ItemPoolIter foundIter = mItemPool.find( iter->first ); + ItemIter foundIter = FindItemById( mItemPool, iter->first ); if( mItemPool.end() != foundIter ) { Actor moveMe = foundIter->second; foundIter->second = iter->second; // Move the existing actors to make room - for( ItemPoolIter iter = ++foundIter; mItemPool.end() != iter; ++iter ) + for( ItemIter iter = ++foundIter; mItemPool.end() != iter; ++iter ) { Actor temp = iter->second; iter->second = moveMe; @@ -729,30 +751,30 @@ void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds // Create last item ItemId lastId = mItemPool.rbegin()->first; Item lastItem( lastId + 1, moveMe ); - mItemPool.insert( lastItem ); + InsertToItemContainer( mItemPool, lastItem ); } else { - mItemPool.insert( *iter ); + InsertToItemContainer( mItemPool, *iter ); } } // Relayout everything - for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) + for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) { // If newly inserted - if( FindById( newItems, iter->first ) ) + if( std::binary_search( sortedItems.begin(), sortedItems.end(), *iter ) ) { - SetupActor( *iter, durationSeconds ); + SetupActor( *iter, layoutSize ); } else { iter->second.RemoveConstraints(); - mActiveLayout->ApplyConstraints( iter->second, iter->first, durationSeconds, mScrollPositionObject, Self() ); + mActiveLayout->ApplyConstraints( iter->second, iter->first, layoutSize, Self() ); } } - CalculateDomainSize(Self().GetCurrentSize()); + CalculateDomainSize( layoutSize ); mAddingItems = false; } @@ -762,7 +784,7 @@ void ItemView::RemoveItem( unsigned int itemId, float durationSeconds ) bool actorsReordered = RemoveActor( itemId ); if( actorsReordered ) { - ReapplyAllConstraints( durationSeconds ); + ReapplyAllConstraints(); OnItemsRemoved(); } @@ -773,13 +795,10 @@ void ItemView::RemoveItems( const ItemIdContainer& itemIds, float durationSecond bool actorsReordered( false ); // Remove from highest id to lowest - set sortedItems; - for( ConstItemIdIter iter = itemIds.begin(); itemIds.end() != iter; ++iter ) - { - sortedItems.insert( *iter ); - } + ItemIdContainer sortedItems(itemIds); + std::sort( sortedItems.begin(), sortedItems.end() ); - for( set::reverse_iterator iter = sortedItems.rbegin(); sortedItems.rend() != iter; ++iter ) + for( ItemIdContainer::reverse_iterator iter = sortedItems.rbegin(); sortedItems.rend() != iter; ++iter ) { if( RemoveActor( *iter ) ) { @@ -789,7 +808,7 @@ void ItemView::RemoveItems( const ItemIdContainer& itemIds, float durationSecond if( actorsReordered ) { - ReapplyAllConstraints( durationSeconds ); + ReapplyAllConstraints(); OnItemsRemoved(); } @@ -799,7 +818,7 @@ bool ItemView::RemoveActor(unsigned int itemId) { bool reordered( false ); - ItemPoolIter removeIter = mItemPool.find( itemId ); + ItemIter removeIter = FindItemById( mItemPool, itemId ); if( removeIter != mItemPool.end() ) { ReleaseActor(itemId, removeIter->second); @@ -807,12 +826,12 @@ bool ItemView::RemoveActor(unsigned int itemId) else { // Removing before the existing item range? - ItemPoolIter iter = mItemPool.begin(); + ItemIter 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()) ); + InsertToItemContainer( mItemPool, Item(iter->first - 1, Actor()) ); removeIter = mItemPool.begin(); } @@ -828,11 +847,11 @@ bool ItemView::RemoveActor(unsigned int itemId) // ID 2 - ActorB ID 2 - ActorC (previously ID 3) // ID 3 - ActorC ID 3 - ActorB (previously ID 4) // ID 4 - ActorD - for (ItemPoolIter iter = removeIter; iter != mItemPool.end(); ++iter) + for (ItemIter iter = removeIter; iter != mItemPool.end(); ++iter) { if( iter->first < mItemPool.rbegin()->first ) { - iter->second = mItemPool[ iter->first + 1 ]; + iter->second = ( iter + 1 )->second; } else { @@ -848,11 +867,12 @@ bool ItemView::RemoveActor(unsigned int itemId) void ItemView::ReplaceItem( Item replacementItem, float durationSeconds ) { mAddingItems = true; + Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); - SetupActor( replacementItem, durationSeconds ); + SetupActor( replacementItem, layoutSize ); Self().Add( replacementItem.second ); - const ItemPoolIter iter = mItemPool.find( replacementItem.first ); + const ItemIter iter = FindItemById( mItemPool, replacementItem.first ); if( mItemPool.end() != iter ) { ReleaseActor(iter->first, iter->second); @@ -860,10 +880,10 @@ void ItemView::ReplaceItem( Item replacementItem, float durationSeconds ) } else { - mItemPool.insert( replacementItem ); + InsertToItemContainer( mItemPool, replacementItem ); } - CalculateDomainSize(Self().GetCurrentSize()); + CalculateDomainSize( layoutSize ); mAddingItems = false; } @@ -879,7 +899,7 @@ void ItemView::ReplaceItems( const ItemContainer& replacementItems, float durati void ItemView::RemoveActorsOutsideRange( ItemRange range ) { // Remove unwanted actors from the ItemView & ItemPool - for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ) + for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ) { unsigned int current = iter->first; @@ -887,7 +907,7 @@ void ItemView::RemoveActorsOutsideRange( ItemRange range ) { ReleaseActor(iter->first, iter->second); - mItemPool.erase( iter++ ); // erase invalidates the return value of post-increment; iter remains valid + iter = mItemPool.erase( iter ); // iter is still valid after the erase } else { @@ -896,7 +916,7 @@ void ItemView::RemoveActorsOutsideRange( ItemRange range ) } } -void ItemView::AddActorsWithinRange( ItemRange range, float durationSeconds ) +void ItemView::AddActorsWithinRange( ItemRange range, const Vector3& layoutSize ) { range.end = std::min(mItemFactory.GetNumberOfItems(), range.end); @@ -905,27 +925,27 @@ void ItemView::AddActorsWithinRange( ItemRange range, float durationSeconds ) { for (unsigned int itemId = range.begin; itemId < range.end; ++itemId) { - AddNewActor( itemId, durationSeconds ); + AddNewActor( itemId, layoutSize ); } } else { for (unsigned int itemId = range.end; itemId > range.begin; --itemId) { - AddNewActor( itemId-1, durationSeconds ); + AddNewActor( itemId-1, layoutSize ); } } // Total number of items may change dynamically. // Always recalculate the domain size to reflect that. - CalculateDomainSize(Self().GetCurrentSize()); + CalculateDomainSize(Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE )); } -void ItemView::AddNewActor( unsigned int itemId, float durationSeconds ) +void ItemView::AddNewActor( unsigned int itemId, const Vector3& layoutSize ) { mAddingItems = true; - if( mItemPool.end() == mItemPool.find( itemId ) ) + if( mItemPool.end() == FindItemById( mItemPool, itemId ) ) { Actor actor = mItemFactory.NewItem( itemId ); @@ -933,9 +953,9 @@ void ItemView::AddNewActor( unsigned int itemId, float durationSeconds ) { Item newItem( itemId, actor ); - mItemPool.insert( newItem ); + InsertToItemContainer( mItemPool, newItem ); - SetupActor( newItem, durationSeconds ); + SetupActor( newItem, layoutSize ); Self().Add( actor ); } } @@ -943,20 +963,18 @@ void ItemView::AddNewActor( unsigned int itemId, float durationSeconds ) mAddingItems = false; } -void ItemView::SetupActor( Item item, float durationSeconds ) +void ItemView::SetupActor( Item item, const Vector3& layoutSize ) { - item.second.SetParentOrigin( mItemsParentOrigin ); - item.second.SetAnchorPoint( mItemsAnchorPoint ); + item.second.SetProperty( Actor::Property::PARENT_ORIGIN, mItemsParentOrigin ); + item.second.SetProperty( Actor::Property::ANCHOR_POINT, mItemsAnchorPoint ); if( mActiveLayout ) { Vector3 size; - if( mActiveLayout->GetItemSize( item.first, mActiveLayoutTargetSize, size ) ) - { - item.second.SetSize( size.GetVectorXY() ); - } + mActiveLayout->GetItemSize( item.first, mActiveLayoutTargetSize, size ); + item.second.SetProperty( Actor::Property::SIZE, size.GetVectorXY() ); - mActiveLayout->ApplyConstraints( item.second, item.first, durationSeconds, mScrollPositionObject, Self() ); + mActiveLayout->ApplyConstraints( item.second, item.first, layoutSize, Self() ); } } @@ -990,79 +1008,53 @@ 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::ScrollComponent scrollComponent = Dali::Toolkit::ScrollComponent::DownCast(child); - if(scrollComponent) + Dali::Toolkit::ScrollBar scrollBar = Dali::Toolkit::ScrollBar::DownCast(child); + if(scrollBar) { - // Set the scroll connector when scroll bar is being added - scrollComponent.SetScrollConnector(mScrollConnector); + scrollBar.SetScrollPropertySource(Self(), + Toolkit::ItemView::Property::LAYOUT_POSITION, + Toolkit::Scrollable::Property::SCROLL_POSITION_MIN_Y, + Toolkit::Scrollable::Property::SCROLL_POSITION_MAX_Y, + Toolkit::ItemView::Property::SCROLL_CONTENT_SIZE); } } -} - -bool ItemView::OnTouchEvent(const TouchEvent& event) -{ - // Ignore events with multiple-touch points - if (event.GetPointCount() != 1) - { - return false; - } - - if (event.GetPoint(0).state == TouchPoint::Down) - { - // Cancel ongoing scrolling etc. - mGestureState = Gesture::Clear; - - mScrollDistance = 0.0f; - mScrollSpeed = 0.0f; - Self().SetProperty(mPropertyScrollSpeed, mScrollSpeed); - - mScrollOvershoot = 0.0f; - AnimateScrollOvershoot(0.0f); - - if(mScrollAnimation) - { - mScrollCompletedSignal.Emit(GetCurrentScrollPosition()); - } - - RemoveAnimation(mScrollAnimation); - } - return true; // consume since we're potentially scrolling + Scrollable::OnChildAdd( child ); } -bool ItemView::OnMouseWheelEvent(const MouseWheelEvent& event) +bool ItemView::OnWheelEvent(const WheelEvent& event) { - // Respond the mouse wheel event to scroll + // Respond the wheel event to scroll if (mActiveLayout) { Actor self = Self(); - const Vector3 layoutSize = Self().GetCurrentSize(); - float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.z * mMouseWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor()); + const Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); + float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.GetDelta() * mWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor()); float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout); - mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition ); - self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize)); + self.SetProperty(Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition ); + mScrollStartedSignal.Emit(GetCurrentScrollPosition()); mRefreshEnabled = true; } - if (mMouseWheelEventFinishedTimer.IsRunning()) + if (mWheelEventFinishedTimer.IsRunning()) { - mMouseWheelEventFinishedTimer.Stop(); + mWheelEventFinishedTimer.Stop(); } - mMouseWheelEventFinishedTimer.Start(); + mWheelEventFinishedTimer.Start(); return true; } -bool ItemView::OnMouseWheelEventFinished() +bool ItemView::OnWheelEventFinished() { if (mActiveLayout) { RemoveAnimation(mScrollAnimation); - // No more mouse wheel events coming. Do the anchoring if enabled. + // No more wheel events coming. Do the anchoring if enabled. mScrollAnimation = DoAnchoring(); if (mScrollAnimation) { @@ -1081,46 +1073,82 @@ bool ItemView::OnMouseWheelEventFinished() return false; } -void ItemView::ReapplyAllConstraints( float durationSeconds ) +void ItemView::ReapplyAllConstraints() { - for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) + Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); + + for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) { unsigned int id = iter->first; Actor actor = iter->second; actor.RemoveConstraints(); - mActiveLayout->ApplyConstraints(actor, id, durationSeconds, mScrollPositionObject, Self()); + mActiveLayout->ApplyConstraints(actor, id, layoutSize, Self()); } } void ItemView::OnItemsRemoved() { - CalculateDomainSize(Self().GetCurrentSize()); + CalculateDomainSize(Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE )); // 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 firstItemScrollPosition = ClampFirstItemPosition(GetCurrentLayoutPosition(0), Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ), *mActiveLayout); + Self().SetProperty( Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition ); } } -float ItemView::ClampFirstItemPosition(float targetPosition, const Vector3& targetSize, ItemLayout& layout) +float ItemView::ClampFirstItemPosition( float targetPosition, const Vector3& targetSize, ItemLayout& layout, bool updateOvershoot ) { Actor self = Self(); float minLayoutPosition = layout.GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize); float clamppedPosition = std::min(0.0f, std::max(minLayoutPosition, targetPosition)); - mScrollOvershoot = targetPosition - clamppedPosition; - self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition); + self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition)); + + if( updateOvershoot ) + { + mScrollOvershoot = targetPosition - clamppedPosition; + } return clamppedPosition; } +bool ItemView::OnTouch( Actor actor, const TouchEvent& touch ) +{ + // Ignore events with multiple-touch points + if (touch.GetPointCount() != 1) + { + return false; + } + + if ( touch.GetState( 0 ) == PointState::DOWN ) + { + // Cancel ongoing scrolling etc. + mGestureState = Gesture::Clear; + + mScrollDistance = 0.0f; + mScrollSpeed = 0.0f; + Self().SetProperty(Toolkit::ItemView::Property::SCROLL_SPEED, mScrollSpeed); + + mScrollOvershoot = 0.0f; + AnimateScrollOvershoot(0.0f); + + if(mScrollAnimation) + { + mScrollCompletedSignal.Emit(GetCurrentScrollPosition()); + } + + RemoveAnimation(mScrollAnimation); + } + + return false; // Do not consume as we're potentially scrolling (detecting pan gestures) +} + void ItemView::OnPan( const PanGesture& gesture ) { Actor self = Self(); - const Vector3 layoutSize = Self().GetCurrentSize(); + const Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); RemoveAnimation(mScrollAnimation); @@ -1161,15 +1189,16 @@ void ItemView::OnPan( const PanGesture& gesture ) , DEFAULT_MINIMUM_SWIPE_DURATION, DEFAULT_MAXIMUM_SWIPE_DURATION); mScrollAnimation = Animation::New(flickAnimationDuration); - mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut ); - mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut ); - mScrollAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut ); + mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION ), firstItemScrollPosition, AlphaFunction::EASE_OUT ); + mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::SCROLL_SPEED), 0.0f, AlphaFunction::EASE_OUT ); mIsFlicking = true; + // Check whether it has already scrolled to the end - if(fabs(currentLayoutPosition - firstItemScrollPosition) > Math::MACHINE_EPSILON_0) + if( fabs(currentLayoutPosition - firstItemScrollPosition) < Math::MACHINE_EPSILON_0 ) { - AnimateScrollOvershoot(0.0f); + AnimateScrollOvershoot( 0.0f ); + RemoveAnimation( mScrollAnimation ); } } @@ -1208,18 +1237,43 @@ void ItemView::OnPan( const PanGesture& gesture ) float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout); - float currentOvershoot = mScrollPositionObject.GetProperty(ScrollConnector::OVERSHOOT); + float currentOvershoot = self.GetCurrentProperty< float >( Toolkit::ItemView::Property::OVERSHOOT ); - mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition ); - self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize)); + self.SetProperty(Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition ); - if( (firstItemScrollPosition >= 0.0f && currentOvershoot < 1.0f) || (firstItemScrollPosition <= mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize) && currentOvershoot > -1.0f) ) + if( ( firstItemScrollPosition >= 0.0f && + currentOvershoot < 1.0f ) || + ( firstItemScrollPosition <= mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize) && + currentOvershoot > -1.0f ) ) { mTotalPanDisplacement += gesture.displacement; } mScrollOvershoot = CalculateScrollOvershoot(); - mScrollPositionObject.SetProperty( ScrollConnector::OVERSHOOT, mScrollOvershoot ); + + // If the view is moved in a direction against the overshoot indicator, then the indicator should be animated off. + // First make sure we are not in an animation, otherwise a previously started + // off-animation will be overwritten as the user continues scrolling. + if( !mInAnimation ) + { + // Check if the movement is against the current overshoot amount (if we are currently displaying the indicator). + if( ( ( mScrollOvershoot > Math::MACHINE_EPSILON_0 ) && ( mScrollDistance < -Math::MACHINE_EPSILON_0 ) ) || + ( ( mScrollOvershoot < Math::MACHINE_EPSILON_0 ) && ( mScrollDistance > Math::MACHINE_EPSILON_0 ) ) ) + { + // The user has moved against the indicator direction. + // First, we reset the total displacement. This means the overshoot amount will become zero the next frame, + // and if the user starts dragging in the overshoot direction again, the indicator will appear once more. + mTotalPanDisplacement = Vector2::ZERO; + // Animate the overshoot indicator off. + AnimateScrollOvershoot( 0.0f, false ); + } + else + { + // Only set the property directly if we are not animating the overshoot away, + // as otherwise this will overwrite the animation generated value. + self.SetProperty( Toolkit::ItemView::Property::OVERSHOOT, mScrollOvershoot ); + } + } } break; @@ -1246,7 +1300,7 @@ bool ItemView::OnAccessibilityPan(PanGesture gesture) return true; } -Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled) +Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled) { Actor nextFocusActor; if(mActiveLayout) @@ -1269,7 +1323,7 @@ Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::Key } } float layoutPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) ); - Vector3 layoutSize = Self().GetCurrentSize(); + Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); if(!nextFocusActor) { // likely the current item is not buffered, so not in our item pool, probably best to get first viewable item @@ -1288,10 +1342,10 @@ void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor) { int nextItemID = GetItemId(commitedFocusableActor); float layoutPosition = GetCurrentLayoutPosition(0); - Vector3 layoutSize = Self().GetCurrentSize(); + Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); float scrollTo = mActiveLayout->GetClosestOnScreenLayoutPosition(nextItemID, layoutPosition, layoutSize); - ScrollTo(Vector3(0.0f, scrollTo, 0.0f), DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION); + ScrollTo(Vector2(0.0f, scrollTo), DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION); } } @@ -1305,9 +1359,8 @@ Animation ItemView::DoAnchoring() float anchorPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) ); anchoringAnimation = Animation::New(mAnchoringDuration); - anchoringAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), anchorPosition, AlphaFunctions::EaseOut ); - anchoringAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(anchorPosition, self.GetCurrentSize()), AlphaFunctions::EaseOut ); - anchoringAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut ); + anchoringAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), anchorPosition, AlphaFunction::EASE_OUT ); + anchoringAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::SCROLL_SPEED), 0.0f, AlphaFunction::EASE_OUT ); if(!mIsFlicking) { AnimateScrollOvershoot(0.0f); @@ -1344,6 +1397,9 @@ void ItemView::OnLayoutActivationScrollFinished(Animation& source) RemoveAnimation(mScrollAnimation); mRefreshEnabled = true; DoRefresh(GetCurrentLayoutPosition(0), true); + + // Emit the layout activated signal + mLayoutActivatedSignal.Emit(); } void ItemView::OnOvershootOnFinished(Animation& animation) @@ -1355,26 +1411,26 @@ void ItemView::OnOvershootOnFinished(Animation& animation) { AnimateScrollOvershoot(0.0f); } + mInAnimation = false; } void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds) { Actor self = Self(); - const Vector3 layoutSize = Self().GetCurrentSize(); + const Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); float firstItemScrollPosition = ClampFirstItemPosition(mActiveLayout->GetItemScrollToPosition(itemId), layoutSize, *mActiveLayout); if(durationSeconds > 0.0f) { RemoveAnimation(mScrollAnimation); mScrollAnimation = Animation::New(durationSeconds); - mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut ); - mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut ); + mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, mScrollToAlphaFunction ); mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished); mScrollAnimation.Play(); } else { - mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition ); + self.SetProperty( Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition ); AnimateScrollOvershoot(0.0f); } @@ -1404,25 +1460,23 @@ void ItemView::CalculateDomainSize(const Vector3& layoutSize) firstItemPosition = mActiveLayout->GetItemPosition( 0,0,layoutSize ); float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize); - self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition); lastItemPosition = mActiveLayout->GetItemPosition( fabs(minLayoutPosition),fabs(minLayoutPosition),layoutSize ); float domainSize; if(IsHorizontal(mActiveLayout->GetOrientation())) { - self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, Vector3(0.0f, firstItemPosition.x, 0.0f)); - self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector3(0.0f, lastItemPosition.x, 0.0f)); domainSize = fabs(firstItemPosition.x - lastItemPosition.x); } else { - self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, Vector3(0.0f, firstItemPosition.y, 0.0f)); - self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector3(0.0f, lastItemPosition.y, 0.0f)); domainSize = fabs(firstItemPosition.y - lastItemPosition.y); } - mScrollConnector.SetScrollDomain(minLayoutPosition, 0.0f, domainSize); + self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, Vector2::ZERO); + self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition)); + + self.SetProperty(Toolkit::ItemView::Property::SCROLL_CONTENT_SIZE, domainSize); bool isLayoutScrollable = IsLayoutScrollable(layoutSize); self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, isLayoutScrollable); @@ -1430,23 +1484,13 @@ void ItemView::CalculateDomainSize(const Vector3& layoutSize) } } -Vector3 ItemView::GetDomainSize() const -{ - Actor self = Self(); - - float minScrollPosition = self.GetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN); - float maxScrollPosition = self.GetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX); - - return Vector3(0.0f, fabs(maxScrollPosition - minScrollPosition), 0.0f); -} - bool ItemView::IsLayoutScrollable(const Vector3& layoutSize) { Actor self = Self(); - float currentLayoutPosition = ClampFirstItemPosition( GetCurrentLayoutPosition(0), layoutSize, *mActiveLayout ); - float forwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition + 1.0, layoutSize, *mActiveLayout); - float backwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition - 1.0, layoutSize, *mActiveLayout); + float currentLayoutPosition = ClampFirstItemPosition( GetCurrentLayoutPosition(0), layoutSize, *mActiveLayout, false ); + float forwardClampedPosition = ClampFirstItemPosition( currentLayoutPosition + 1.0, layoutSize, *mActiveLayout, false ); + float backwardClampedPosition = ClampFirstItemPosition( currentLayoutPosition - 1.0, layoutSize, *mActiveLayout, false ); return (fabs(forwardClampedPosition - backwardClampedPosition) > Math::MACHINE_EPSILON_0); } @@ -1457,14 +1501,14 @@ float ItemView::GetScrollPosition(float layoutPosition, const Vector3& layoutSiz return IsHorizontal(mActiveLayout->GetOrientation()) ? firstItemPosition.x: firstItemPosition.y; } -Vector3 ItemView::GetCurrentScrollPosition() const +Vector2 ItemView::GetCurrentScrollPosition() const { - float currentLayoutPosition = GetCurrentLayoutPosition(0); - return Vector3(0.0f, GetScrollPosition(currentLayoutPosition, Self().GetCurrentSize()), 0.0f); + return Vector2(0.0f, GetScrollPosition(GetCurrentLayoutPosition(0), Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ))); } void ItemView::AddOverlay(Actor actor) { + actor.SetProperty( Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D ); Self().Add(actor); } @@ -1473,10 +1517,10 @@ void ItemView::RemoveOverlay(Actor actor) Self().Remove(actor); } -void ItemView::ScrollTo(const Vector3& position, float duration) +void ItemView::ScrollTo(const Vector2& position, float duration) { Actor self = Self(); - const Vector3 layoutSize = Self().GetCurrentSize(); + const Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ); float firstItemScrollPosition = ClampFirstItemPosition(position.y, layoutSize, *mActiveLayout); @@ -1484,14 +1528,13 @@ void ItemView::ScrollTo(const Vector3& position, float duration) { RemoveAnimation(mScrollAnimation); mScrollAnimation = Animation::New(duration); - mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut ); - mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut ); + mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, mScrollToAlphaFunction ); mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished); mScrollAnimation.Play(); } else { - mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition ); + self.SetProperty( Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition ); AnimateScrollOvershoot(0.0f); } @@ -1499,53 +1542,65 @@ void ItemView::ScrollTo(const Vector3& position, float duration) mRefreshEnabled = true; } +void ItemView::SetOvershootSize( const Vector2& size ) +{ + mOvershootSize = size; + + if( mOvershootOverlay ) + { + // Remove old & add new size constraint + mOvershootOverlay.RemoveConstraints( OVERSHOOT_SIZE_CONSTRAINT_TAG ); + ApplyOvershootSizeConstraint( mOvershootOverlay, mOvershootSize.height ); + } +} + void ItemView::SetOvershootEffectColor( const Vector4& color ) { mOvershootEffectColor = color; if( mOvershootOverlay ) { - mOvershootOverlay.SetColor( color ); + mOvershootOverlay.SetProperty( Actor::Property::COLOR, color ); } } -void ItemView::SetOvershootEnabled( bool enable ) +void ItemView::EnableScrollOvershoot( bool enable ) { Actor self = Self(); if( enable ) { - Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX; - mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex ); - mOvershootOverlay.SetColor(mOvershootEffectColor); - mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT); - mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT); - mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY); - self.Add(mOvershootOverlay); - - Constraint constraint = Constraint::New( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint ); - constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::SCROLL_DIRECTION ) ); - constraint.AddSource( ParentSource( Actor::Property::SIZE ) ); - constraint.Apply(); - - mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height); - - constraint = Constraint::New( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint ); - constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::SCROLL_DIRECTION ) ); - constraint.AddSource( Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ) ); - constraint.Apply(); - - constraint = Constraint::New( mOvershootOverlay, Actor::Property::POSITION, OvershootOverlayPositionConstraint ); - constraint.AddSource( ParentSource( Actor::Property::SIZE ) ); - constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::SCROLL_DIRECTION ) ); - constraint.AddSource( Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ) ); - constraint.Apply(); - - constraint = Constraint::New( mOvershootOverlay, Actor::Property::VISIBLE, OvershootOverlayVisibilityConstraint ); - constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL ) ); - constraint.Apply(); - - constraint = Constraint::New( mOvershootOverlay, effectOvershootPropertyIndex, EqualToConstraint() ); - constraint.AddSource( Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ) ); - constraint.Apply(); + if( !mOvershootOverlay ) + { + Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX; + mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex ); + mOvershootOverlay.SetProperty( Actor::Property::COLOR,mOvershootEffectColor); + mOvershootOverlay.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::TOP_LEFT ); + mOvershootOverlay.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT); + mOvershootOverlay.SetProperty( Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D ); + self.Add(mOvershootOverlay); + + ApplyOvershootSizeConstraint( mOvershootOverlay, mOvershootSize.height ); + + Constraint constraint = Constraint::New( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint ); + constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) ); + constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) ); + constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) ); + constraint.Apply(); + + constraint = Constraint::New( mOvershootOverlay, Actor::Property::POSITION, OvershootOverlayPositionConstraint ); + constraint.AddSource( ParentSource( Actor::Property::SIZE ) ); + constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) ); + constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) ); + constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) ); + constraint.Apply(); + + constraint = Constraint::New( mOvershootOverlay, Actor::Property::VISIBLE, OvershootOverlayVisibilityConstraint ); + constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL ) ); + constraint.Apply(); + + constraint = Constraint::New( mOvershootOverlay, effectOvershootPropertyIndex, EqualToConstraint() ); + constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) ); + constraint.Apply(); + } } else { @@ -1568,8 +1623,8 @@ float ItemView::CalculateScrollOvershoot() Actor self = Self(); float scrollDistance = CalculateScrollDistance(mTotalPanDisplacement, *mActiveLayout) * mActiveLayout->GetScrollSpeedFactor(); float positionDelta = GetCurrentLayoutPosition(0) + scrollDistance; - float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentSize()); - self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition); + float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE )); + self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition)); float clamppedPosition = std::min(0.0f, std::max(minLayoutPosition, positionDelta)); overshoot = positionDelta - clamppedPosition; } @@ -1590,27 +1645,30 @@ void ItemView::AnimateScrollOvershoot(float overshootAmount, bool animateBack) return; } + Actor self = Self(); + if(mOvershootAnimationSpeed > Math::MACHINE_EPSILON_0) { - float currentOvershoot = mScrollPositionObject.GetProperty(ScrollConnector::OVERSHOOT); + float currentOvershoot = self.GetCurrentProperty< float >( Toolkit::ItemView::Property::OVERSHOOT ); float duration = 0.0f; if (mOvershootOverlay) { - duration = mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot)) / mOvershootAnimationSpeed; + duration = mOvershootOverlay.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ).height * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot)) / mOvershootAnimationSpeed; } + // Mark the animation as in progress to prevent manual property sets overwriting it. + mInAnimation = true; + mAnimatingOvershootOn = animatingOn; RemoveAnimation(mScrollOvershootAnimation); mScrollOvershootAnimation = Animation::New(duration); mScrollOvershootAnimation.FinishedSignal().Connect(this, &ItemView::OnOvershootOnFinished); - mScrollOvershootAnimation.AnimateTo( Property(mScrollPositionObject, ScrollConnector::OVERSHOOT), overshootAmount, TimePeriod(0.0f, duration) ); + mScrollOvershootAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::OVERSHOOT), overshootAmount, TimePeriod(0.0f, duration) ); mScrollOvershootAnimation.Play(); - - mAnimatingOvershootOn = animatingOn; } else { - mScrollPositionObject.SetProperty( ScrollConnector::OVERSHOOT, overshootAmount ); + self.SetProperty( Toolkit::ItemView::Property::OVERSHOOT, overshootAmount ); } } @@ -1619,9 +1677,9 @@ void ItemView::SetItemsParentOrigin( const Vector3& parentOrigin ) if( parentOrigin != mItemsParentOrigin ) { mItemsParentOrigin = parentOrigin; - for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) + for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) { - iter->second.SetParentOrigin(parentOrigin); + iter->second.SetProperty( Actor::Property::PARENT_ORIGIN,parentOrigin ); } } } @@ -1636,9 +1694,9 @@ void ItemView::SetItemsAnchorPoint( const Vector3& anchorPoint ) if( anchorPoint != mItemsAnchorPoint ) { mItemsAnchorPoint = anchorPoint; - for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) + for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter) { - iter->second.SetAnchorPoint(anchorPoint); + iter->second.SetProperty( Actor::Property::ANCHOR_POINT,anchorPoint); } } } @@ -1662,13 +1720,246 @@ void ItemView::GetItemsRange(ItemRange& range) } } -void ItemView::OnScrollPositionChanged( float position ) +bool ItemView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) { - // Cancel scroll animation to prevent any fighting of setting the scroll position property. - RemoveAnimation(mScrollAnimation); + Dali::BaseHandle handle( object ); + + bool connected( true ); + Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( handle ); + + if( 0 == strcmp( signalName.c_str(), LAYOUT_ACTIVATED_SIGNAL ) ) + { + itemView.LayoutActivatedSignal().Connect( tracker, functor ); + } + else + { + // signalName does not match any signal + connected = false; + } + + return connected; +} + +void ItemView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) +{ + Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) ); + + if( itemView ) + { + ItemView& itemViewImpl( GetImpl( itemView ) ); + switch( index ) + { + case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED: + { + itemViewImpl.SetMinimumSwipeSpeed( value.Get() ); + break; + } + + case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE: + { + itemViewImpl.SetMinimumSwipeDistance( value.Get() ); + break; + } + + case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP: + { + itemViewImpl.SetWheelScrollDistanceStep( value.Get() ); + break; + } + + case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED: + { + itemViewImpl.SetAnchoring( value.Get() ); + break; + } + + case Toolkit::ItemView::Property::REFRESH_INTERVAL: + { + itemViewImpl.SetRefreshInterval( value.Get() ); + break; + } + + case Toolkit::ItemView::Property::LAYOUT: + { + // Get a Property::Array from the property if possible. + Property::Array layoutArray; + if( value.Get( layoutArray ) ) + { + itemViewImpl.SetLayoutArray( layoutArray ); + } + break; + } + } + } +} - // Refresh the cache immediately when the scroll position is changed. - DoRefresh(position, false); // No need to cache extra items. +Property::Array ItemView::GetLayoutArray() +{ + return mlayoutArray; +} + +void ItemView::SetLayoutArray( const Property::Array& layouts ) +{ + mlayoutArray = layouts; + const int layoutCount = GetLayoutCount(); + if( layoutCount > 0 ) + { + for(int index = layoutCount - 1; index >= 0; --index) + { + RemoveLayout(index); + if(index == 0) break; + } + } + + for( unsigned int arrayIdx = 0, arrayCount = layouts.Count(); arrayIdx < arrayCount; ++arrayIdx ) + { + const Property::Value& element = layouts.GetElementAt( arrayIdx ); + + Property::Map* layout = element.GetMap(); + if( layout != NULL ) + { + for( unsigned int mapIdx = 0, mapCount = (*layout).Count(); mapIdx < mapCount; ++mapIdx ) + { + KeyValuePair propertyPair( (*layout).GetKeyValue( mapIdx ) ); + + if(propertyPair.first == DefaultItemLayoutProperty::TYPE) + { + int layoutType = propertyPair.second.Get(); + if(layoutType <= DefaultItemLayout::SPIRAL && layoutType >= DefaultItemLayout::DEPTH) + { + //DEPTH, GRID, LIST, SPIRAL + switch(DefaultItemLayout::Type(layoutType)) + { + case DefaultItemLayout::DEPTH: + { + Internal::DepthLayoutPtr depthLayout = Internal::DepthLayout::New(); + (*depthLayout).SetLayoutProperties(*layout); + (*depthLayout).SetDepthLayoutProperties(*layout); + AddLayout(*depthLayout); + break; + } + case DefaultItemLayout::GRID: + { + Internal::GridLayoutPtr gridLayout = Internal::GridLayout::New(); + (*gridLayout).SetLayoutProperties(*layout); + (*gridLayout).SetGridLayoutProperties(*layout); + AddLayout(*gridLayout); + break; + } + case DefaultItemLayout::LIST: + { + Internal::GridLayoutPtr listLayout = Internal::GridLayout::New(); + listLayout->SetNumberOfColumns( 1 ); + (*listLayout).SetLayoutProperties(*layout); + (*listLayout).SetGridLayoutProperties(*layout); + AddLayout(*listLayout); + break; + } + case DefaultItemLayout::SPIRAL: + { + Internal::SpiralLayoutPtr spiralLayout = Internal::SpiralLayout::New(); + (*spiralLayout).SetLayoutProperties(*layout); + (*spiralLayout).SetSpiralLayoutProperties(*layout); + AddLayout(*spiralLayout); + break; + } + } + } + } + } + } + } +} + +Property::Value ItemView::GetProperty( BaseObject* object, Property::Index index ) +{ + Property::Value value; + + Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) ); + + if( itemView ) + { + ItemView& itemViewImpl( GetImpl( itemView ) ); + switch( index ) + { + case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED: + { + value = itemViewImpl.GetMinimumSwipeSpeed(); + break; + } + + case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE: + { + value = itemViewImpl.GetMinimumSwipeDistance(); + break; + } + + case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP: + { + value = itemViewImpl.GetWheelScrollDistanceStep(); + break; + } + + case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED: + { + value = itemViewImpl.GetAnchoring(); + break; + } + + case Toolkit::ItemView::Property::REFRESH_INTERVAL: + { + value = itemViewImpl.GetRefreshInterval(); + break; + } + + case Toolkit::ItemView::Property::LAYOUT: + { + Property::Array layouts= itemViewImpl.GetLayoutArray(); + value = layouts; + break; + } + } + } + + return value; +} + +bool ItemView::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes ) +{ + Dali::BaseHandle handle( object ); + + Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( handle ); + + DALI_ASSERT_ALWAYS( itemView ); + + if( 0 == strcmp( actionName.c_str(), ACTION_STOP_SCROLLING ) ) + { + GetImpl( itemView ).DoStopScrolling(); + } + else if ( 0 == strcmp( actionName.c_str(), ACTION_ENABLE_REFRESH ) ) + { + GetImpl( itemView ).SetRefreshNotificationEnabled( true ); + } + else if ( 0 == strcmp( actionName.c_str(), ACTION_DISABLE_REFRESH ) ) + { + GetImpl( itemView ).SetRefreshNotificationEnabled( false ); + } + + return true; +} + +void ItemView::DoStopScrolling() +{ + if( mScrollAnimation ) + { + mScrollAnimation.Stop(); + mScrollAnimation.Reset(); + } +} + +void ItemView::SetRefreshNotificationEnabled( bool enabled ) +{ + mRefreshNotificationEnabled = enabled; } } // namespace Internal