X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=base%2Fdali-toolkit%2Finternal%2Fcontrols%2Fscrollable%2Fscroll-view%2Fscroll-view-impl.cpp;h=578fd897f76801a8b23830337d0bc4f039c45006;hp=0c761fba27ffdeab32dc2276d28995e0252e070c;hb=a342499604e471b0e0d80eac30eb28e898b06c69;hpb=a1a30b337ce9bf681f3738e43d1b6846732d5e1b diff --git a/base/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp b/base/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp index 0c761fb..578fd89 100644 --- a/base/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp +++ b/base/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp @@ -48,10 +48,11 @@ namespace { const int DEFAULT_REFRESH_INTERVAL_MILLISECONDS = 50; ///< Refresh rate TODO: Animation should have an update signal (and see item-view-impl) -const float FLICK_SPEED_THRESHOLD = 500.0f; ///< Flick threshold in pixels/ms +const Vector2 DEFAULT_MIN_FLICK_DISTANCE(30.0f, 30.0f); ///< minimum distance for pan before flick allowed +const float DEFAULT_MIN_FLICK_SPEED_THRESHOLD(500.0f); ///< Minimum pan speed required for flick in pixels/s const float FREE_FLICK_SPEED_THRESHOLD = 200.0f; ///< Free-Flick threshold in pixels/ms const float AUTOLOCK_AXIS_MINIMUM_DISTANCE2 = 100.0f; ///< Auto-lock axis after minimum distance squared. -const float FLICK_ORTHO_ANGLE_RANGE = 60.0f; ///< degrees. (if >45, then supports diagonal flicking) +const float FLICK_ORTHO_ANGLE_RANGE = 75.0f; ///< degrees. (if >45, then supports diagonal flicking) const unsigned int MAXIMUM_NUMBER_OF_VALUES = 5; ///< Number of values to use for weighted pan calculation. const Vector2 DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = Vector2(0.17f, 0.1f); ///< The step of horizontal scroll distance in the proportion of stage size for each mouse wheel event received. const unsigned long MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET( 150u ); @@ -605,6 +606,8 @@ ScrollView::ScrollView() mSnapOvershootAlphaFunction(AlphaFunctions::EaseOut), mSnapDuration(Toolkit::ScrollView::DEFAULT_SLOW_SNAP_ANIMATION_DURATION), mSnapAlphaFunction(AlphaFunctions::EaseOut), + mMinFlickDistance(DEFAULT_MIN_FLICK_DISTANCE), + mFlickSpeedThreshold(DEFAULT_MIN_FLICK_SPEED_THRESHOLD), mFlickDuration(Toolkit::ScrollView::DEFAULT_FAST_SNAP_ANIMATION_DURATION), mFlickAlphaFunction(AlphaFunctions::EaseOut), mAxisAutoLockGradient(Toolkit::ScrollView::DEFAULT_AXIS_AUTO_LOCK_GRADIENT), @@ -1017,6 +1020,7 @@ void ScrollView::UpdatePropertyDomain(const Vector3& size) } if( scrollPositionChanged ) { + DALI_LOG_SCROLL_STATE("[0x%X] Domain Changed, setting mPropertyPrePosition To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y ); self.SetProperty(mPropertyPrePosition, mScrollPrePosition); } if( domainChanged ) @@ -1060,6 +1064,8 @@ void ScrollView::SetScrollSensitive(bool sensitive) } else if((mSensitive) && (!sensitive)) { + DALI_LOG_SCROLL_STATE("[0x%X] BEFORE: panning:[%d]", this, int(mPanning)); + // while the scroll view is panning, the state needs to be reset. if ( mPanning ) { @@ -1071,6 +1077,7 @@ void ScrollView::SetScrollSensitive(bool sensitive) mSensitive = sensitive; mGestureStackDepth = 0; + DALI_LOG_SCROLL_STATE("[0x%X] AFTER: panning:[%d]", this, int(mPanning)); } } @@ -1198,6 +1205,26 @@ void ScrollView::SetFlickSpeedCoefficient(float speed) mFlickSpeedCoefficient = speed; } +Vector2 ScrollView::GetMinimumDistanceForFlick() const +{ + return mMinFlickDistance; +} + +void ScrollView::SetMinimumDistanceForFlick( const Vector2& distance ) +{ + mMinFlickDistance = distance; +} + +float ScrollView::GetMinimumSpeedForFlick() const +{ + return mFlickSpeedThreshold; +} + +void ScrollView::SetMinimumSpeedForFlick( float speed ) +{ + mFlickSpeedThreshold = speed; +} + float ScrollView::GetMaxFlickSpeed() const { return mMaxFlickSpeed; @@ -1296,6 +1323,7 @@ void ScrollView::TransformTo(const Vector3& position, const Vector3& scale, floa { DALI_LOG_SCROLL_STATE("[0x%X] Interrupting Pan, set to false", this ); mPanning = false; + mGestureStackDepth = 0; self.SetProperty( mPropertyPanning, false ); if( mScrollMainInternalPrePositionConstraint ) @@ -1498,6 +1526,7 @@ Actor ScrollView::FindClosestActorToPosition(const Vector3& position, FindDirect bool ScrollView::ScrollToSnapPoint() { + DALI_LOG_SCROLL_STATE("[0x%X]", this ); Vector2 stationaryVelocity = Vector2(0.0f, 0.0f); return SnapWithVelocity( stationaryVelocity ); } @@ -1540,7 +1569,7 @@ bool ScrollView::SnapWithVelocity(Vector2 velocity) // that will be accepted as a general N,E,S,W flick direction. const float orthoAngleRange = FLICK_ORTHO_ANGLE_RANGE * M_PI / 180.0f; - const float flickSpeedThreshold2 = FLICK_SPEED_THRESHOLD*FLICK_SPEED_THRESHOLD; + const float flickSpeedThreshold2 = mFlickSpeedThreshold * mFlickSpeedThreshold; Vector3 positionSnap = mScrollPrePosition; @@ -1832,11 +1861,15 @@ bool ScrollView::AnimateTo(const Vector3& position, const Vector3& positionDurat if( !(mScrollStateFlags & SCROLL_ANIMATION_FLAGS) ) { + DALI_LOG_SCROLL_STATE("[0x%X] Setting mPropertyPrePosition To[%.2f, %.2f]", this, mScrollTargetPosition.x, mScrollTargetPosition.y ); self.SetProperty(mPropertyPrePosition, mScrollTargetPosition); mScrollPrePosition = mScrollTargetPosition; mScrollPostPosition = mScrollTargetPosition; WrapPosition(mScrollPostPosition); } + + DALI_LOG_SCROLL_STATE("[0x%X] position-changed, mScrollTargetPosition[%.2f, %.2f], mScrollPrePosition[%.2f, %.2f], mScrollPostPosition[%.2f, %.2f]", this, mScrollTargetPosition.x, mScrollTargetPosition.y, mScrollPrePosition.x, mScrollPrePosition.y, mScrollPostPosition.x, mScrollPostPosition.y ); + DALI_LOG_SCROLL_STATE("[0x%X] mPropertyPrePosition[%.2f, %.2f], mPropertyPosition[%.2f, %.2f]", this, self.GetProperty( mPropertyPrePosition ).Get().x, self.GetProperty( mPropertyPrePosition ).Get().y, self.GetProperty( mPropertyPosition ).Get().x, self.GetProperty( mPropertyPosition ).Get().y ); } // Scale Delta /////////////////////////////////////////////////////// @@ -1975,10 +2008,11 @@ void ScrollView::HandleSnapAnimationFinished() UpdateLocalScrollProperties(); WrapPosition(mScrollPrePosition); + DALI_LOG_SCROLL_STATE("[0x%X] Setting mPropertyPrePosition To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y ); self.SetProperty(mPropertyPrePosition, mScrollPrePosition); Vector3 currentScrollPosition = GetCurrentScrollPosition(); - DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 3 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y); + DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignalV2 3 current[%.2f, %.2f], mScrollTargetPosition[%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y, -mScrollTargetPosition.x, -mScrollTargetPosition.y ); mScrollCompletedSignalV2.Emit( currentScrollPosition ); mDomainOffset += deltaPosition - mScrollPostPosition; @@ -2091,17 +2125,19 @@ void ScrollView::OnPropertySet( Property::Index index, Property::Value propertyV { self.GetProperty(mPropertyPrePosition).Get(mScrollPrePosition); propertyValue.Get(mScrollPrePosition.x); + DALI_LOG_SCROLL_STATE("[0x%X] Setting mPropertyPrePosition To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y ); self.SetProperty(mPropertyPrePosition, mScrollPrePosition); } else if( index == mPropertyY ) { self.GetProperty(mPropertyPrePosition).Get(mScrollPrePosition); propertyValue.Get(mScrollPrePosition.y); + DALI_LOG_SCROLL_STATE("[0x%X] Setting mPropertyPrePosition To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y ); self.SetProperty(mPropertyPrePosition, mScrollPrePosition); } else if( index == mPropertyPrePosition ) { - DALI_LOG_SCROLL_STATE("[0x%X]", this); + DALI_LOG_SCROLL_STATE("[0x%X]: mPropertyPrePosition[%.2f, %.2f]", this, propertyValue.Get().x, propertyValue.Get().y); propertyValue.Get(mScrollPrePosition); } } @@ -2127,13 +2163,20 @@ void ScrollView::StopTouchDownTimer() bool ScrollView::OnTouchDownTimeout() { + DALI_LOG_SCROLL_STATE("[0x%X]", this); + mTouchDownTimeoutReached = true; - if( mScrollStateFlags & (SCROLL_ANIMATION_FLAGS | SNAP_ANIMATION_FLAGS) ) + unsigned int currentScrollStateFlags( mScrollStateFlags ); // Cleared in StopAnimation so keep local copy for comparison + if( currentScrollStateFlags & (SCROLL_ANIMATION_FLAGS | SNAP_ANIMATION_FLAGS) ) { + DALI_LOG_SCROLL_STATE("[0x%X] Scrolling Or snapping flags set, stopping animation", this); + StopAnimation(); - if( mScrollStateFlags & SCROLL_ANIMATION_FLAGS ) + if( currentScrollStateFlags & SCROLL_ANIMATION_FLAGS ) { + DALI_LOG_SCROLL_STATE("[0x%X] Scrolling flags set, emitting signal", this); + mScrollInterrupted = true; // reset domain offset as scrolling from original plane. mDomainOffset = Vector3::ZERO; @@ -2153,6 +2196,8 @@ bool ScrollView::OnTouchEvent(const TouchEvent& event) { if(!mSensitive) { + DALI_LOG_SCROLL_STATE("[0x%X], Not Sensitive, ignoring", this); + // Ignore this touch event, if scrollview is insensitive. return false; } @@ -2160,22 +2205,32 @@ bool ScrollView::OnTouchEvent(const TouchEvent& event) // Ignore events with multiple-touch points if (event.GetPointCount() != 1) { + DALI_LOG_SCROLL_STATE("[0x%X], multiple touch, ignoring", this); + return false; } - if( event.GetPoint(0).state == TouchPoint::Down ) + const TouchPoint::State pointState = event.GetPoint(0).state; + if( pointState == TouchPoint::Down ) { + DALI_LOG_SCROLL_STATE("[0x%X] Down", this); + if(mGestureStackDepth==0) { mTouchDownTime = event.time; // This allows time for a pan-gesture to start, to avoid breaking snap-animation behavior with fast flicks. // If touch-down does not become a pan (after timeout interval), then snap-animation can be interrupted. + mTouchDownTimeoutReached = false; + mScrollInterrupted = false; StartTouchDownTimer(); } } - else if( event.GetPoint(0).state == TouchPoint::Up ) + else if( ( pointState == TouchPoint::Up ) || + ( ( pointState == TouchPoint::Interrupted ) && ( event.GetPoint(0).hitActor == Self() ) ) ) { + DALI_LOG_SCROLL_STATE("[0x%X] %s", this, ( ( pointState == TouchPoint::Up ) ? "Up" : "Interrupted" ) ); + StopTouchDownTimer(); // if the user touches and releases without enough movement to go @@ -2183,8 +2238,8 @@ bool ScrollView::OnTouchEvent(const TouchEvent& event) // otherwise our scroll could be stopped (interrupted) half way through an animation. if(mGestureStackDepth==0 && mTouchDownTimeoutReached) { - unsigned timeDelta( event.time - mTouchDownTime ); - if ( timeDelta >= MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET ) + if( ( event.GetPoint(0).state == TouchPoint::Interrupted ) || + ( ( event.time - mTouchDownTime ) >= MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET ) ) { // Reset the velocity only if down was received a while ago mLastVelocity = Vector2( 0.0f, 0.0f ); @@ -2194,6 +2249,8 @@ bool ScrollView::OnTouchEvent(const TouchEvent& event) // Only finish the transform if scrolling was interrupted on down or if we are scrolling if ( mScrollInterrupted || mScrolling ) { + DALI_LOG_SCROLL_STATE("[0x%X] Calling FinishTransform", this); + FinishTransform(); } } @@ -2255,6 +2312,7 @@ void ScrollView::ResetScrolling() Actor self = Self(); self.GetProperty(mPropertyPosition).Get(mScrollPostPosition); mScrollPrePosition = mScrollPostPosition; + DALI_LOG_SCROLL_STATE("[0x%X] Setting mPropertyPrePosition To[%.2f, %.2f]", this, mScrollPostPosition.x, mScrollPostPosition.y ); self.SetProperty(mPropertyPrePosition, mScrollPostPosition); } @@ -2314,7 +2372,9 @@ void ScrollView::AnimateInternalXTo( float position, float duration, AlphaFuncti if( duration > Math::MACHINE_EPSILON_10 ) { Actor self = Self(); + DALI_LOG_SCROLL_STATE("[0x%X], Animating from[%.2f] to[%.2f]", this, self.GetProperty(mPropertyPrePosition).Get().x, position ); mInternalXAnimation = Animation::New(duration); + DALI_LOG_SCROLL_STATE("[0x%X], mInternalXAnimation[0x%X]", this, mInternalXAnimation.GetObjectPtr() ); mInternalXAnimation.FinishedSignal().Connect(this, &ScrollView::OnScrollAnimationFinished); mInternalXAnimation.AnimateTo( Property(self, mPropertyPrePosition, 0), position, alpha, duration); mInternalXAnimation.Play(); @@ -2333,7 +2393,9 @@ void ScrollView::AnimateInternalYTo( float position, float duration, AlphaFuncti if( duration > Math::MACHINE_EPSILON_10 ) { Actor self = Self(); + DALI_LOG_SCROLL_STATE("[0x%X], Animating from[%.2f] to[%.2f]", this, self.GetProperty(mPropertyPrePosition).Get().y, position ); mInternalYAnimation = Animation::New(duration); + DALI_LOG_SCROLL_STATE("[0x%X], mInternalYAnimation[0x%X]", this, mInternalYAnimation.GetObjectPtr() ); mInternalYAnimation.FinishedSignal().Connect(this, &ScrollView::OnScrollAnimationFinished); mInternalYAnimation.AnimateTo( Property(self, mPropertyPrePosition, 1), position, alpha, TimePeriod(duration)); mInternalYAnimation.Play(); @@ -2358,12 +2420,16 @@ void ScrollView::OnScrollAnimationFinished( Animation& source ) if( source == mSnapAnimation ) { + DALI_LOG_SCROLL_STATE("[0x%X] mSnapAnimation[0x%X]", this, mSnapAnimation.GetObjectPtr() ); + // generic snap animation used for scaling and rotation mSnapAnimation.Reset(); } if( source == mInternalXAnimation ) { + DALI_LOG_SCROLL_STATE("[0x%X] mInternalXAnimation[0x%X], expected[%.2f], actual[%.2f], post[%.2f]", this, mInternalXAnimation.GetObjectPtr(), mScrollTargetPosition.x, Self().GetProperty(mPropertyPrePosition).Get().x, mScrollPostPosition.x ); + if( !(mScrollStateFlags & AnimatingInternalY) ) { scrollingFinished = true; @@ -2374,6 +2440,7 @@ void ScrollView::OnScrollAnimationFinished( Animation& source ) { const RulerDomain rulerDomain = mRulerX->GetDomain(); mScrollPrePosition.x = -WrapInDomain(-mScrollPrePosition.x, rulerDomain.min, rulerDomain.max); + DALI_LOG_SCROLL_STATE("[0x%X] Setting mPropertyPrePosition To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y ); handle.SetProperty(mPropertyPrePosition, mScrollPrePosition); } SnapInternalXTo(mScrollPostPosition.x); @@ -2381,6 +2448,8 @@ void ScrollView::OnScrollAnimationFinished( Animation& source ) if( source == mInternalYAnimation ) { + DALI_LOG_SCROLL_STATE("[0x%X] mInternalYAnimation[0x%X], expected[%.2f], actual[%.2f], post[%.2f]", this, mInternalYAnimation.GetObjectPtr(), mScrollTargetPosition.y, Self().GetProperty(mPropertyPrePosition).Get().y, mScrollPostPosition.y ); + if( !(mScrollStateFlags & AnimatingInternalX) ) { scrollingFinished = true; @@ -2391,11 +2460,14 @@ void ScrollView::OnScrollAnimationFinished( Animation& source ) // wrap pre scroll y position and set it const RulerDomain rulerDomain = mRulerY->GetDomain(); mScrollPrePosition.y = -WrapInDomain(-mScrollPrePosition.y, rulerDomain.min, rulerDomain.max); + DALI_LOG_SCROLL_STATE("[0x%X] Setting mPropertyPrePosition To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y ); handle.SetProperty(mPropertyPrePosition, mScrollPrePosition); } SnapInternalYTo(mScrollPostPosition.y); } + DALI_LOG_SCROLL_STATE("[0x%X] scrollingFinished[%d] Animation[0x%X]", this, scrollingFinished, source.GetObjectPtr()); + if(scrollingFinished) { HandleSnapAnimationFinished(); @@ -2408,6 +2480,8 @@ void ScrollView::OnSnapInternalPositionFinished( Animation& source ) UpdateLocalScrollProperties(); if( source == mInternalXAnimation ) { + DALI_LOG_SCROLL_STATE("[0x%X] Finished X PostPosition Animation", this ); + // clear internal x animation flags mScrollStateFlags &= ~SCROLL_X_STATE_MASK; mInternalXAnimation.Reset(); @@ -2415,6 +2489,8 @@ void ScrollView::OnSnapInternalPositionFinished( Animation& source ) } if( source == mInternalYAnimation ) { + DALI_LOG_SCROLL_STATE("[0x%X] Finished Y PostPosition Animation", this ); + mScrollStateFlags &= ~SCROLL_Y_STATE_MASK; mInternalYAnimation.Reset(); WrapPosition(mScrollPrePosition); @@ -2432,8 +2508,11 @@ void ScrollView::SnapInternalXTo(float position) // if internal x not equal to inputed parameter, animate it float duration = std::min(fabsf((position - mScrollPrePosition.x) / mMaxOvershoot.x) * mSnapOvershootDuration, mSnapOvershootDuration); + DALI_LOG_SCROLL_STATE("[0x%X] duration[%.2f]", this, duration ); if( duration > Math::MACHINE_EPSILON_1 ) { + DALI_LOG_SCROLL_STATE("[0x%X] Starting X Snap Animation to[%.2f]", this, position ); + mInternalXAnimation = Animation::New(duration); mInternalXAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapInternalPositionFinished); mInternalXAnimation.AnimateTo(Property(self, mPropertyPrePosition, 0), position); @@ -2455,8 +2534,11 @@ void ScrollView::SnapInternalYTo(float position) // if internal y not equal to inputed parameter, animate it float duration = std::min(fabsf((position - mScrollPrePosition.y) / mMaxOvershoot.y) * mSnapOvershootDuration, mSnapOvershootDuration); + DALI_LOG_SCROLL_STATE("[0x%X] duration[%.2f]", this, duration ); if( duration > Math::MACHINE_EPSILON_1 ) { + DALI_LOG_SCROLL_STATE("[0x%X] Starting Y Snap Animation to[%.2f]", this, position ); + mInternalYAnimation = Animation::New(duration); mInternalYAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapInternalPositionFinished); mInternalYAnimation.AnimateTo(Property(self, mPropertyPrePosition, 1), position); @@ -2644,8 +2726,19 @@ void ScrollView::OnGestureEx(Gesture::State state) mGestureStackDepth--; if(mGestureStackDepth==0) { + // no flick if we have not exceeded min flick distance + if( (fabsf(mPanDelta.x) < mMinFlickDistance.x) + && (fabsf(mPanDelta.y) < mMinFlickDistance.y) ) + { + // reset flick velocity + mLastVelocity = Vector2::ZERO; + } FinishTransform(); } + else + { + DALI_LOG_SCROLL_STATE("[0x%X] mGestureStackDepth[%d]", this, mGestureStackDepth); + } } } @@ -2661,6 +2754,7 @@ void ScrollView::FinishTransform() PreAnimatedScrollSetup(); + // convert pixels/millisecond to pixels per second bool animating = SnapWithVelocity(mLastVelocity * 1000.0f); if(!animating)