DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layout-position", FLOAT, LAYOUT_POSITION)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scroll-speed", FLOAT, SCROLL_SPEED)
+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, "scroll-direction", VECTOR2, SCROLL_DIRECTION)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layout-orientation", INTEGER, LAYOUT_ORIENTATION)
-DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scroll-content-size", FLOAT, SCROLL_CONTENT_SIZE)
+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, "layout-activated", LAYOUT_ACTIVATED_SIGNAL )
+DALI_SIGNAL_REGISTRATION( Toolkit, ItemView, "layoutActivated", LAYOUT_ACTIVATED_SIGNAL )
DALI_TYPE_REGISTRATION_END()
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;
}
// Overshoot overlay constraints
-void OvershootOverlaySizeConstraint( Vector3& current, const PropertyInputContainer& inputs )
+struct OvershootOverlaySizeConstraint
{
- const Vector2& parentScrollDirection = inputs[0]->GetVector2();
- const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast<Toolkit::ControlOrientation::Type>(inputs[1]->GetInteger());
- const Vector3& parentSize = inputs[2]->GetVector3();
-
- if(Toolkit::IsVertical(layoutOrientation))
+ 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<Toolkit::ControlOrientation::Type>(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 )
{
ItemView::ItemView(ItemFactory& factory)
: Scrollable( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | 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(false),
mAnchoringDuration(DEFAULT_ANCHORING_DURATION),
mRefreshIntervalLayoutPositions(0.0f),
- mRefreshOrderHint(true/*Refresh item 0 first*/),
mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED),
mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE),
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),
mRefreshEnabled(true),
- mItemsParentOrigin( ParentOrigin::CENTER),
- mItemsAnchorPoint( AnchorPoint::CENTER)
+ mInAnimation(false)
{
}
{
Actor self = Self();
- SetOvershootEnabled(true);
-
Vector2 stageSize = Stage::GetCurrent().GetSize();
mWheelScrollDistanceStep = stageSize.y * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
void ItemView::OnRefreshNotification(PropertyNotification& source)
{
- if(mRefreshEnabled || mScrollAnimation)
+ // Cancel scroll animation to prevent any fighting of setting the scroll position property by scroll bar during fast scroll.
+ if(!mRefreshEnabled && mScrollAnimation)
{
- // Only refresh the cache during normal scrolling
- DoRefresh(GetCurrentLayoutPosition(0), true);
+ RemoveAnimation(mScrollAnimation);
}
+
+ // Only cache extra items when it is not a fast scroll
+ DoRefresh(GetCurrentLayoutPosition(0), mRefreshEnabled || mScrollAnimation);
}
void ItemView::Refresh()
Toolkit::Scrollable::Property::SCROLL_POSITION_MIN_Y,
Toolkit::Scrollable::Property::SCROLL_POSITION_MAX_Y,
Toolkit::ItemView::Property::SCROLL_CONTENT_SIZE);
- scrollBar.ScrollPositionIntervalReachedSignal().Connect( this, &ItemView::OnScrollPositionChanged );
}
}
}
}
}
-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(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition));
+ if( updateOvershoot )
+ {
+ mScrollOvershoot = targetPosition - clamppedPosition;
+ }
+
return clamppedPosition;
}
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();
- self.SetProperty( Toolkit::ItemView::Property::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;
{
AnimateScrollOvershoot(0.0f);
}
+ mInAnimation = false;
}
void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
{
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);
}
void ItemView::AddOverlay(Actor actor)
{
+ actor.SetDrawMode( DrawMode::OVERLAY_2D );
Self().Add(actor);
}
mOvershootOverlay.SetColor(mOvershootEffectColor);
mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+ mOvershootOverlay.SetDrawMode( DrawMode::OVERLAY_2D );
self.Add(mOvershootOverlay);
- Constraint constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint );
+ Constraint constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint(mOvershootSize.height) );
constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
constraint.Apply();
- mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
+ mOvershootOverlay.SetSize(mOvershootSize.width, mOvershootSize.height);
constraint = Constraint::New<Quaternion>( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint );
constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
duration = mOvershootOverlay.GetCurrentSize().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(self, Toolkit::ItemView::Property::OVERSHOOT), overshootAmount, TimePeriod(0.0f, duration) );
mScrollOvershootAnimation.Play();
-
- mAnimatingOvershootOn = animatingOn;
}
else
{
}
}
-void ItemView::OnScrollPositionChanged( float position )
-{
- // Cancel scroll animation to prevent any fighting of setting the scroll position property.
- RemoveAnimation(mScrollAnimation);
-
- // Refresh the cache immediately when the scroll position is changed.
- DoRefresh(position, false); // No need to cache extra items.
-}
-
bool ItemView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
{
Dali::BaseHandle handle( object );