Merge "Fix: The last line of the text overlaps with the text-editor's border/edge...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-impl-constraints.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
23 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
24
25 namespace Dali
26 {
27 namespace Toolkit
28 {
29 namespace Internal
30 {
31 namespace
32 {
33
34 float FinalDefaultAlphaFunction(float offset)
35 {
36   return offset * 0.5f;
37 }
38
39 /**
40  * Internal Relative position Constraint
41  * Generates the relative position value of the scroll view
42  * based on the absolute position, and it's relation to the
43  * scroll domain. This is a value from 0.0f to 1.0f in each
44  * scroll position axis.
45  */
46 void InternalRelativePositionConstraint(Vector2& relativePosition, const PropertyInputContainer& inputs)
47 {
48   Vector2        position = -inputs[0]->GetVector2();
49   const Vector2& min      = inputs[1]->GetVector2();
50   const Vector2& max      = inputs[2]->GetVector2();
51   const Vector3& size     = inputs[3]->GetVector3();
52
53   position.x = WrapInDomain(position.x, min.x, max.x);
54   position.y = WrapInDomain(position.y, min.y, max.y);
55
56   Vector2 domainSize = (max - min) - size.GetVectorXY();
57
58   relativePosition.x = domainSize.x > Math::MACHINE_EPSILON_1 ? fabsf((position.x - min.x) / domainSize.x) : 0.0f;
59   relativePosition.y = domainSize.y > Math::MACHINE_EPSILON_1 ? fabsf((position.y - min.y) / domainSize.y) : 0.0f;
60 }
61
62 /**
63  * Internal scroll domain Constraint
64  * Generates the scroll domain of the scroll view.
65  */
66 void InternalScrollDomainConstraint(Vector2& scrollDomain, const PropertyInputContainer& inputs)
67 {
68   const Vector2& min  = inputs[0]->GetVector2();
69   const Vector2& max  = inputs[1]->GetVector2();
70   const Vector3& size = inputs[2]->GetVector3();
71
72   scrollDomain = (max - min) - size.GetVectorXY();
73 }
74
75 /**
76  * Internal maximum scroll position Constraint
77  * Generates the maximum scroll position of the scroll view.
78  */
79 void InternalPrePositionMaxConstraint(Vector2& scrollMax, const PropertyInputContainer& inputs)
80 {
81   const Vector2& max  = inputs[0]->GetVector2();
82   const Vector3& size = inputs[1]->GetVector3();
83
84   scrollMax = max - size.GetVectorXY();
85 }
86
87 /**
88  * Internal Pre-Position Property Constraint.
89  *
90  * Generates position property based on current position + gesture displacement.
91  * Or generates position property based on positionX/Y.
92  * Note: This is the position prior to any clamping at scroll boundaries.
93  */
94 struct InternalPrePositionConstraint
95 {
96   InternalPrePositionConstraint(const Vector2&       initialPanPosition,
97                                 const Vector2&       initialPanMask,
98                                 bool                 axisAutoLock,
99                                 float                axisAutoLockGradient,
100                                 ScrollView::LockAxis initialLockAxis,
101                                 const Vector2&       maxOvershoot,
102                                 const RulerPtr&      rulerX,
103                                 const RulerPtr&      rulerY)
104   : mLocalStart(initialPanPosition),
105     mInitialPanMask(initialPanMask),
106     mMaxOvershoot(maxOvershoot),
107     mAxisAutoLockGradient(axisAutoLockGradient),
108     mLockAxis(initialLockAxis),
109     mAxisAutoLock(axisAutoLock),
110     mWasPanning(false)
111   {
112     const RulerDomain& rulerDomainX = rulerX->GetDomain();
113     const RulerDomain& rulerDomainY = rulerY->GetDomain();
114     mDomainMin                      = Vector2(rulerDomainX.min, -rulerDomainY.min);
115     mDomainMax                      = Vector2(-rulerDomainX.max, -rulerDomainY.max);
116     mClampX                         = rulerDomainX.enabled;
117     mClampY                         = rulerDomainY.enabled;
118     mFixedRulerX                    = rulerX->GetType() == Ruler::FIXED;
119     mFixedRulerY                    = rulerY->GetType() == Ruler::FIXED;
120   }
121
122   void operator()(Vector2& scrollPostPosition, const PropertyInputContainer& inputs)
123   {
124     const Vector2& panPosition = inputs[0]->GetVector2();
125     const bool&    inGesture   = inputs[1]->GetBoolean();
126
127     // First check if we are within a gesture.
128     // The ScrollView may have received a start gesture from ::OnPan()
129     // while the finish gesture is received now in this constraint.
130     // This gesture must then be rejected as the value will be "old".
131     // Typically the last value from the end of the last gesture.
132     // If we are rejecting the gesture, we simply don't modify the constraint target.
133     if(inGesture)
134     {
135       if(!mWasPanning)
136       {
137         mPrePosition    = scrollPostPosition;
138         mStartPosition  = mPrePosition;
139         mCurrentPanMask = mInitialPanMask;
140         mWasPanning     = true;
141       }
142
143       // Calculate Deltas...
144       const Vector2& currentPosition = panPosition;
145       Vector2        panDelta(currentPosition - mLocalStart);
146
147       // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
148       // appears mostly horizontal or mostly vertical respectively...
149       if(mAxisAutoLock)
150       {
151         mLockAxis = GetLockAxis(panDelta, mLockAxis, mAxisAutoLockGradient);
152         if(mLockAxis == ScrollView::LockVertical)
153         {
154           mCurrentPanMask.y = 0.0f;
155         }
156         else if(mLockAxis == ScrollView::LockHorizontal)
157         {
158           mCurrentPanMask.x = 0.0f;
159         }
160       }
161
162       // Restrict deltas based on ruler enable/disable and axis-lock state...
163       panDelta *= mCurrentPanMask;
164
165       // Perform Position transform based on input deltas...
166       scrollPostPosition = mPrePosition;
167       scrollPostPosition += panDelta;
168
169       // if no wrapping then clamp preposition to maximum overshoot amount
170       const Vector3& size = inputs[2]->GetVector3();
171       if(mClampX)
172       {
173         float newXPosition = Clamp(scrollPostPosition.x, (mDomainMax.x + size.x) - mMaxOvershoot.x, mDomainMin.x + mMaxOvershoot.x);
174         if((newXPosition < scrollPostPosition.x - Math::MACHINE_EPSILON_1) || (newXPosition > scrollPostPosition.x + Math::MACHINE_EPSILON_1))
175         {
176           mPrePosition.x = newXPosition;
177           mLocalStart.x  = panPosition.x;
178         }
179         scrollPostPosition.x = newXPosition;
180       }
181       if(mClampY)
182       {
183         float newYPosition = Clamp(scrollPostPosition.y, (mDomainMax.y + size.y) - mMaxOvershoot.y, mDomainMin.y + mMaxOvershoot.y);
184         if((newYPosition < scrollPostPosition.y - Math::MACHINE_EPSILON_1) || (newYPosition > scrollPostPosition.y + Math::MACHINE_EPSILON_1))
185         {
186           mPrePosition.y = newYPosition;
187           mLocalStart.y  = panPosition.y;
188         }
189         scrollPostPosition.y = newYPosition;
190       }
191
192       // If we are using a fixed ruler in a particular axis, limit the maximum pages scrolled on that axis.
193       if(mFixedRulerX || mFixedRulerY)
194       {
195         // Here we limit the maximum amount that can be moved from the starting position of the gesture to one page.
196         // We do this only if we have a fixed ruler (on that axis) and the mode is enabled.
197         // Note: 1.0f is subtracted to keep the value within one page size (otherwise we stray on to the page after).
198         // Note: A further 1.0f is subtracted to handle a compensation that happens later within the flick handling code in SnapWithVelocity().
199         //       When a flick is completed, an adjustment of 1.0f is sometimes made to allow for the scenario where:
200         //       A flick finishes before the update thread has advanced the scroll position past the previous snap point.
201         Vector2 viewPageSizeLimit(size.x - (1.0f + 1.0f), size.y - (1.0f - 1.0f));
202         Vector2 minPosition(mStartPosition.x - viewPageSizeLimit.x, mStartPosition.y - viewPageSizeLimit.y);
203         Vector2 maxPosition(mStartPosition.x + viewPageSizeLimit.x, mStartPosition.y + viewPageSizeLimit.y);
204
205         if(mFixedRulerX)
206         {
207           scrollPostPosition.x = Clamp(scrollPostPosition.x, minPosition.x, maxPosition.x);
208         }
209         if(mFixedRulerY)
210         {
211           scrollPostPosition.y = Clamp(scrollPostPosition.y, minPosition.y, maxPosition.y);
212         }
213       }
214     }
215   }
216
217   Vector2 mPrePosition;
218   Vector2 mLocalStart;
219   Vector2 mStartPosition;  ///< The start position of the gesture - used to limit scroll amount (not modified by clamping).
220   Vector2 mInitialPanMask; ///< Initial pan mask (based on ruler settings).
221   Vector2 mCurrentPanMask; ///< Current pan mask that can be altered by axis lock mode.
222   Vector2 mDomainMin;
223   Vector2 mDomainMax;
224   Vector2 mMaxOvershoot;
225
226   float                mAxisAutoLockGradient; ///< Set by ScrollView
227   ScrollView::LockAxis mLockAxis;
228
229   bool mAxisAutoLock : 1; ///< Set by ScrollView
230   bool mWasPanning : 1;
231   bool mClampX : 1;
232   bool mClampY : 1;
233   bool mFixedRulerX : 1;
234   bool mFixedRulerY : 1;
235 };
236
237 /**
238  * Internal Position Property Constraint.
239  *
240  * Generates position property based on pre-position
241  * Note: This is the position after clamping.
242  * (uses result of InternalPrePositionConstraint)
243  */
244 struct InternalPositionConstraint
245 {
246   InternalPositionConstraint(const RulerDomain& domainX, const RulerDomain& domainY, bool wrap)
247   : mDomainMin(-domainX.min, -domainY.min),
248     mDomainMax(-domainX.max, -domainY.max),
249     mClampX(domainX.enabled),
250     mClampY(domainY.enabled),
251     mWrap(wrap)
252   {
253   }
254
255   void operator()(Vector2& position, const PropertyInputContainer& inputs)
256   {
257     position            = inputs[0]->GetVector2();
258     const Vector2& size = inputs[3]->GetVector3().GetVectorXY();
259     const Vector2& min  = inputs[1]->GetVector2();
260     const Vector2& max  = inputs[2]->GetVector2();
261
262     if(mWrap)
263     {
264       position.x = -WrapInDomain(-position.x, min.x, max.x);
265       position.y = -WrapInDomain(-position.y, min.y, max.y);
266     }
267     else
268     {
269       // clamp post position to domain
270       position.x = mClampX ? Clamp(position.x, mDomainMax.x + size.x, mDomainMin.x) : position.x;
271       position.y = mClampY ? Clamp(position.y, mDomainMax.y + size.y, mDomainMin.y) : position.y;
272     }
273   }
274
275   Vector2 mDomainMin;
276   Vector2 mDomainMax;
277   bool    mClampX;
278   bool    mClampY;
279   bool    mWrap;
280 };
281
282 /**
283  * This constraint updates the X overshoot property using the difference
284  * SCROLL_PRE_POSITION.x and SCROLL_POSITION.x, returning a relative value between 0.0f and 1.0f
285  */
286 struct OvershootXConstraint
287 {
288   OvershootXConstraint(float maxOvershoot)
289   : mMaxOvershoot(maxOvershoot)
290   {
291   }
292
293   void operator()(float& current, const PropertyInputContainer& inputs)
294   {
295     if(inputs[2]->GetBoolean())
296     {
297       const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
298       const Vector2& scrollPostPosition = inputs[1]->GetVector2();
299       float          newOvershoot       = scrollPrePosition.x - scrollPostPosition.x;
300       current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
301     }
302     else
303     {
304       current = 0.0f;
305     }
306   }
307
308   float mMaxOvershoot;
309 };
310
311 /**
312  * This constraint updates the Y overshoot property using the difference
313  * SCROLL_PRE_POSITION.y and SCROLL_POSITION.y, returning a relative value between 0.0f and 1.0f
314  */
315 struct OvershootYConstraint
316 {
317   OvershootYConstraint(float maxOvershoot)
318   : mMaxOvershoot(maxOvershoot)
319   {
320   }
321
322   void operator()(float& current, const PropertyInputContainer& inputs)
323   {
324     if(inputs[2]->GetBoolean())
325     {
326       const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
327       const Vector2& scrollPostPosition = inputs[1]->GetVector2();
328       float          newOvershoot       = scrollPrePosition.y - scrollPostPosition.y;
329       current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
330     }
331     else
332     {
333       current = 0.0f;
334     }
335   }
336
337   float mMaxOvershoot;
338 };
339
340 /**
341  * Internal Position-Delta Property Constraint.
342  *
343  * Generates position-delta property based on scroll-position + scroll-offset properties.
344  */
345 void InternalPositionDeltaConstraint(Vector2& current, const PropertyInputContainer& inputs)
346 {
347   const Vector2& scrollPosition = inputs[0]->GetVector2();
348   const Vector2& scrollOffset   = inputs[1]->GetVector2();
349
350   current = scrollPosition + scrollOffset;
351 }
352
353 /**
354  * Internal Final Position Constraint
355  * The position of content is:
356  * of scroll-position + f(scroll-overshoot)
357  * where f(...) function defines how overshoot
358  * should affect final-position.
359  */
360 struct InternalFinalConstraint
361 {
362   InternalFinalConstraint(AlphaFunctionPrototype functionX,
363                           AlphaFunctionPrototype functionY)
364   : mFunctionX(functionX),
365     mFunctionY(functionY)
366   {
367   }
368
369   void operator()(Vector2& current, const PropertyInputContainer& inputs)
370   {
371     const float& overshootx = inputs[1]->GetFloat();
372     const float& overshooty = inputs[2]->GetFloat();
373     Vector2      offset(mFunctionX(overshootx),
374                    mFunctionY(overshooty));
375
376     current = inputs[0]->GetVector2() - offset;
377   }
378
379   AlphaFunctionPrototype mFunctionX;
380   AlphaFunctionPrototype mFunctionY;
381 };
382
383 } // namespace
384
385 void ScrollViewConstraints::UpdateMainInternalConstraint(ScrollView& scrollView)
386 {
387   // TODO: Only update the constraints which have changed, rather than remove all and add all again.
388   // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
389   Actor              scrollViewActor = scrollView.Self();
390   PanGestureDetector detector(scrollView.GetPanGestureDetector());
391
392   if(mScrollMainInternalPositionConstraint)
393   {
394     mScrollMainInternalPositionConstraint.Remove();
395     mScrollMainInternalDeltaConstraint.Remove();
396     mScrollMainInternalFinalConstraint.Remove();
397     mScrollMainInternalRelativeConstraint.Remove();
398     mScrollMainInternalDomainConstraint.Remove();
399     mScrollMainInternalPrePositionMaxConstraint.Remove();
400   }
401   if(mScrollMainInternalPrePositionConstraint)
402   {
403     mScrollMainInternalPrePositionConstraint.Remove();
404   }
405
406   // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
407   // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
408
409   // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
410   Vector2 initialPanMask = Vector2(scrollView.mRulerX->IsEnabled() ? 1.0f : 0.0f, scrollView.mRulerY->IsEnabled() ? 1.0f : 0.0f);
411
412   if(scrollView.mLockAxis == ScrollView::LockVertical)
413   {
414     initialPanMask.y = 0.0f;
415   }
416   else if(scrollView.mLockAxis == ScrollView::LockHorizontal)
417   {
418     initialPanMask.x = 0.0f;
419   }
420
421   if(scrollView.mPanning)
422   {
423     mScrollMainInternalPrePositionConstraint = Constraint::New<Vector2>(scrollViewActor,
424                                                                         Toolkit::ScrollView::Property::SCROLL_PRE_POSITION,
425                                                                         InternalPrePositionConstraint(scrollView.mPanStartPosition,
426                                                                                                       initialPanMask,
427                                                                                                       scrollView.mAxisAutoLock,
428                                                                                                       scrollView.mAxisAutoLockGradient,
429                                                                                                       scrollView.mLockAxis,
430                                                                                                       scrollView.mMaxOvershoot,
431                                                                                                       scrollView.mRulerX,
432                                                                                                       scrollView.mRulerY));
433     mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::LOCAL_POSITION));
434     mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::PANNING));
435     mScrollMainInternalPrePositionConstraint.AddSource(Source(scrollViewActor, Actor::Property::SIZE));
436     mScrollMainInternalPrePositionConstraint.Apply();
437   }
438
439   // 2. Second calculate the clamped position (actual position)
440   mScrollMainInternalPositionConstraint = Constraint::New<Vector2>(scrollViewActor,
441                                                                    Toolkit::ScrollView::Property::SCROLL_POSITION,
442                                                                    InternalPositionConstraint(scrollView.mRulerX->GetDomain(),
443                                                                                               scrollView.mRulerY->GetDomain(),
444                                                                                               scrollView.mWrapMode));
445   mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
446   mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
447   mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
448   mScrollMainInternalPositionConstraint.AddSource(Source(scrollViewActor, Actor::Property::SIZE));
449   mScrollMainInternalPositionConstraint.Apply();
450
451   mScrollMainInternalDeltaConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_POSITION_DELTA, InternalPositionDeltaConstraint);
452   mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
453   mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET));
454   mScrollMainInternalDeltaConstraint.Apply();
455
456   mScrollMainInternalFinalConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_FINAL, InternalFinalConstraint(FinalDefaultAlphaFunction, FinalDefaultAlphaFunction));
457   mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
458   mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_X));
459   mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_Y));
460   mScrollMainInternalFinalConstraint.Apply();
461
462   mScrollMainInternalRelativeConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_RELATIVE_POSITION, InternalRelativePositionConstraint);
463   mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
464   mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
465   mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
466   mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Actor::Property::SIZE));
467   mScrollMainInternalRelativeConstraint.Apply();
468
469   mScrollMainInternalDomainConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_DOMAIN_SIZE, InternalScrollDomainConstraint);
470   mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
471   mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
472   mScrollMainInternalDomainConstraint.AddSource(LocalSource(Actor::Property::SIZE));
473   mScrollMainInternalDomainConstraint.Apply();
474
475   mScrollMainInternalPrePositionMaxConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_MAX, InternalPrePositionMaxConstraint);
476   mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
477   mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Actor::Property::SIZE));
478   mScrollMainInternalPrePositionMaxConstraint.Apply();
479
480   // When panning we want to make sure overshoot values are affected by pre position and post position
481   SetOvershootConstraintsEnabled(scrollView, !scrollView.mWrapMode);
482 }
483
484 void ScrollViewConstraints::SetOvershootConstraintsEnabled(ScrollView& scrollView, bool enabled)
485 {
486   Actor scrollViewActor(scrollView.Self());
487   // remove and reset, it may now be in wrong order with the main internal constraints
488   if(mScrollMainInternalOvershootXConstraint)
489   {
490     mScrollMainInternalOvershootXConstraint.Remove();
491     mScrollMainInternalOvershootXConstraint.Reset();
492     mScrollMainInternalOvershootYConstraint.Remove();
493     mScrollMainInternalOvershootYConstraint.Reset();
494   }
495   if(enabled)
496   {
497     mScrollMainInternalOvershootXConstraint = Constraint::New<float>(scrollViewActor, Toolkit::ScrollView::Property::OVERSHOOT_X, OvershootXConstraint(scrollView.mMaxOvershoot.x));
498     mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
499     mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
500     mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL));
501     mScrollMainInternalOvershootXConstraint.Apply();
502
503     mScrollMainInternalOvershootYConstraint = Constraint::New<float>(scrollViewActor, Toolkit::ScrollView::Property::OVERSHOOT_Y, OvershootYConstraint(scrollView.mMaxOvershoot.y));
504     mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
505     mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
506     mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL));
507     mScrollMainInternalOvershootYConstraint.Apply();
508   }
509   else
510   {
511     scrollViewActor.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_X, 0.0f);
512     scrollViewActor.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_Y, 0.0f);
513   }
514 }
515
516 void ScrollViewConstraints::SetInternalConstraints(ScrollView& scrollView)
517 {
518   // Internal constraints (applied to target ScrollBase Actor itself) /////////
519   UpdateMainInternalConstraint(scrollView);
520
521   // User definable constraints to apply to all child actors //////////////////
522   Actor scrollViewActor = scrollView.Self();
523
524   // Apply some default constraints to ScrollView & its bound actors
525   // Movement + Wrap function
526
527   Constraint constraint;
528
529   // MoveActor (scrolling)
530   constraint = Constraint::New<Vector3>(scrollViewActor, Actor::Property::POSITION, MoveActorConstraint);
531   constraint.AddSource(Source(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_POSITION));
532   constraint.SetRemoveAction(Constraint::DISCARD);
533   scrollView.ApplyConstraintToBoundActors(constraint);
534
535   // WrapActor (wrap functionality)
536   constraint = Constraint::New<Vector3>(scrollViewActor, Actor::Property::POSITION, WrapActorConstraint);
537   constraint.AddSource(LocalSource(Actor::Property::SCALE));
538   constraint.AddSource(LocalSource(Actor::Property::ANCHOR_POINT));
539   constraint.AddSource(LocalSource(Actor::Property::SIZE));
540   constraint.AddSource(Source(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
541   constraint.AddSource(Source(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
542   constraint.AddSource(Source(scrollViewActor, Toolkit::ScrollView::Property::WRAP));
543   constraint.SetRemoveAction(Constraint::DISCARD);
544   scrollView.ApplyConstraintToBoundActors(constraint);
545 }
546
547
548 } // namespace Internal
549
550 } // namespace Toolkit
551
552 } // namespace Dali