END_TEST;
}
+
+// Non-API test (so no P or N variant).
+int UtcDaliToolkitScrollViewGesturePageLimit(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( " UtcDaliToolkitScrollViewGesturePageLimit" );
+
+ // Set up a scrollView.
+ ScrollView scrollView = ScrollView::New();
+
+ // Do not rely on stage size for UTC tests.
+ Vector2 pageSize( 720.0f, 1280.0f );
+ scrollView.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+ scrollView.SetSize( pageSize );
+ scrollView.SetParentOrigin( ParentOrigin::CENTER );
+ scrollView.SetAnchorPoint( AnchorPoint::CENTER );
+ scrollView.SetPosition( 0.0f, 0.0f, 0.0f );
+
+ // Position rulers.
+ // We set the X ruler to fixed to give us pages to snap to.
+ Dali::Toolkit::FixedRuler* rulerX = new Dali::Toolkit::FixedRuler( pageSize.width );
+ // Note: The 3x page width is arbitary, but we need enough to show that we are
+ // capping page movement by the page limiter, and not the domain.
+ rulerX->SetDomain( Dali::Toolkit::RulerDomain( 0.0f, pageSize.width * 3.0f, false ) );
+ Dali::Toolkit::RulerPtr rulerY = new Dali::Toolkit::DefaultRuler();
+ rulerY->Disable();
+ scrollView.SetRulerX( rulerX );
+ scrollView.SetRulerY( rulerY );
+
+ scrollView.SetWrapMode( false );
+ scrollView.SetScrollSensitive( true );
+
+ Stage::GetCurrent().Add( scrollView );
+
+ // Set up a gesture to perform.
+ Vector2 startPos( 50.0f, 0.0f );
+ Vector2 direction( -5.0f, 0.0f );
+ int frames = 200;
+
+ // Force starting position.
+ scrollView.ScrollTo( startPos, 0.0f );
+ Wait( application );
+
+ // Deliberately skip the "Finished" part of the gesture, so we can read the coordinates before the snap begins.
+ Vector2 currentPos( PerformGestureDiagonalSwipe( application, startPos, direction, frames - 1, false ) );
+
+ // Confirm the final X coord has not moved more than one page from the start X position.
+ DALI_TEST_GREATER( ( startPos.x + pageSize.width ), scrollView.GetCurrentScrollPosition().x, TEST_LOCATION );
+
+ // Finish the gesture and wait for the snap.
+ currentPos += direction;
+ SendPan( application, Gesture::Finished, currentPos );
+ // We add RENDER_FRAME_INTERVAL on to wait for an extra frame (for the last "finished" gesture to complete first.
+ Wait( application, RENDER_DELAY_SCROLL + RENDER_FRAME_INTERVAL );
+
+ // Confirm the final X coord has snapped to exactly one page ahead of the start page.
+ DALI_TEST_EQUALS( pageSize.width, scrollView.GetCurrentScrollPosition().x, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+ END_TEST;
+}
*/
struct InternalPrePositionConstraint
{
- InternalPrePositionConstraint(const Vector2& initialPanPosition,
- const Vector2& initialPanMask,
- bool axisAutoLock,
- float axisAutoLockGradient,
- ScrollView::LockAxis initialLockAxis,
- const Vector2& maxOvershoot,
- const RulerDomain& domainX, const RulerDomain& domainY)
- : mLocalStart(initialPanPosition),
- mInitialPanMask(initialPanMask),
- mDomainMin( -domainX.min, -domainY.min ),
- mDomainMax( -domainX.max, -domainY.max ),
- mMaxOvershoot(maxOvershoot),
- mAxisAutoLockGradient(axisAutoLockGradient),
- mLockAxis(initialLockAxis),
- mAxisAutoLock(axisAutoLock),
- mWasPanning(false),
- mClampX( domainX.enabled ),
- mClampY( domainY.enabled )
- {
+ InternalPrePositionConstraint( const Vector2& initialPanPosition,
+ const Vector2& initialPanMask,
+ bool axisAutoLock,
+ float axisAutoLockGradient,
+ ScrollView::LockAxis initialLockAxis,
+ const Vector2& maxOvershoot,
+ const RulerPtr& rulerX, const RulerPtr& rulerY )
+ : mLocalStart( initialPanPosition ),
+ mInitialPanMask( initialPanMask ),
+ mMaxOvershoot( maxOvershoot ),
+ mAxisAutoLockGradient( axisAutoLockGradient ),
+ mLockAxis( initialLockAxis ),
+ mAxisAutoLock( axisAutoLock ),
+ mWasPanning( false )
+ {
+ const RulerDomain& rulerDomainX = rulerX->GetDomain();
+ const RulerDomain& rulerDomainY = rulerY->GetDomain();
+ mDomainMin = Vector2( rulerDomainX.min, -rulerDomainY.min );
+ mDomainMax = Vector2( -rulerDomainX.max, -rulerDomainY.max );
+ mClampX = rulerDomainX.enabled;
+ mClampY = rulerDomainY.enabled;
+ mFixedRulerX = rulerX->GetType() == Ruler::Fixed;
+ mFixedRulerY = rulerY->GetType() == Ruler::Fixed;
}
void operator()( Vector2& scrollPostPosition, const PropertyInputContainer& inputs )
if(!mWasPanning)
{
mPrePosition = scrollPostPosition;
+ mStartPosition = mPrePosition;
mCurrentPanMask = mInitialPanMask;
mWasPanning = true;
}
}
scrollPostPosition.y = newYPosition;
}
+
+ // If we are using a fixed ruler in a particular axis, limit the maximum pages scrolled on that axis.
+ if( mFixedRulerX || mFixedRulerY )
+ {
+ // Here we limit the maximum amount that can be moved from the starting position of the gesture to one page.
+ // We do this only if we have a fixed ruler (on that axis) and the mode is enabled.
+ // Note: 1.0f is subtracted to keep the value within one page size (otherwise we stray on to the page after).
+ // Note: A further 1.0f is subtracted to handle a compensation that happens later within the flick handling code in SnapWithVelocity().
+ // When a flick is completed, an adjustment of 1.0f is sometimes made to allow for the scenario where:
+ // A flick finishes before the update thread has advanced the scroll position past the previous snap point.
+ Vector2 pageSizeLimit( size.x - ( 1.0f + 1.0f ), size.y - ( 1.0f - 1.0f ) );
+ Vector2 minPosition( mStartPosition.x - pageSizeLimit.x, mStartPosition.y - pageSizeLimit.y );
+ Vector2 maxPosition( mStartPosition.x + pageSizeLimit.x, mStartPosition.y + pageSizeLimit.y );
+
+ if( mFixedRulerX )
+ {
+ scrollPostPosition.x = Clamp( scrollPostPosition.x, minPosition.x, maxPosition.x );
+ }
+ if( mFixedRulerY )
+ {
+ scrollPostPosition.y = Clamp( scrollPostPosition.y, minPosition.y, maxPosition.y );
+ }
+ }
}
Vector2 mPrePosition;
Vector2 mLocalStart;
- Vector2 mInitialPanMask; ///< Initial pan mask (based on ruler settings)
+ Vector2 mStartPosition; ///< The start position of the gesture - used to limit scroll amount (not modified by clamping).
+ Vector2 mInitialPanMask; ///< Initial pan mask (based on ruler settings).
Vector2 mCurrentPanMask; ///< Current pan mask that can be altered by axis lock mode.
Vector2 mDomainMin;
Vector2 mDomainMax;
float mAxisAutoLockGradient; ///< Set by ScrollView
ScrollView::LockAxis mLockAxis;
- bool mAxisAutoLock:1; ///< Set by ScrollView
+ bool mAxisAutoLock:1; ///< Set by ScrollView
bool mWasPanning:1;
bool mClampX:1;
bool mClampY:1;
+ bool mFixedRulerX:1;
+ bool mFixedRulerY:1;
};
/**
mMaxFlickSpeed(DEFAULT_MAX_FLICK_SPEED),
mWheelScrollDistanceStep(Vector2::ZERO),
mInAccessibilityPan(false),
- mInitialized(false),
mScrolling(false),
mScrollInterrupted(false),
mPanning(false),
mWheelScrollDistanceStep = Stage::GetCurrent().GetSize() * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
- mInitialized = true;
-
mGestureStackDepth = 0;
EnableGestureDetection( Gesture::Type( Gesture::Pan ) );
mAxisAutoLockGradient,
mLockAxis,
mMaxOvershoot,
- mRulerX->GetDomain(),
- mRulerY->GetDomain() ) );
+ mRulerX,
+ mRulerY ) );
mScrollMainInternalPrePositionConstraint.AddSource( Source( detector, PanGestureDetector::Property::LOCAL_POSITION ) );
mScrollMainInternalPrePositionConstraint.AddSource( Source( self, Actor::Property::SIZE ) );
mScrollMainInternalPrePositionConstraint.Apply();