(ScrollView) Moved constraint related behaviour into a new class 41/265541/3
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Thu, 21 Oct 2021 13:46:01 +0000 (14:46 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Thu, 21 Oct 2021 17:29:21 +0000 (18:29 +0100)
Change-Id: Id55340b53b62f895a4a48bc53674ba3bbd85d986

dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h
dali-toolkit/internal/file.list

diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp
new file mode 100644 (file)
index 0000000..24827dd
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2021 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+
+float FinalDefaultAlphaFunction(float offset)
+{
+  return offset * 0.5f;
+}
+
+/**
+ * Internal Relative position Constraint
+ * Generates the relative position value of the scroll view
+ * based on the absolute position, and it's relation to the
+ * scroll domain. This is a value from 0.0f to 1.0f in each
+ * scroll position axis.
+ */
+void InternalRelativePositionConstraint(Vector2& relativePosition, const PropertyInputContainer& inputs)
+{
+  Vector2        position = -inputs[0]->GetVector2();
+  const Vector2& min      = inputs[1]->GetVector2();
+  const Vector2& max      = inputs[2]->GetVector2();
+  const Vector3& size     = inputs[3]->GetVector3();
+
+  position.x = WrapInDomain(position.x, min.x, max.x);
+  position.y = WrapInDomain(position.y, min.y, max.y);
+
+  Vector2 domainSize = (max - min) - size.GetVectorXY();
+
+  relativePosition.x = domainSize.x > Math::MACHINE_EPSILON_1 ? fabsf((position.x - min.x) / domainSize.x) : 0.0f;
+  relativePosition.y = domainSize.y > Math::MACHINE_EPSILON_1 ? fabsf((position.y - min.y) / domainSize.y) : 0.0f;
+}
+
+/**
+ * Internal scroll domain Constraint
+ * Generates the scroll domain of the scroll view.
+ */
+void InternalScrollDomainConstraint(Vector2& scrollDomain, const PropertyInputContainer& inputs)
+{
+  const Vector2& min  = inputs[0]->GetVector2();
+  const Vector2& max  = inputs[1]->GetVector2();
+  const Vector3& size = inputs[2]->GetVector3();
+
+  scrollDomain = (max - min) - size.GetVectorXY();
+}
+
+/**
+ * Internal maximum scroll position Constraint
+ * Generates the maximum scroll position of the scroll view.
+ */
+void InternalPrePositionMaxConstraint(Vector2& scrollMax, const PropertyInputContainer& inputs)
+{
+  const Vector2& max  = inputs[0]->GetVector2();
+  const Vector3& size = inputs[1]->GetVector3();
+
+  scrollMax = max - size.GetVectorXY();
+}
+
+/**
+ * Internal Pre-Position Property Constraint.
+ *
+ * Generates position property based on current position + gesture displacement.
+ * Or generates position property based on positionX/Y.
+ * Note: This is the position prior to any clamping at scroll boundaries.
+ */
+struct InternalPrePositionConstraint
+{
+  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)
+  {
+    const Vector2& panPosition = inputs[0]->GetVector2();
+    const bool&    inGesture   = inputs[1]->GetBoolean();
+
+    // First check if we are within a gesture.
+    // The ScrollView may have received a start gesture from ::OnPan()
+    // while the finish gesture is received now in this constraint.
+    // This gesture must then be rejected as the value will be "old".
+    // Typically the last value from the end of the last gesture.
+    // If we are rejecting the gesture, we simply don't modify the constraint target.
+    if(inGesture)
+    {
+      if(!mWasPanning)
+      {
+        mPrePosition    = scrollPostPosition;
+        mStartPosition  = mPrePosition;
+        mCurrentPanMask = mInitialPanMask;
+        mWasPanning     = true;
+      }
+
+      // Calculate Deltas...
+      const Vector2& currentPosition = panPosition;
+      Vector2        panDelta(currentPosition - mLocalStart);
+
+      // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
+      // appears mostly horizontal or mostly vertical respectively...
+      if(mAxisAutoLock)
+      {
+        mLockAxis = GetLockAxis(panDelta, mLockAxis, mAxisAutoLockGradient);
+        if(mLockAxis == ScrollView::LockVertical)
+        {
+          mCurrentPanMask.y = 0.0f;
+        }
+        else if(mLockAxis == ScrollView::LockHorizontal)
+        {
+          mCurrentPanMask.x = 0.0f;
+        }
+      }
+
+      // Restrict deltas based on ruler enable/disable and axis-lock state...
+      panDelta *= mCurrentPanMask;
+
+      // Perform Position transform based on input deltas...
+      scrollPostPosition = mPrePosition;
+      scrollPostPosition += panDelta;
+
+      // if no wrapping then clamp preposition to maximum overshoot amount
+      const Vector3& size = inputs[2]->GetVector3();
+      if(mClampX)
+      {
+        float newXPosition = Clamp(scrollPostPosition.x, (mDomainMax.x + size.x) - mMaxOvershoot.x, mDomainMin.x + mMaxOvershoot.x);
+        if((newXPosition < scrollPostPosition.x - Math::MACHINE_EPSILON_1) || (newXPosition > scrollPostPosition.x + Math::MACHINE_EPSILON_1))
+        {
+          mPrePosition.x = newXPosition;
+          mLocalStart.x  = panPosition.x;
+        }
+        scrollPostPosition.x = newXPosition;
+      }
+      if(mClampY)
+      {
+        float newYPosition = Clamp(scrollPostPosition.y, (mDomainMax.y + size.y) - mMaxOvershoot.y, mDomainMin.y + mMaxOvershoot.y);
+        if((newYPosition < scrollPostPosition.y - Math::MACHINE_EPSILON_1) || (newYPosition > scrollPostPosition.y + Math::MACHINE_EPSILON_1))
+        {
+          mPrePosition.y = newYPosition;
+          mLocalStart.y  = panPosition.y;
+        }
+        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 viewPageSizeLimit(size.x - (1.0f + 1.0f), size.y - (1.0f - 1.0f));
+        Vector2 minPosition(mStartPosition.x - viewPageSizeLimit.x, mStartPosition.y - viewPageSizeLimit.y);
+        Vector2 maxPosition(mStartPosition.x + viewPageSizeLimit.x, mStartPosition.y + viewPageSizeLimit.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 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;
+  Vector2 mMaxOvershoot;
+
+  float                mAxisAutoLockGradient; ///< Set by ScrollView
+  ScrollView::LockAxis mLockAxis;
+
+  bool mAxisAutoLock : 1; ///< Set by ScrollView
+  bool mWasPanning : 1;
+  bool mClampX : 1;
+  bool mClampY : 1;
+  bool mFixedRulerX : 1;
+  bool mFixedRulerY : 1;
+};
+
+/**
+ * Internal Position Property Constraint.
+ *
+ * Generates position property based on pre-position
+ * Note: This is the position after clamping.
+ * (uses result of InternalPrePositionConstraint)
+ */
+struct InternalPositionConstraint
+{
+  InternalPositionConstraint(const RulerDomain& domainX, const RulerDomain& domainY, bool wrap)
+  : mDomainMin(-domainX.min, -domainY.min),
+    mDomainMax(-domainX.max, -domainY.max),
+    mClampX(domainX.enabled),
+    mClampY(domainY.enabled),
+    mWrap(wrap)
+  {
+  }
+
+  void operator()(Vector2& position, const PropertyInputContainer& inputs)
+  {
+    position            = inputs[0]->GetVector2();
+    const Vector2& size = inputs[3]->GetVector3().GetVectorXY();
+    const Vector2& min  = inputs[1]->GetVector2();
+    const Vector2& max  = inputs[2]->GetVector2();
+
+    if(mWrap)
+    {
+      position.x = -WrapInDomain(-position.x, min.x, max.x);
+      position.y = -WrapInDomain(-position.y, min.y, max.y);
+    }
+    else
+    {
+      // clamp post position to domain
+      position.x = mClampX ? Clamp(position.x, mDomainMax.x + size.x, mDomainMin.x) : position.x;
+      position.y = mClampY ? Clamp(position.y, mDomainMax.y + size.y, mDomainMin.y) : position.y;
+    }
+  }
+
+  Vector2 mDomainMin;
+  Vector2 mDomainMax;
+  bool    mClampX;
+  bool    mClampY;
+  bool    mWrap;
+};
+
+/**
+ * This constraint updates the X overshoot property using the difference
+ * SCROLL_PRE_POSITION.x and SCROLL_POSITION.x, returning a relative value between 0.0f and 1.0f
+ */
+struct OvershootXConstraint
+{
+  OvershootXConstraint(float maxOvershoot)
+  : mMaxOvershoot(maxOvershoot)
+  {
+  }
+
+  void operator()(float& current, const PropertyInputContainer& inputs)
+  {
+    if(inputs[2]->GetBoolean())
+    {
+      const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
+      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
+      float          newOvershoot       = scrollPrePosition.x - scrollPostPosition.x;
+      current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
+    }
+    else
+    {
+      current = 0.0f;
+    }
+  }
+
+  float mMaxOvershoot;
+};
+
+/**
+ * This constraint updates the Y overshoot property using the difference
+ * SCROLL_PRE_POSITION.y and SCROLL_POSITION.y, returning a relative value between 0.0f and 1.0f
+ */
+struct OvershootYConstraint
+{
+  OvershootYConstraint(float maxOvershoot)
+  : mMaxOvershoot(maxOvershoot)
+  {
+  }
+
+  void operator()(float& current, const PropertyInputContainer& inputs)
+  {
+    if(inputs[2]->GetBoolean())
+    {
+      const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
+      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
+      float          newOvershoot       = scrollPrePosition.y - scrollPostPosition.y;
+      current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
+    }
+    else
+    {
+      current = 0.0f;
+    }
+  }
+
+  float mMaxOvershoot;
+};
+
+/**
+ * Internal Position-Delta Property Constraint.
+ *
+ * Generates position-delta property based on scroll-position + scroll-offset properties.
+ */
+void InternalPositionDeltaConstraint(Vector2& current, const PropertyInputContainer& inputs)
+{
+  const Vector2& scrollPosition = inputs[0]->GetVector2();
+  const Vector2& scrollOffset   = inputs[1]->GetVector2();
+
+  current = scrollPosition + scrollOffset;
+}
+
+/**
+ * Internal Final Position Constraint
+ * The position of content is:
+ * of scroll-position + f(scroll-overshoot)
+ * where f(...) function defines how overshoot
+ * should affect final-position.
+ */
+struct InternalFinalConstraint
+{
+  InternalFinalConstraint(AlphaFunctionPrototype functionX,
+                          AlphaFunctionPrototype functionY)
+  : mFunctionX(functionX),
+    mFunctionY(functionY)
+  {
+  }
+
+  void operator()(Vector2& current, const PropertyInputContainer& inputs)
+  {
+    const float& overshootx = inputs[1]->GetFloat();
+    const float& overshooty = inputs[2]->GetFloat();
+    Vector2      offset(mFunctionX(overshootx),
+                   mFunctionY(overshooty));
+
+    current = inputs[0]->GetVector2() - offset;
+  }
+
+  AlphaFunctionPrototype mFunctionX;
+  AlphaFunctionPrototype mFunctionY;
+};
+
+} // namespace
+
+void ScrollViewConstraints::UpdateMainInternalConstraint(ScrollView& scrollView)
+{
+  // TODO: Only update the constraints which have changed, rather than remove all and add all again.
+  // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
+  Actor              scrollViewActor = scrollView.Self();
+  PanGestureDetector detector(scrollView.GetPanGestureDetector());
+
+  if(mScrollMainInternalPositionConstraint)
+  {
+    mScrollMainInternalPositionConstraint.Remove();
+    mScrollMainInternalDeltaConstraint.Remove();
+    mScrollMainInternalFinalConstraint.Remove();
+    mScrollMainInternalRelativeConstraint.Remove();
+    mScrollMainInternalDomainConstraint.Remove();
+    mScrollMainInternalPrePositionMaxConstraint.Remove();
+  }
+  if(mScrollMainInternalPrePositionConstraint)
+  {
+    mScrollMainInternalPrePositionConstraint.Remove();
+  }
+
+  // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
+  // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
+
+  // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
+  Vector2 initialPanMask = Vector2(scrollView.mRulerX->IsEnabled() ? 1.0f : 0.0f, scrollView.mRulerY->IsEnabled() ? 1.0f : 0.0f);
+
+  if(scrollView.mLockAxis == ScrollView::LockVertical)
+  {
+    initialPanMask.y = 0.0f;
+  }
+  else if(scrollView.mLockAxis == ScrollView::LockHorizontal)
+  {
+    initialPanMask.x = 0.0f;
+  }
+
+  if(scrollView.mPanning)
+  {
+    mScrollMainInternalPrePositionConstraint = Constraint::New<Vector2>(scrollViewActor,
+                                                                        Toolkit::ScrollView::Property::SCROLL_PRE_POSITION,
+                                                                        InternalPrePositionConstraint(scrollView.mPanStartPosition,
+                                                                                                      initialPanMask,
+                                                                                                      scrollView.mAxisAutoLock,
+                                                                                                      scrollView.mAxisAutoLockGradient,
+                                                                                                      scrollView.mLockAxis,
+                                                                                                      scrollView.mMaxOvershoot,
+                                                                                                      scrollView.mRulerX,
+                                                                                                      scrollView.mRulerY));
+    mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::LOCAL_POSITION));
+    mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::PANNING));
+    mScrollMainInternalPrePositionConstraint.AddSource(Source(scrollViewActor, Actor::Property::SIZE));
+    mScrollMainInternalPrePositionConstraint.Apply();
+  }
+
+  // 2. Second calculate the clamped position (actual position)
+  mScrollMainInternalPositionConstraint = Constraint::New<Vector2>(scrollViewActor,
+                                                                   Toolkit::ScrollView::Property::SCROLL_POSITION,
+                                                                   InternalPositionConstraint(scrollView.mRulerX->GetDomain(),
+                                                                                              scrollView.mRulerY->GetDomain(),
+                                                                                              scrollView.mWrapMode));
+  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
+  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
+  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  mScrollMainInternalPositionConstraint.AddSource(Source(scrollViewActor, Actor::Property::SIZE));
+  mScrollMainInternalPositionConstraint.Apply();
+
+  mScrollMainInternalDeltaConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_POSITION_DELTA, InternalPositionDeltaConstraint);
+  mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+  mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET));
+  mScrollMainInternalDeltaConstraint.Apply();
+
+  mScrollMainInternalFinalConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_FINAL, InternalFinalConstraint(FinalDefaultAlphaFunction, FinalDefaultAlphaFunction));
+  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_X));
+  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_Y));
+  mScrollMainInternalFinalConstraint.Apply();
+
+  mScrollMainInternalRelativeConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_RELATIVE_POSITION, InternalRelativePositionConstraint);
+  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
+  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Actor::Property::SIZE));
+  mScrollMainInternalRelativeConstraint.Apply();
+
+  mScrollMainInternalDomainConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_DOMAIN_SIZE, InternalScrollDomainConstraint);
+  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
+  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Actor::Property::SIZE));
+  mScrollMainInternalDomainConstraint.Apply();
+
+  mScrollMainInternalPrePositionMaxConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_MAX, InternalPrePositionMaxConstraint);
+  mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Actor::Property::SIZE));
+  mScrollMainInternalPrePositionMaxConstraint.Apply();
+
+  // When panning we want to make sure overshoot values are affected by pre position and post position
+  SetOvershootConstraintsEnabled(scrollView, !scrollView.mWrapMode);
+}
+
+void ScrollViewConstraints::SetOvershootConstraintsEnabled(ScrollView& scrollView, bool enabled)
+{
+  Actor scrollViewActor(scrollView.Self());
+  // remove and reset, it may now be in wrong order with the main internal constraints
+  if(mScrollMainInternalOvershootXConstraint)
+  {
+    mScrollMainInternalOvershootXConstraint.Remove();
+    mScrollMainInternalOvershootXConstraint.Reset();
+    mScrollMainInternalOvershootYConstraint.Remove();
+    mScrollMainInternalOvershootYConstraint.Reset();
+  }
+  if(enabled)
+  {
+    mScrollMainInternalOvershootXConstraint = Constraint::New<float>(scrollViewActor, Toolkit::ScrollView::Property::OVERSHOOT_X, OvershootXConstraint(scrollView.mMaxOvershoot.x));
+    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
+    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL));
+    mScrollMainInternalOvershootXConstraint.Apply();
+
+    mScrollMainInternalOvershootYConstraint = Constraint::New<float>(scrollViewActor, Toolkit::ScrollView::Property::OVERSHOOT_Y, OvershootYConstraint(scrollView.mMaxOvershoot.y));
+    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
+    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL));
+    mScrollMainInternalOvershootYConstraint.Apply();
+  }
+  else
+  {
+    scrollViewActor.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_X, 0.0f);
+    scrollViewActor.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_Y, 0.0f);
+  }
+}
+
+void ScrollViewConstraints::SetInternalConstraints(ScrollView& scrollView)
+{
+  // Internal constraints (applied to target ScrollBase Actor itself) /////////
+  UpdateMainInternalConstraint(scrollView);
+
+  // User definable constraints to apply to all child actors //////////////////
+  Actor scrollViewActor = scrollView.Self();
+
+  // Apply some default constraints to ScrollView & its bound actors
+  // Movement + Wrap function
+
+  Constraint constraint;
+
+  // MoveActor (scrolling)
+  constraint = Constraint::New<Vector3>(scrollViewActor, Actor::Property::POSITION, MoveActorConstraint);
+  constraint.AddSource(Source(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_POSITION));
+  constraint.SetRemoveAction(Constraint::DISCARD);
+  scrollView.ApplyConstraintToBoundActors(constraint);
+
+  // WrapActor (wrap functionality)
+  constraint = Constraint::New<Vector3>(scrollViewActor, Actor::Property::POSITION, WrapActorConstraint);
+  constraint.AddSource(LocalSource(Actor::Property::SCALE));
+  constraint.AddSource(LocalSource(Actor::Property::ANCHOR_POINT));
+  constraint.AddSource(LocalSource(Actor::Property::SIZE));
+  constraint.AddSource(Source(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
+  constraint.AddSource(Source(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  constraint.AddSource(Source(scrollViewActor, Toolkit::ScrollView::Property::WRAP));
+  constraint.SetRemoveAction(Constraint::DISCARD);
+  scrollView.ApplyConstraintToBoundActors(constraint);
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h
new file mode 100644 (file)
index 0000000..540a3fd
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_CONSTRAINTS_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_CONSTRAINTS_H
+
+/*
+ * Copyright (c) 2021 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraint.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class ScrollView;
+
+/// Sets up and owns the Constraints used by the ScrollView class
+class ScrollViewConstraints
+{
+public:
+
+  ScrollViewConstraints() = default;  ///< Default Constructor
+  ~ScrollViewConstraints() = default; ///< Default Non-Virtual Destructor
+
+  // Not copyable or moveable
+  ScrollViewConstraints(const ScrollViewConstraints&) = delete;
+  ScrollViewConstraints(ScrollViewConstraints&&) = delete;
+  ScrollViewConstraints& operator=(const ScrollViewConstraints&) = delete;
+  ScrollViewConstraints& operator=(ScrollViewConstraints&&) = delete;
+
+  /**
+   * Updates the main internal scroll constraints with new ruler and domain values
+   *
+   * @param[in] scrollView A reference to the scroll view object
+   */
+  void UpdateMainInternalConstraint(Internal::ScrollView& scrollView);
+
+  /**
+   * Enables/disables the overshoot constraints
+   *
+   * @param[in] scrollView A reference to the scroll view object
+   * @param[in] enabled whether to enable or disable the overshoot constraints
+   */
+  void SetOvershootConstraintsEnabled(ScrollView& scrollView, bool enabled);
+
+  /**
+   * Sets internal constraints for this ScrollView.
+   * Many of these internal constraints are based on properties within ScrollView.
+   *
+   * @param[in] scrollView A reference to the scroll view object
+   */
+  void SetInternalConstraints(ScrollView& scrollView);
+
+public:
+
+  Constraint mScrollMainInternalPrePositionConstraint;
+  Constraint mScrollMainInternalPositionConstraint;
+  Constraint mScrollMainInternalOvershootXConstraint;
+  Constraint mScrollMainInternalOvershootYConstraint;
+  Constraint mScrollMainInternalDeltaConstraint;
+  Constraint mScrollMainInternalFinalConstraint;
+  Constraint mScrollMainInternalRelativeConstraint;
+  Constraint mScrollMainInternalDomainConstraint;
+  Constraint mScrollMainInternalPrePositionMaxConstraint;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_CONSTRAINTS_H
index 708830f..2473439 100644 (file)
 // TODO: Orientation.
 // TODO: upgrade Vector2/3 to support returning Unit vectors, normals, & cross product (dot product is already provided)
 
-using namespace Dali;
-
 namespace
 {
-const float DEFAULT_SLOW_SNAP_ANIMATION_DURATION(0.5f);  ///< Default Drag-Release animation time.
-const float DEFAULT_FAST_SNAP_ANIMATION_DURATION(0.25f); ///< Default Drag-Flick animation time.
-const float DEFAULT_SNAP_OVERSHOOT_DURATION(0.5f);       ///< Default Overshoot snapping animation time.
-const float DEFAULT_MAX_OVERSHOOT(100.0f);               ///< Default maximum allowed overshoot in pixels
-
-const float DEFAULT_AXIS_AUTO_LOCK_GRADIENT(0.36f); ///< Default Axis-AutoLock gradient threshold. default is 0.36:1 (20 degrees)
-const float DEFAULT_FRICTION_COEFFICIENT(1.0f);     ///< Default Friction Co-efficient. (in stage diagonals per second)
-const float DEFAULT_FLICK_SPEED_COEFFICIENT(1.0f);  ///< Default Flick speed coefficient (multiples input touch velocity)
-const float DEFAULT_MAX_FLICK_SPEED(3.0f);          ///< Default Maximum flick speed. (in stage diagonals per second)
-
-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                       = 75.0f;                ///< degrees. (if >45, then supports diagonal flicking)
-const Vector2       DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = Vector2(0.17f, 0.1f); ///< The step of horizontal scroll distance in the proportion of stage size for each wheel event received.
-const unsigned long MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET(150u);
-const float         TOUCH_DOWN_TIMER_INTERVAL = 100.0f;
-const float         DEFAULT_SCROLL_UPDATE_DISTANCE(30.0f); ///< Default distance to travel in pixels for scroll update signal
+using namespace Dali;
+
+constexpr float DEFAULT_SLOW_SNAP_ANIMATION_DURATION(0.5f);  ///< Default Drag-Release animation time.
+constexpr float DEFAULT_FAST_SNAP_ANIMATION_DURATION(0.25f); ///< Default Drag-Flick animation time.
+constexpr float DEFAULT_SNAP_OVERSHOOT_DURATION(0.5f);       ///< Default Overshoot snapping animation time.
+constexpr float DEFAULT_MAX_OVERSHOOT(100.0f);               ///< Default maximum allowed overshoot in pixels
+
+constexpr float DEFAULT_AXIS_AUTO_LOCK_GRADIENT(0.36f); ///< Default Axis-AutoLock gradient threshold. default is 0.36:1 (20 degrees)
+constexpr float DEFAULT_FRICTION_COEFFICIENT(1.0f);     ///< Default Friction Co-efficient. (in stage diagonals per second)
+constexpr float DEFAULT_FLICK_SPEED_COEFFICIENT(1.0f);  ///< Default Flick speed coefficient (multiples input touch velocity)
+constexpr float DEFAULT_MAX_FLICK_SPEED(3.0f);          ///< Default Maximum flick speed. (in stage diagonals per second)
+
+constexpr Dali::Vector2 DEFAULT_MIN_FLICK_DISTANCE(30.0f, 30.0f);  ///< minimum distance for pan before flick allowed
+constexpr float         DEFAULT_MIN_FLICK_SPEED_THRESHOLD(500.0f); ///< Minimum pan speed required for flick in pixels/s
+
+constexpr float FREE_FLICK_SPEED_THRESHOLD      = 200.0f; ///< Free-Flick threshold in pixels/ms
+constexpr float AUTOLOCK_AXIS_MINIMUM_DISTANCE2 = 100.0f; ///< Auto-lock axis after minimum distance squared.
+constexpr float FLICK_ORTHO_ANGLE_RANGE         = 75.0f;  ///< degrees. (if >45, then supports diagonal flicking)
+
+constexpr Dali::Vector2 DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION(0.17f, 0.1f); ///< The step of horizontal scroll distance in the proportion of stage size for each wheel event received.
+
+constexpr unsigned long MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET(150u);
+constexpr float         TOUCH_DOWN_TIMER_INTERVAL = 100.0f;
+constexpr float         DEFAULT_SCROLL_UPDATE_DISTANCE(30.0f); ///< Default distance to travel in pixels for scroll update signal
 
 const std::string INTERNAL_MAX_POSITION_PROPERTY_NAME("internalMaxPosition");
 
@@ -104,7 +107,7 @@ float VectorInDomain(float a, float b, float start, float end, Dali::Toolkit::Di
 {
   if(bias == Dali::Toolkit::DIRECTION_BIAS_NONE)
   {
-    return ShortestDistanceInDomain(a, b, start, end);
+    return Dali::ShortestDistanceInDomain(a, b, start, end);
   }
   //  (a-start + end-b)
   float size = end - start;
@@ -145,11 +148,11 @@ float VectorInDomain(float a, float b, float start, float end, Dali::Toolkit::Di
  * @param anchor The Anchor point of interest.
  * @return The position of the Anchor
  */
-Vector3 GetPositionOfAnchor(Actor& actor, const Vector3& anchor)
+Dali::Vector3 GetPositionOfAnchor(Dali::Actor& actor, const Dali::Vector3& anchor)
 {
-  Vector3 childPosition = actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
-  Vector3 childAnchor   = -actor.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) + anchor;
-  Vector3 childSize     = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE);
+  Dali::Vector3 childPosition = actor.GetCurrentProperty<Dali::Vector3>(Dali::Actor::Property::POSITION);
+  Dali::Vector3 childAnchor   = -actor.GetCurrentProperty<Dali::Vector3>(Dali::Actor::Property::ANCHOR_POINT) + anchor;
+  Dali::Vector3 childSize     = actor.GetCurrentProperty<Dali::Vector3>(Dali::Actor::Property::SIZE);
 
   return childPosition + childAnchor * childSize;
 }
@@ -257,11 +260,6 @@ Actor FindClosestActorToPosition(
 
 // AlphaFunctions /////////////////////////////////////////////////////////////////////////////////
 
-float FinalDefaultAlphaFunction(float offset)
-{
-  return offset * 0.5f;
-}
-
 /**
  * ConstantDecelerationAlphaFunction
  * Newtoninan distance for constant deceleration
@@ -278,56 +276,6 @@ float ConstantDecelerationAlphaFunction(float progress)
   return progress * 2.0f - progress * progress;
 }
 
-// Internal Constraints ///////////////////////////////////////////////////////////////////////////
-
-/**
- * Internal Relative position Constraint
- * Generates the relative position value of the scroll view
- * based on the absolute position, and it's relation to the
- * scroll domain. This is a value from 0.0f to 1.0f in each
- * scroll position axis.
- */
-void InternalRelativePositionConstraint(Vector2& relativePosition, const PropertyInputContainer& inputs)
-{
-  Vector2        position = -inputs[0]->GetVector2();
-  const Vector2& min      = inputs[1]->GetVector2();
-  const Vector2& max      = inputs[2]->GetVector2();
-  const Vector3& size     = inputs[3]->GetVector3();
-
-  position.x = WrapInDomain(position.x, min.x, max.x);
-  position.y = WrapInDomain(position.y, min.y, max.y);
-
-  Vector2 domainSize = (max - min) - size.GetVectorXY();
-
-  relativePosition.x = domainSize.x > Math::MACHINE_EPSILON_1 ? fabsf((position.x - min.x) / domainSize.x) : 0.0f;
-  relativePosition.y = domainSize.y > Math::MACHINE_EPSILON_1 ? fabsf((position.y - min.y) / domainSize.y) : 0.0f;
-}
-
-/**
- * Internal scroll domain Constraint
- * Generates the scroll domain of the scroll view.
- */
-void InternalScrollDomainConstraint(Vector2& scrollDomain, const PropertyInputContainer& inputs)
-{
-  const Vector2& min  = inputs[0]->GetVector2();
-  const Vector2& max  = inputs[1]->GetVector2();
-  const Vector3& size = inputs[2]->GetVector3();
-
-  scrollDomain = (max - min) - size.GetVectorXY();
-}
-
-/**
- * Internal maximum scroll position Constraint
- * Generates the maximum scroll position of the scroll view.
- */
-void InternalPrePositionMaxConstraint(Vector2& scrollMax, const PropertyInputContainer& inputs)
-{
-  const Vector2& max  = inputs[0]->GetVector2();
-  const Vector3& size = inputs[1]->GetVector3();
-
-  scrollMax = max - size.GetVectorXY();
-}
-
 /**
  * Clamp a position
  * @param[in] size The size to clamp to
@@ -631,336 +579,6 @@ DALI_SIGNAL_REGISTRATION(Toolkit, ScrollView, "valueChanged", SIGNAL_SNAP_STARTE
 
 DALI_TYPE_REGISTRATION_END()
 
-/**
- * Returns whether to lock scrolling to a particular axis
- *
- * @param[in] panDelta Distance panned since gesture started
- * @param[in] currentLockAxis The current lock axis value
- * @param[in] lockGradient How quickly to lock to a particular axis
- *
- * @return The new axis lock state
- */
-ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient)
-{
-  if(panDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
-     currentLockAxis == ScrollView::LockPossible)
-  {
-    float dx = fabsf(panDelta.x);
-    float dy = fabsf(panDelta.y);
-    if(dx * lockGradient >= dy)
-    {
-      // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
-      currentLockAxis = ScrollView::LockVertical;
-    }
-    else if(dy * lockGradient > dx)
-    {
-      // 0.36:1 gradient to the vertical (deviate < 20 degrees)
-      currentLockAxis = ScrollView::LockHorizontal;
-    }
-    else
-    {
-      currentLockAxis = ScrollView::LockNone;
-    }
-  }
-  return currentLockAxis;
-}
-
-/**
- * Internal Pre-Position Property Constraint.
- *
- * Generates position property based on current position + gesture displacement.
- * Or generates position property based on positionX/Y.
- * Note: This is the position prior to any clamping at scroll boundaries.
- */
-struct InternalPrePositionConstraint
-{
-  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)
-  {
-    const Vector2& panPosition = inputs[0]->GetVector2();
-    const bool&    inGesture   = inputs[1]->GetBoolean();
-
-    // First check if we are within a gesture.
-    // The ScrollView may have received a start gesture from ::OnPan()
-    // while the finish gesture is received now in this constraint.
-    // This gesture must then be rejected as the value will be "old".
-    // Typically the last value from the end of the last gesture.
-    // If we are rejecting the gesture, we simply don't modify the constraint target.
-    if(inGesture)
-    {
-      if(!mWasPanning)
-      {
-        mPrePosition    = scrollPostPosition;
-        mStartPosition  = mPrePosition;
-        mCurrentPanMask = mInitialPanMask;
-        mWasPanning     = true;
-      }
-
-      // Calculate Deltas...
-      const Vector2& currentPosition = panPosition;
-      Vector2        panDelta(currentPosition - mLocalStart);
-
-      // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
-      // appears mostly horizontal or mostly vertical respectively...
-      if(mAxisAutoLock)
-      {
-        mLockAxis = GetLockAxis(panDelta, mLockAxis, mAxisAutoLockGradient);
-        if(mLockAxis == ScrollView::LockVertical)
-        {
-          mCurrentPanMask.y = 0.0f;
-        }
-        else if(mLockAxis == ScrollView::LockHorizontal)
-        {
-          mCurrentPanMask.x = 0.0f;
-        }
-      }
-
-      // Restrict deltas based on ruler enable/disable and axis-lock state...
-      panDelta *= mCurrentPanMask;
-
-      // Perform Position transform based on input deltas...
-      scrollPostPosition = mPrePosition;
-      scrollPostPosition += panDelta;
-
-      // if no wrapping then clamp preposition to maximum overshoot amount
-      const Vector3& size = inputs[2]->GetVector3();
-      if(mClampX)
-      {
-        float newXPosition = Clamp(scrollPostPosition.x, (mDomainMax.x + size.x) - mMaxOvershoot.x, mDomainMin.x + mMaxOvershoot.x);
-        if((newXPosition < scrollPostPosition.x - Math::MACHINE_EPSILON_1) || (newXPosition > scrollPostPosition.x + Math::MACHINE_EPSILON_1))
-        {
-          mPrePosition.x = newXPosition;
-          mLocalStart.x  = panPosition.x;
-        }
-        scrollPostPosition.x = newXPosition;
-      }
-      if(mClampY)
-      {
-        float newYPosition = Clamp(scrollPostPosition.y, (mDomainMax.y + size.y) - mMaxOvershoot.y, mDomainMin.y + mMaxOvershoot.y);
-        if((newYPosition < scrollPostPosition.y - Math::MACHINE_EPSILON_1) || (newYPosition > scrollPostPosition.y + Math::MACHINE_EPSILON_1))
-        {
-          mPrePosition.y = newYPosition;
-          mLocalStart.y  = panPosition.y;
-        }
-        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 viewPageSizeLimit(size.x - (1.0f + 1.0f), size.y - (1.0f - 1.0f));
-        Vector2 minPosition(mStartPosition.x - viewPageSizeLimit.x, mStartPosition.y - viewPageSizeLimit.y);
-        Vector2 maxPosition(mStartPosition.x + viewPageSizeLimit.x, mStartPosition.y + viewPageSizeLimit.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 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;
-  Vector2 mMaxOvershoot;
-
-  float                mAxisAutoLockGradient; ///< Set by ScrollView
-  ScrollView::LockAxis mLockAxis;
-
-  bool mAxisAutoLock : 1; ///< Set by ScrollView
-  bool mWasPanning : 1;
-  bool mClampX : 1;
-  bool mClampY : 1;
-  bool mFixedRulerX : 1;
-  bool mFixedRulerY : 1;
-};
-
-/**
- * Internal Position Property Constraint.
- *
- * Generates position property based on pre-position
- * Note: This is the position after clamping.
- * (uses result of InternalPrePositionConstraint)
- */
-struct InternalPositionConstraint
-{
-  InternalPositionConstraint(const RulerDomain& domainX, const RulerDomain& domainY, bool wrap)
-  : mDomainMin(-domainX.min, -domainY.min),
-    mDomainMax(-domainX.max, -domainY.max),
-    mClampX(domainX.enabled),
-    mClampY(domainY.enabled),
-    mWrap(wrap)
-  {
-  }
-
-  void operator()(Vector2& position, const PropertyInputContainer& inputs)
-  {
-    position            = inputs[0]->GetVector2();
-    const Vector2& size = inputs[3]->GetVector3().GetVectorXY();
-    const Vector2& min  = inputs[1]->GetVector2();
-    const Vector2& max  = inputs[2]->GetVector2();
-
-    if(mWrap)
-    {
-      position.x = -WrapInDomain(-position.x, min.x, max.x);
-      position.y = -WrapInDomain(-position.y, min.y, max.y);
-    }
-    else
-    {
-      // clamp post position to domain
-      position.x = mClampX ? Clamp(position.x, mDomainMax.x + size.x, mDomainMin.x) : position.x;
-      position.y = mClampY ? Clamp(position.y, mDomainMax.y + size.y, mDomainMin.y) : position.y;
-    }
-  }
-
-  Vector2 mDomainMin;
-  Vector2 mDomainMax;
-  bool    mClampX;
-  bool    mClampY;
-  bool    mWrap;
-};
-
-/**
- * This constraint updates the X overshoot property using the difference
- * SCROLL_PRE_POSITION.x and SCROLL_POSITION.x, returning a relative value between 0.0f and 1.0f
- */
-struct OvershootXConstraint
-{
-  OvershootXConstraint(float maxOvershoot)
-  : mMaxOvershoot(maxOvershoot)
-  {
-  }
-
-  void operator()(float& current, const PropertyInputContainer& inputs)
-  {
-    if(inputs[2]->GetBoolean())
-    {
-      const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
-      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
-      float          newOvershoot       = scrollPrePosition.x - scrollPostPosition.x;
-      current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
-    }
-    else
-    {
-      current = 0.0f;
-    }
-  }
-
-  float mMaxOvershoot;
-};
-
-/**
- * This constraint updates the Y overshoot property using the difference
- * SCROLL_PRE_POSITION.y and SCROLL_POSITION.y, returning a relative value between 0.0f and 1.0f
- */
-struct OvershootYConstraint
-{
-  OvershootYConstraint(float maxOvershoot)
-  : mMaxOvershoot(maxOvershoot)
-  {
-  }
-
-  void operator()(float& current, const PropertyInputContainer& inputs)
-  {
-    if(inputs[2]->GetBoolean())
-    {
-      const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
-      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
-      float          newOvershoot       = scrollPrePosition.y - scrollPostPosition.y;
-      current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
-    }
-    else
-    {
-      current = 0.0f;
-    }
-  }
-
-  float mMaxOvershoot;
-};
-
-/**
- * Internal Position-Delta Property Constraint.
- *
- * Generates position-delta property based on scroll-position + scroll-offset properties.
- */
-void InternalPositionDeltaConstraint(Vector2& current, const PropertyInputContainer& inputs)
-{
-  const Vector2& scrollPosition = inputs[0]->GetVector2();
-  const Vector2& scrollOffset   = inputs[1]->GetVector2();
-
-  current = scrollPosition + scrollOffset;
-}
-
-/**
- * Internal Final Position Constraint
- * The position of content is:
- * of scroll-position + f(scroll-overshoot)
- * where f(...) function defines how overshoot
- * should affect final-position.
- */
-struct InternalFinalConstraint
-{
-  InternalFinalConstraint(AlphaFunctionPrototype functionX,
-                          AlphaFunctionPrototype functionY)
-  : mFunctionX(functionX),
-    mFunctionY(functionY)
-  {
-  }
-
-  void operator()(Vector2& current, const PropertyInputContainer& inputs)
-  {
-    const float& overshootx = inputs[1]->GetFloat();
-    const float& overshooty = inputs[2]->GetFloat();
-    Vector2      offset(mFunctionX(overshootx),
-                   mFunctionY(overshooty));
-
-    current = inputs[0]->GetVector2() - offset;
-  }
-
-  AlphaFunctionPrototype mFunctionX;
-  AlphaFunctionPrototype mFunctionY;
-};
-
 } // namespace
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1056,7 +674,7 @@ void ScrollView::OnInitialize()
   self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, mCanScrollHorizontal);
 
   UpdatePropertyDomain();
-  SetInternalConstraints();
+  mConstraints.SetInternalConstraints(*this);
 
   // Connect wheel event
   self.WheelEventSignal().Connect(this, &ScrollView::OnWheelEvent);
@@ -1227,7 +845,7 @@ void ScrollView::SetRulerX(RulerPtr ruler)
   mRulerX = ruler;
 
   UpdatePropertyDomain();
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::SetRulerY(RulerPtr ruler)
@@ -1235,7 +853,7 @@ void ScrollView::SetRulerY(RulerPtr ruler)
   mRulerY = ruler;
 
   UpdatePropertyDomain();
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::UpdatePropertyDomain()
@@ -1377,7 +995,7 @@ void ScrollView::SetMaxOvershoot(float overshootX, float overshootY)
   mMaxOvershoot.y      = overshootY;
   mUserMaxOvershoot    = mMaxOvershoot;
   mDefaultMaxOvershoot = false;
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::SetSnapOvershootAlphaFunction(AlphaFunction alpha)
@@ -1440,7 +1058,7 @@ bool ScrollView::GetAxisAutoLock() const
 void ScrollView::SetAxisAutoLock(bool enable)
 {
   mAxisAutoLock = enable;
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 float ScrollView::GetAxisAutoLockGradient() const
@@ -1452,7 +1070,7 @@ void ScrollView::SetAxisAutoLockGradient(float gradient)
 {
   DALI_ASSERT_DEBUG(gradient >= 0.0f && gradient <= 1.0f);
   mAxisAutoLockGradient = gradient;
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 float ScrollView::GetFrictionCoefficient() const
@@ -1583,9 +1201,9 @@ void ScrollView::TransformTo(const Vector2& position, float duration, AlphaFunct
     mGestureStackDepth = 0;
     self.SetProperty(Toolkit::ScrollView::Property::PANNING, false);
 
-    if(mScrollMainInternalPrePositionConstraint)
+    if(mConstraints.mScrollMainInternalPrePositionConstraint)
     {
-      mScrollMainInternalPrePositionConstraint.Remove();
+      mConstraints.mScrollMainInternalPrePositionConstraint.Remove();
     }
   }
 
@@ -1770,7 +1388,7 @@ bool ScrollView::AnimateTo(const Vector2& position, const Vector2& positionDurat
   // Position Delta ///////////////////////////////////////////////////////
   if(positionChanged)
   {
-    UpdateMainInternalConstraint();
+    mConstraints.UpdateMainInternalConstraint(*this);
     if(mWrapMode && findShortcuts)
     {
       // In Wrap Mode, the shortest distance is a little less intuitive...
@@ -1843,7 +1461,7 @@ void ScrollView::EnableScrollOvershoot(bool enable)
     }
   }
 
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::AddOverlay(Actor actor)
@@ -2035,7 +1653,7 @@ void ScrollView::OnSizeSet(const Vector3& size)
     }
   }
   UpdatePropertyDomain();
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
   if(IsOvershootEnabled())
   {
     mOvershootIndicator->Reset();
@@ -2575,7 +2193,7 @@ void ScrollView::OnPan(const PanGesture& gesture)
       self.SetProperty(Toolkit::ScrollView::Property::PANNING, true);
       self.SetProperty(Toolkit::ScrollView::Property::START_PAGE_POSITION, Vector3(position.x, position.y, 0.0f));
 
-      UpdateMainInternalConstraint();
+      mConstraints.UpdateMainInternalConstraint(*this);
       Toolkit::ScrollBar scrollBar = mScrollBar.GetHandle();
       if(scrollBar && mTransientScrollBar)
       {
@@ -2618,9 +2236,9 @@ void ScrollView::OnPan(const PanGesture& gesture)
         mPanning      = false;
         self.SetProperty(Toolkit::ScrollView::Property::PANNING, false);
 
-        if(mScrollMainInternalPrePositionConstraint)
+        if(mConstraints.mScrollMainInternalPrePositionConstraint)
         {
-          mScrollMainInternalPrePositionConstraint.Remove();
+          mConstraints.mScrollMainInternalPrePositionConstraint.Remove();
         }
 
         Toolkit::ScrollBar scrollBar = mScrollBar.GetHandle();
@@ -2798,168 +2416,6 @@ void ScrollView::WrapPosition(Vector2& position) const
   }
 }
 
-void ScrollView::UpdateMainInternalConstraint()
-{
-  // TODO: Only update the constraints which have changed, rather than remove all and add all again.
-  // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
-  Actor              self = Self();
-  PanGestureDetector detector(GetPanGestureDetector());
-
-  if(mScrollMainInternalPositionConstraint)
-  {
-    mScrollMainInternalPositionConstraint.Remove();
-    mScrollMainInternalDeltaConstraint.Remove();
-    mScrollMainInternalFinalConstraint.Remove();
-    mScrollMainInternalRelativeConstraint.Remove();
-    mScrollMainInternalDomainConstraint.Remove();
-    mScrollMainInternalPrePositionMaxConstraint.Remove();
-  }
-  if(mScrollMainInternalPrePositionConstraint)
-  {
-    mScrollMainInternalPrePositionConstraint.Remove();
-  }
-
-  // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
-  // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
-
-  // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
-  Vector2 initialPanMask = Vector2(mRulerX->IsEnabled() ? 1.0f : 0.0f, mRulerY->IsEnabled() ? 1.0f : 0.0f);
-
-  if(mLockAxis == LockVertical)
-  {
-    initialPanMask.y = 0.0f;
-  }
-  else if(mLockAxis == LockHorizontal)
-  {
-    initialPanMask.x = 0.0f;
-  }
-
-  if(mPanning)
-  {
-    mScrollMainInternalPrePositionConstraint = Constraint::New<Vector2>(self,
-                                                                        Toolkit::ScrollView::Property::SCROLL_PRE_POSITION,
-                                                                        InternalPrePositionConstraint(mPanStartPosition,
-                                                                                                      initialPanMask,
-                                                                                                      mAxisAutoLock,
-                                                                                                      mAxisAutoLockGradient,
-                                                                                                      mLockAxis,
-                                                                                                      mMaxOvershoot,
-                                                                                                      mRulerX,
-                                                                                                      mRulerY));
-    mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::LOCAL_POSITION));
-    mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::PANNING));
-    mScrollMainInternalPrePositionConstraint.AddSource(Source(self, Actor::Property::SIZE));
-    mScrollMainInternalPrePositionConstraint.Apply();
-  }
-
-  // 2. Second calculate the clamped position (actual position)
-  mScrollMainInternalPositionConstraint = Constraint::New<Vector2>(self,
-                                                                   Toolkit::ScrollView::Property::SCROLL_POSITION,
-                                                                   InternalPositionConstraint(mRulerX->GetDomain(),
-                                                                                              mRulerY->GetDomain(),
-                                                                                              mWrapMode));
-  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
-  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
-  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  mScrollMainInternalPositionConstraint.AddSource(Source(self, Actor::Property::SIZE));
-  mScrollMainInternalPositionConstraint.Apply();
-
-  mScrollMainInternalDeltaConstraint = Constraint::New<Vector2>(self, Toolkit::ScrollView::Property::SCROLL_POSITION_DELTA, InternalPositionDeltaConstraint);
-  mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-  mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET));
-  mScrollMainInternalDeltaConstraint.Apply();
-
-  mScrollMainInternalFinalConstraint = Constraint::New<Vector2>(self, Toolkit::ScrollView::Property::SCROLL_FINAL, InternalFinalConstraint(FinalDefaultAlphaFunction, FinalDefaultAlphaFunction));
-  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_X));
-  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_Y));
-  mScrollMainInternalFinalConstraint.Apply();
-
-  mScrollMainInternalRelativeConstraint = Constraint::New<Vector2>(self, Toolkit::Scrollable::Property::SCROLL_RELATIVE_POSITION, InternalRelativePositionConstraint);
-  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
-  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Actor::Property::SIZE));
-  mScrollMainInternalRelativeConstraint.Apply();
-
-  mScrollMainInternalDomainConstraint = Constraint::New<Vector2>(self, Toolkit::ScrollView::Property::SCROLL_DOMAIN_SIZE, InternalScrollDomainConstraint);
-  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
-  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Actor::Property::SIZE));
-  mScrollMainInternalDomainConstraint.Apply();
-
-  mScrollMainInternalPrePositionMaxConstraint = Constraint::New<Vector2>(self, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_MAX, InternalPrePositionMaxConstraint);
-  mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Actor::Property::SIZE));
-  mScrollMainInternalPrePositionMaxConstraint.Apply();
-
-  // When panning we want to make sure overshoot values are affected by pre position and post position
-  SetOvershootConstraintsEnabled(!mWrapMode);
-}
-
-void ScrollView::SetOvershootConstraintsEnabled(bool enabled)
-{
-  Actor self(Self());
-  // remove and reset, it may now be in wrong order with the main internal constraints
-  if(mScrollMainInternalOvershootXConstraint)
-  {
-    mScrollMainInternalOvershootXConstraint.Remove();
-    mScrollMainInternalOvershootXConstraint.Reset();
-    mScrollMainInternalOvershootYConstraint.Remove();
-    mScrollMainInternalOvershootYConstraint.Reset();
-  }
-  if(enabled)
-  {
-    mScrollMainInternalOvershootXConstraint = Constraint::New<float>(self, Toolkit::ScrollView::Property::OVERSHOOT_X, OvershootXConstraint(mMaxOvershoot.x));
-    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
-    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL));
-    mScrollMainInternalOvershootXConstraint.Apply();
-
-    mScrollMainInternalOvershootYConstraint = Constraint::New<float>(self, Toolkit::ScrollView::Property::OVERSHOOT_Y, OvershootYConstraint(mMaxOvershoot.y));
-    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
-    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL));
-    mScrollMainInternalOvershootYConstraint.Apply();
-  }
-  else
-  {
-    self.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_X, 0.0f);
-    self.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_Y, 0.0f);
-  }
-}
-
-void ScrollView::SetInternalConstraints()
-{
-  // Internal constraints (applied to target ScrollBase Actor itself) /////////
-  UpdateMainInternalConstraint();
-
-  // User definable constraints to apply to all child actors //////////////////
-  Actor self = Self();
-
-  // Apply some default constraints to ScrollView & its bound actors
-  // Movement + Wrap function
-
-  Constraint constraint;
-
-  // MoveActor (scrolling)
-  constraint = Constraint::New<Vector3>(self, Actor::Property::POSITION, MoveActorConstraint);
-  constraint.AddSource(Source(self, Toolkit::ScrollView::Property::SCROLL_POSITION));
-  constraint.SetRemoveAction(Constraint::DISCARD);
-  ApplyConstraintToBoundActors(constraint);
-
-  // WrapActor (wrap functionality)
-  constraint = Constraint::New<Vector3>(self, Actor::Property::POSITION, WrapActorConstraint);
-  constraint.AddSource(LocalSource(Actor::Property::SCALE));
-  constraint.AddSource(LocalSource(Actor::Property::ANCHOR_POINT));
-  constraint.AddSource(LocalSource(Actor::Property::SIZE));
-  constraint.AddSource(Source(self, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
-  constraint.AddSource(Source(self, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  constraint.AddSource(Source(self, Toolkit::ScrollView::Property::WRAP));
-  constraint.SetRemoveAction(Constraint::DISCARD);
-  ApplyConstraintToBoundActors(constraint);
-}
-
 void ScrollView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
 {
   Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object));
@@ -3122,6 +2578,31 @@ void ScrollView::SetScrollMode(const Property::Map& scrollModeMap)
   SetRulerY(rulerY);
 }
 
+ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient)
+{
+  if(panDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
+     currentLockAxis == ScrollView::LockPossible)
+  {
+    float dx = fabsf(panDelta.x);
+    float dy = fabsf(panDelta.y);
+    if(dx * lockGradient >= dy)
+    {
+      // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
+      currentLockAxis = ScrollView::LockVertical;
+    }
+    else if(dy * lockGradient > dx)
+    {
+      // 0.36:1 gradient to the vertical (deviate < 20 degrees)
+      currentLockAxis = ScrollView::LockHorizontal;
+    }
+    else
+    {
+      currentLockAxis = ScrollView::LockNone;
+    }
+  }
+  return currentLockAxis;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index aee050e..c53e3b7 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h>
 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h>
 
 namespace Dali
 {
@@ -765,26 +766,6 @@ private:
    */
   void WrapPosition(Vector2& position) const;
 
-  /**
-   * Updates the main internal scroll constraints with new ruler and domain
-   * values
-   */
-  void UpdateMainInternalConstraint();
-
-  /**
-   * Enables/disables the overshoot constraints
-   *
-   * @param[in] enabled whether to enable or disable the overshoot constraints
-   */
-  void SetOvershootConstraintsEnabled(bool enabled);
-
-  /**
-   * Sets internal constraints for this ScrollView.
-   * Many of these internal constraints are based on properties within
-   * ScrollView.
-   */
-  void SetInternalConstraints();
-
 protected:
   struct AccessibleImpl : public Scrollable::AccessibleImpl
   {
@@ -865,6 +846,8 @@ private:
   ScrollView& operator=(const ScrollView& rhs);
 
 private:
+  ScrollViewConstraints mConstraints;
+
   unsigned long mTouchDownTime; ///< The touch down time
 
   int     mGestureStackDepth; ///< How many gestures are currently occuring.
@@ -922,17 +905,6 @@ private:
 
   Vector2 mWheelScrollDistanceStep; ///< The step of scroll distance in actor coordinates in X and Y axes for each wheel event received.
 
-  //ScrollInternalConstraintsPtr mScrollInternalConstraints;
-  Constraint mScrollMainInternalPrePositionConstraint;
-  Constraint mScrollMainInternalPositionConstraint;
-  Constraint mScrollMainInternalOvershootXConstraint;
-  Constraint mScrollMainInternalOvershootYConstraint;
-  Constraint mScrollMainInternalDeltaConstraint;
-  Constraint mScrollMainInternalFinalConstraint;
-  Constraint mScrollMainInternalRelativeConstraint;
-  Constraint mScrollMainInternalDomainConstraint;
-  Constraint mScrollMainInternalPrePositionMaxConstraint;
-
   ScrollOvershootIndicatorPtr    mOvershootIndicator;
   WeakHandle<Toolkit::ScrollBar> mScrollBar;
 
@@ -953,8 +925,21 @@ private:
   bool mCanScrollHorizontal : 1;        ///< Local value of our property to check against
   bool mCanScrollVertical : 1;          ///< Local value of our property to check against
   bool mTransientScrollBar : 1;         ///< True if scroll-bar should be automatically show/hidden during/after panning
+
+  friend ScrollViewConstraints;
 };
 
+/**
+ * Returns whether to lock scrolling to a particular axis
+ *
+ * @param[in] panDelta Distance panned since gesture started
+ * @param[in] currentLockAxis The current lock axis value
+ * @param[in] lockGradient How quickly to lock to a particular axis
+ *
+ * @return The new axis lock state
+ */
+ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient);
+
 } // namespace Internal
 
 // Helpers for public-api forwarding methods
index f1aa866..7fb8e01 100644 (file)
@@ -92,6 +92,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp
    ${toolkit_src_dir}/controls/scene3d-view/scene3d-view-impl.cpp
    ${toolkit_src_dir}/controls/scene3d-view/gltf-loader.cpp