a6d1cde675845ce81f8a48c6b98f482d0b2f5c1c
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-custom-effect-impl.cpp
1 /*
2  * Copyright (c) 2014 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-custom-effect-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <boost/bind.hpp>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-helper-functions.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace // unnamed namespace
37 {
38
39 using namespace ScrollViewHelperFunctions;
40
41 /**
42  * ScrollViewCustomEffectInfo
43  *
44  * ScrollAmountConstraint calculates the attached actor's current scroll position, -1.0f to 1.0f is from one side of the screen to the other.
45  * It also calculates if the other constraints can be skipped
46  *
47  * Color constraint: adjusts the alpha of the page based on their parent page's position relative
48  * to the middle of the screen.
49  * When at middle of screen Alpha is 100% opacity.
50  * When outside the viewable area, the opacity is 0%.
51  *
52  * Position constraint: adjusts the position of the page based on their parent page's position
53  * relative to the middle of the screen.
54  * When at middle of the screen the position is not altered.
55  * When one screen away from middle the position is rotated as per expected in a 3D inner cube.
56  */
57 class ScrollViewCustomEffectInfo : public Dali::RefObject
58 {
59 public:
60
61   ScrollViewCustomEffectInfo( uint flags,
62                               Property::Index scrollAmountProperty,
63                               Property::Index anchorProperty,
64                               const Vector2& pageSpacing,
65                               const Vector3& translateIn, const Vector3& translateOut,
66                               const Quaternion& globalRotateIn, const Quaternion& globalRotateOut,
67                               const Vector3& globalOriginIn, const Vector3& globalOriginOut,
68                               const float swingAngleIn, const Vector3& swingAxisIn, const float swingAngleOut, const Vector3& swingAxisOut,
69                               const Vector3& swingAnchorIn, const Vector3& swingAnchorOut,
70                               const float opacityThresholdIn, const float opacityThresholdOut,
71                               AlphaFunction globalRotateAlphaFunctionIn, AlphaFunction globalRotateAlphaFunctionOut,
72                               AlphaFunction swingAlphaFunctionIn, AlphaFunction swingAlphaFunctionOut,
73                               AlphaFunction swingAnchorAlphaFunctionIn, AlphaFunction swingAnchorAlphaFunctionOut,
74                               AlphaFunction translateAlphaFunctionIn, AlphaFunction translateAlphaFunctionOut,
75                               AlphaFunction opacityAlphaFunctionIn, AlphaFunction opacityAlphaFunctionOut ) :
76     mScrollAmountProperty(scrollAmountProperty),
77     mAnchorProperty(anchorProperty),
78     mFlags(flags),
79     mPageSpacing(pageSpacing),
80     mTranslateIn(translateIn), mTranslateOut(translateOut),
81     mGlobalRotateIn(globalRotateIn), mGlobalRotateOut(globalRotateOut),
82     mGlobalOriginIn(globalOriginIn), mGlobalOriginOut(globalOriginOut),
83     mSwingAngleIn(swingAngleIn), mSwingAxisIn(swingAxisIn), mSwingAngleOut(swingAngleOut), mSwingAxisOut(swingAxisOut),
84     mSwingAnchorIn(swingAnchorIn), mSwingAnchorOut(swingAnchorOut),
85     mOpacityThresholdIn(opacityThresholdIn), mOpacityThresholdOut(opacityThresholdOut),
86     mGlobalRotateAlphaFunctionIn(globalRotateAlphaFunctionIn), mGlobalRotateAlphaFunctionOut(globalRotateAlphaFunctionOut),
87     mSwingAlphaFunctionIn(swingAlphaFunctionIn), mSwingAlphaFunctionOut(swingAlphaFunctionOut),
88     mSwingAnchorAlphaFunctionIn(swingAnchorAlphaFunctionIn), mSwingAnchorAlphaFunctionOut(swingAnchorAlphaFunctionOut),
89     mTranslateAlphaFunctionIn(translateAlphaFunctionIn), mTranslateAlphaFunctionOut(translateAlphaFunctionOut),
90     mOpacityAlphaFunctionIn(opacityAlphaFunctionIn), mOpacityAlphaFunctionOut(opacityAlphaFunctionOut),
91     mPanning(false),
92     mScrolling(false),
93     mWasOutsideView(true),
94     mWrapped(false),
95     mWasWrapped(false),
96     mSkipConstraints(false),
97     mPassedCentreThisFrame(false),
98     mForceDirectionUpdate(true),
99     mDirectionFlags(0),
100     mLastDirectionFlags(0),
101     mCurrentOpacityAlphaFunction(NULL)
102   {
103   }
104
105   Vector3 ScrollAmountConstraint(const Vector3& current,
106                                  const PropertyInput& pagePositionProperty,
107                                  const PropertyInput& scrollPositionProperty,
108                                  const PropertyInput& scrollPositionMin,
109                                  const PropertyInput& scrollPositionMax,
110                                  const PropertyInput& pageSizeProperty,
111                                  const PropertyInput& scrollWrap)
112   {
113     // store last scroll pos
114     mLastScrollPosition = mScrollPos;
115     mPagePos = pagePositionProperty.GetVector3();
116     mScrollPos = scrollPositionProperty.GetVector3();
117     mScrollMin = scrollPositionMin.GetVector3();
118     mScrollMax = scrollPositionMax.GetVector3();
119     mPageSize = pageSizeProperty.GetVector3();
120     mWrap = scrollWrap.GetBoolean();
121     mWasWrapped = mWrapped;
122
123     mLastDirectionFlags = mDirectionFlags;
124
125     // Get position of page.
126     mPosition = mPagePos + mScrollPos;
127
128     // short circuit: if we're looking straight on at the page (jonny 5 is alive)
129     mIsStraightOnView = IsStraightOnView( mPosition );
130
131     mLastScrollAmount = mScrollAmount;
132     Vector3 newScrollAmount(mPosition / mPageSize);
133     mScrollAmount = newScrollAmount;
134     mWrapped = false;
135     if( !mIsStraightOnView && mWrap )
136     {
137       // only need to wrap if not already straight on view
138       WrapPositionWithinDomain( mPosition, mPageSize, mScrollMin, mScrollMax );
139       mIsStraightOnView = IsStraightOnView( mPosition );
140       newScrollAmount = mPosition / mPageSize;
141       if((mScrollAmount.x > 0.0f && newScrollAmount.x < 0.0f)
142          || (mScrollAmount.x < 0.0f && newScrollAmount.x > 0.0f)
143          || (mScrollAmount.y > 0.0f && newScrollAmount.y < 0.0f)
144          || (mScrollAmount.y < 0.0f && newScrollAmount.y > 0.0f))
145       {
146         mWrapped = true;
147       }
148     }
149     mScrollAmount = newScrollAmount;
150
151     return mScrollAmount;
152   }
153
154   Quaternion PageDirectionAndRotationConstraint(const Quaternion& current,
155                                   const PropertyInput& scrollPositionProperty,
156                                   const PropertyInput& panningProperty,
157                                   const PropertyInput& scrollingProperty)
158   {
159     bool panning = panningProperty.GetBoolean();
160     bool scrolling = scrollingProperty.GetBoolean();
161
162     bool isOutsideView = IsOutsideView( mPosition, mPageSize );
163
164     mSkipConstraints = isOutsideView | mIsStraightOnView;
165
166     bool bIsCurrentPage = mScrollAmount.x > -0.5f && mScrollAmount.x < 0.5f;
167
168     if(mSkipConstraints)
169     {
170       mPanning = panning;
171       mScrolling = scrolling;
172       mWasOutsideView = isOutsideView;
173       mWasStraightOnView = mIsStraightOnView;
174       return current;
175     }
176     Vector3 scrollDirection = mScrollAmount - mLastScrollAmount;
177     mPassedCentreThisFrame = bIsCurrentPage && (((mLastScrollAmount.x < 0.0f) && (mScrollAmount.x > 0.0f)) || ((mLastScrollAmount.x > 0.0f) && (mScrollAmount.x < 0.0f)) || ((mLastScrollAmount.y < 0.0f) && (mScrollAmount.y > 0.0f)) || ((mLastScrollAmount.y > 0.0f) && (mScrollAmount.y < 0.0f)) || (mWasStraightOnView && !mIsStraightOnView));
178
179     // may have wrapped this frame and never gone out of view
180     bool bWrappedOffScreen = (mWrapped != mWasWrapped && (fabs(scrollDirection.x) > 1.0f || fabs(scrollDirection.y) > 1.0f));
181
182     mCanChangeDirection = (scrolling && !mScrolling) || mPassedCentreThisFrame || (!isOutsideView && mWasOutsideView) || bWrappedOffScreen;
183
184     if(mCanChangeDirection)
185     {
186       // figure out if we have changed direction
187       if((mWrapped != mWasWrapped) && (fabs(scrollDirection.x) > 1.0f || fabs(scrollDirection.y) || (!isOutsideView && mWasOutsideView)))
188       {
189         if( fabs(scrollDirection.x) > 1.0f )
190         {
191           if(scrollDirection.x < 0.0f)
192           {
193             scrollDirection.x += (mScrollMax.x - mScrollMin.x) / mPageSize.x;
194           }
195           else
196           {
197             scrollDirection.x -= (mScrollMax.x - mScrollMin.x) / mPageSize.x;
198           }
199         }
200         if( fabs(scrollDirection.y) > 1.0f )
201         {
202           if(scrollDirection.y < 0.0f)
203           {
204             scrollDirection.y += (mScrollMax.y - mScrollMin.y) / mPageSize.y;
205           }
206           else
207           {
208             scrollDirection.y -= (mScrollMax.y - mScrollMin.y) / mPageSize.y;
209           }
210         }
211       }
212
213       // clear direction flags
214       mDirectionFlags &= ~Toolkit::ScrollView::DirectionFlagMask_Direction;
215       if(scrollDirection.x < 0.0f)
216       {
217         mDirectionFlags |= Toolkit::ScrollView::DirectionFlagLeft;
218       }
219       else if( scrollDirection.x > 0.0f )
220       {
221         mDirectionFlags |= Toolkit::ScrollView::DirectionFlagRight;
222       }
223
224       if(scrolling && !mScrolling)
225       {
226         // have started moving
227         if(((mDirectionFlags & Toolkit::ScrollView::DirectionFlagLeft)
228            && (mScrollAmount.x > 0.0f))
229            || ((mDirectionFlags & Toolkit::ScrollView::DirectionFlagRight)
230                && (mScrollAmount.x < 0.0f)))
231         {
232           // started moving towards the screen, allow transition change
233           mDirectionFlags = (mDirectionFlags & ~Toolkit::ScrollView::DirectionFlagMask_Transition) | Toolkit::ScrollView::DirectionFlagTransitionOn;
234         }
235         else if(((mDirectionFlags & Toolkit::ScrollView::DirectionFlagLeft)
236                 && (mScrollAmount.x < 0.0f))
237                 || ((mDirectionFlags & Toolkit::ScrollView::DirectionFlagRight)
238                     && (mScrollAmount.x > 0.0f)))
239         {
240           // started moving away from screen, allow transition change
241           mDirectionFlags  = (mDirectionFlags & ~Toolkit::ScrollView::DirectionFlagMask_Transition) | Toolkit::ScrollView::DirectionFlagTransitionOff;
242         }
243       }
244       else
245       {
246         // have changed direction
247         if((((mDirectionFlags & Toolkit::ScrollView::DirectionFlagLeft)
248            && mScrollAmount.x > 0.0f)
249             || ((mDirectionFlags & Toolkit::ScrollView::DirectionFlagRight)
250                 && mScrollAmount.x < 0.0f))
251            && (isOutsideView || (!isOutsideView && mWasOutsideView) || bWrappedOffScreen))
252         {
253           // went from moving away to moving towards and can change direction
254           mDirectionFlags = (mDirectionFlags & ~Toolkit::ScrollView::DirectionFlagMask_Transition) | Toolkit::ScrollView::DirectionFlagTransitionOn;
255         }
256         else if((((mDirectionFlags & Toolkit::ScrollView::DirectionFlagLeft)
257                 && (mScrollAmount.x < 0.0f))
258                  || ((mDirectionFlags & Toolkit::ScrollView::DirectionFlagRight)
259                      && (mScrollAmount.x > 0.0f)))
260                 && (isOutsideView || mPassedCentreThisFrame || bWrappedOffScreen))
261         {
262           // went from moving towards to moving away and can change direction
263           mDirectionFlags = (mDirectionFlags & (~Toolkit::ScrollView::DirectionFlagMask_Transition)) | Toolkit::ScrollView::DirectionFlagTransitionOff;
264         }
265       }
266       // now set up current values depending on direction
267       if(mFlags & Toolkit::ScrollViewCustomEffect::FlagTranslate)
268       {
269         // want to translate by specific amount
270         if((mFlags & Toolkit::ScrollViewCustomEffect::FlagTranslateIn)
271            && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOn))
272         {
273           mCurrentTranslation = mTranslateIn;
274         }
275         else if((mFlags & Toolkit::ScrollViewCustomEffect::FlagTranslateOut)
276            && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOff))
277         {
278           mCurrentTranslation = mTranslateOut;
279         }
280         else if(!(mFlags & (Toolkit::ScrollViewCustomEffect::FlagTranslateIn | Toolkit::ScrollViewCustomEffect::FlagTranslateOut)))
281         {
282           // using same value for both transitions
283           mCurrentTranslation = mTranslateIn;
284         }
285         else
286         {
287           // no value to use
288           mCurrentTranslation = Vector3::ZERO;
289         }
290       }
291
292       if(mFlags & Toolkit::ScrollViewCustomEffect::FlagRotate)
293       {
294         // want to rotate around an origin
295         if(mFlags & Toolkit::ScrollViewCustomEffect::FlagRotateAngleForcedOrigin)
296         {
297           // the angle forces the origin position depending on page size
298           // also the page spacing is implemented by setting the 'fake' origin far enough back to add a small gap between pages
299           // use rotation origin since it isnt needed otherwise
300           mCurrentGlobalOrigin = mGlobalOriginIn;
301         }
302         else
303         {
304           mCurrentGlobalRotation = mGlobalRotateIn;
305           if((mFlags & Toolkit::ScrollViewCustomEffect::FlagRotateOut)
306              && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOff))
307           {
308             mCurrentGlobalRotation = mGlobalRotateOut;
309           }
310         }
311       }
312
313       // now set up current values depending on direction
314       if(mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAngle)
315       {
316         // want to translate by specific amount
317         if((mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAngleIn)
318            && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOn))
319         {
320           // moving towards centre of screen and have a value for that
321           mCurrentSwingAngle = mSwingAngleIn;
322           mCurrentSwingAxis = mSwingAxisIn;
323         }
324         else if((mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAngleOut)
325            && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOff))
326         {
327           // moving away from centre of screen and have a value for that
328           mCurrentSwingAngle = mSwingAngleOut;
329           mCurrentSwingAxis = mSwingAxisOut;
330         }
331         else if(!(mFlags & (Toolkit::ScrollViewCustomEffect::FlagSwingAngleIn | Toolkit::ScrollViewCustomEffect::FlagSwingAngleOut)))
332         {
333           // using same value for both transitions
334           mCurrentSwingAngle = mSwingAngleIn;
335           mCurrentSwingAxis = mSwingAxisIn;
336         }
337         else
338         {
339           // no value to use
340           mCurrentSwingAngle = 0.0f;
341           mCurrentSwingAxis = Vector3(0.0f, -1.0f, 0.0f);
342         }
343
344         if(mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAnchor)
345         {
346           // want to translate by specific amount
347           if((mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAnchorIn)
348              && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOn))
349           {
350             mCurrentSwingAnchor = mSwingAnchorIn;
351           }
352           else if((mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAnchorOut)
353              && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOff))
354           {
355             mCurrentSwingAnchor = mSwingAnchorOut;
356           }
357           else if(!(mFlags & (Toolkit::ScrollViewCustomEffect::FlagSwingAnchorIn | Toolkit::ScrollViewCustomEffect::FlagSwingAnchorOut)))
358           {
359             // using same value for both transitions
360             mCurrentSwingAnchor = mSwingAnchorIn;
361           }
362           else
363           {
364             // no value to use
365             mCurrentSwingAnchor = Vector3(0,0,0);
366           }
367           if(mDirectionFlags & Toolkit::ScrollView::DirectionFlagLeft)
368           {
369             mCurrentSwingAnchor *= -1.0f;
370           }
371         }
372       }
373
374       // now set up current values depending on direction
375       if(mFlags & Toolkit::ScrollViewCustomEffect::FlagOpacityThreshold)
376       {
377         mCurrentOpacity = mOpacityThresholdIn;
378         if((mFlags & Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdOut)
379            && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOff))
380         {
381           mCurrentOpacity = mOpacityThresholdOut;
382         }
383         if(mFlags & Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionMask)
384         {
385           // need to adjust using alpha functions
386           if( (mFlags & Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionIn)
387              && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOn) )
388           {
389             mCurrentOpacityAlphaFunction = mOpacityAlphaFunctionIn;
390           }
391           else if( (mFlags & Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionOut)
392                   && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOff) )
393           {
394             mCurrentOpacityAlphaFunction = mOpacityAlphaFunctionOut;
395           }
396           else
397           {
398             mCurrentOpacityAlphaFunction = NULL;
399           }
400         }
401       }
402     }
403
404     // if user panning OR any form of scroll direction (animated included) set panning to true
405     mPanning = panning;
406     mScrolling = scrolling;
407     mWasOutsideView = isOutsideView;
408     mWasStraightOnView = mIsStraightOnView;
409
410     if(!(mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAngle))
411     {
412       return current;
413     }
414     Vector3 amount(mScrollAmount);
415     if(mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionMask)
416     {
417       // need to apply alpha function
418       if((mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionIn)
419          && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOn))
420       {
421         amount.x = mSwingAlphaFunctionIn(fabs(mScrollAmount.x));
422         amount.y = mSwingAlphaFunctionIn(fabs(mScrollAmount.y));
423         if(mScrollAmount.x < 0)
424         {
425           amount.x *= -1.0f;
426         }
427         if(mScrollAmount.y < 0)
428         {
429           amount.y *= -1.0f;
430         }
431       }
432       else if((mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionOut)
433              && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOff))
434       {
435         amount.x = mSwingAlphaFunctionOut(fabs(mScrollAmount.x));
436         amount.y = mSwingAlphaFunctionOut(fabs(mScrollAmount.y));
437         if(mScrollAmount.x < 0)
438         {
439           amount.x *= -1.0f;
440         }
441         if(mScrollAmount.y < 0)
442         {
443           amount.y *= -1.0f;
444         }
445       }
446     }
447
448     // TODO - swing angle seems very slightly off... SORT IT!!
449     //Quaternion rotation = Quaternion::Slerp(current, mCurrentSwingAngle, mScrollAmount.x);
450     return Quaternion(mCurrentSwingAngle * amount.x, mCurrentSwingAxis) * current; // Quaternion::Lerp(current, mCurrentSwingAngle, mScrollAmount.x);
451   }
452
453   /**
454    * @param[in] current The current color of this Actor
455    * @param[in] scrollAmountProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
456    * @return The new color of this Actor.
457    */
458   Vector4 ColorConstraint(const Vector4& current,
459                           const PropertyInput& scrollAmountProperty)
460   {
461     if(mSkipConstraints)
462     {
463       if(!mIsStraightOnView)
464       {
465         // will be off screen, set alpha to 0 to stop drawing it
466         return Vector4(current.r, current.g, current.b, 0.0f);
467       }
468       return current;
469     }
470
471     if( !(mFlags & Toolkit::ScrollViewCustomEffect::FlagOpacityThreshold) )
472     {
473       return current;
474     }
475
476     float amount = fabsf(mScrollAmount.x);
477     if((mFlags & Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionMask)
478        && mCurrentOpacityAlphaFunction)
479     {
480       amount = mCurrentOpacityAlphaFunction(amount);
481     }
482     Vector4 newColour(current.r, current.g, current.b, fmaxf(((1.0f - amount) / (1.0f - mCurrentOpacity)), 0.0f));
483     return newColour;
484   }
485
486   /**
487    * @brief PositionConstraint2
488    * @param current
489    * @param scrollPositionProperty
490    * @param startPagePosition
491    * @param startDirection
492    * @return
493    */
494   Vector3 PositionConstraint(const Vector3& current,
495                              const PropertyInput& scrollAmountProperty,
496                              const PropertyInput& anchorProperty,
497                              const PropertyInput& rotationProperty)
498   {
499     if(mSkipConstraints)
500     {
501       return mPosition;
502     }
503
504     Vector3 newPosition;
505
506     if(mFlags & Toolkit::ScrollViewCustomEffect::FlagRotateAngleForcedOrigin)
507     {
508       Quaternion qx(mScrollAmount.x * mCurrentGlobalOrigin.x, Vector3(0, 1, 0));
509       Quaternion qy(mScrollAmount.y * mCurrentGlobalOrigin.y, Vector3(1, 0, 0));
510
511       float thetaBx = (Math::PI - mCurrentGlobalOrigin.x) * 0.5f;
512       float radiusx = ((mPageSize.width + mPageSpacing.width) * 0.5f) * tanf(thetaBx);
513       Vector3 originPositionVec = Vector3(0, 0, radiusx);
514       Vector3 horizontalPos = qx.Rotate(originPositionVec);
515       newPosition.x = horizontalPos.x;
516       newPosition.z = radiusx - horizontalPos.z;
517       // need to create an origin based on current horizontal/vertical scrolling page size
518       //Vector2 thetaA(mScrollAmount.x * mCurrentGlobalOrigin.x, mScrollAmount.y * mCurrentGlobalOrigin.y);
519       float thetaBy = (Math::PI - mCurrentGlobalOrigin.y) * 0.5f;
520       float radiusy = ((mPageSize.height + mPageSpacing.height) * 0.5f) * tanf(thetaBy);
521       originPositionVec = Vector3(0, 0, radiusy);
522       horizontalPos = qy.Rotate(originPositionVec);
523       newPosition.y = horizontalPos.y;
524       if(mDirectionFlags & (Toolkit::ScrollView::DirectionFlagUp | Toolkit::ScrollView::DirectionFlagDown))
525       {
526         newPosition.z = radiusy - horizontalPos.z;
527       }
528
529       //Vector3 vRadius(sinf(thetaA.x) * radius, sinf(thetaA.y) * radius, z);
530       //newPosition = Vector3(vRadius.x, vRadius.y, -vRadius.z + radius);
531     }
532     else if(mFlags & Toolkit::ScrollViewCustomEffect::FlagRotate)
533     {
534       // rotate around our origin which is relative to the scene
535       Vector3 vec = newPosition - mCurrentGlobalOrigin;
536       newPosition -= vec;
537       vec = mCurrentGlobalRotation.Rotate(vec);
538       newPosition += vec;
539     }
540
541     if(mFlags & Toolkit::ScrollViewCustomEffect::FlagTranslate)
542     {
543       //Vector3 spacing(mPageSpacing.x, 0, 0);
544       Vector3 amount(mScrollAmount);
545       amount.z = fabs(mScrollAmount.x);
546       if(mFlags & Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionMask)
547       {
548         // need to apply alpha function
549         if((mFlags & Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionIn)
550            && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOn))
551         {
552           amount.x = mTranslateAlphaFunctionIn(fabs(mScrollAmount.x));
553           amount.y = mTranslateAlphaFunctionIn(fabs(mScrollAmount.y));
554           amount.z = mTranslateAlphaFunctionIn(fabs(mScrollAmount.x));
555           if(mScrollAmount.x < 0)
556           {
557             amount.x *= -1.0f;
558           }
559           if(mScrollAmount.y < 0)
560           {
561             amount.y *= -1.0f;
562           }
563         }
564         else if((mFlags & Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionOut)
565                && (mDirectionFlags & Toolkit::ScrollView::DirectionFlagTransitionOff))
566         {
567           amount.x = mTranslateAlphaFunctionOut(fabs(mScrollAmount.x));
568           amount.y = mTranslateAlphaFunctionOut(fabs(mScrollAmount.y));
569           amount.z = mTranslateAlphaFunctionIn(fabs(mScrollAmount.x));
570           if(mScrollAmount.x < 0)
571           {
572             amount.x *= -1.0f;
573           }
574           if(mScrollAmount.y < 0)
575           {
576             amount.y *= -1.0f;
577           }
578         }
579       }
580       newPosition += mCurrentTranslation * amount; // (mCurrentTranslation + ((!(mFlags & Toolkit::ScrollViewCustomEffect::FlagRotateAngleForcedOrigin)) ? (spacing * 0.5f) : Vector3(0,0,0))) * mScrollAmount;
581     }
582
583     if(mFlags & Toolkit::ScrollViewCustomEffect::FlagSwingAnchor)
584     {
585       // rotate around our anchor point which is local to our actor
586       Quaternion rotation(mCurrentSwingAngle * mScrollAmount.x, mCurrentSwingAxis);
587       Vector3 offset = mCurrentSwingAnchor * mPageSize;
588       newPosition += offset;
589       offset = rotation.Rotate(-offset);
590       newPosition += offset;
591     }
592
593     return newPosition;
594   }
595
596   // input parameters
597
598   Property::Index mScrollAmountProperty;
599   Property::Index mAnchorProperty;
600   uint          mFlags;                         ///< flags describing functionality, set automatically depending on functions called during effect setup
601   Vector2       mPageSpacing;                   ///< space between pages... kinda obvious really
602   Vector3       mTranslateIn;                   ///< translation offset to use when scrolling a page onto the screen
603   Vector3       mTranslateOut;                  ///< translation offset to use when scrolling a page off the screen
604   Quaternion    mGlobalRotateIn;                ///< rotates the page's position around a point
605   Quaternion    mGlobalRotateOut;               ///< rotates the page's position around a point
606   Vector3       mGlobalOriginIn;                ///< the point to rotate a page around when scrolling onto screen
607   Vector3       mGlobalOriginOut;               ///< the point to rotate a page around when scrolling off screen
608   float         mSwingAngleIn;                  ///< angle to rotate a page around its anchor when scrolling onto screen
609   Vector3       mSwingAxisIn;                   ///< angle to rotate a page around its anchor when scrolling off screen
610   float         mSwingAngleOut;                 ///< angle to rotate a page around its anchor when scrolling onto screen
611   Vector3       mSwingAxisOut;                  ///< angle to rotate a page around its anchor when scrolling off screen
612   Vector3       mSwingAnchorIn;                 ///< the page anchor point to use when scrolling onto screen
613   Vector3       mSwingAnchorOut;                ///< the page anchor point to use when scrolling off screen
614   float         mOpacityThresholdIn;            ///< the point at which opacity will change as page scrolls onto screen
615   float         mOpacityThresholdOut;           ///< the point at which opacity will change as page scrolls off screen
616   AlphaFunction mGlobalRotateAlphaFunctionIn;
617   AlphaFunction mGlobalRotateAlphaFunctionOut;
618   AlphaFunction mSwingAlphaFunctionIn;
619   AlphaFunction mSwingAlphaFunctionOut;
620   AlphaFunction mSwingAnchorAlphaFunctionIn;
621   AlphaFunction mSwingAnchorAlphaFunctionOut;
622   AlphaFunction mTranslateAlphaFunctionIn;
623   AlphaFunction mTranslateAlphaFunctionOut;
624   AlphaFunction mOpacityAlphaFunctionIn;
625   AlphaFunction mOpacityAlphaFunctionOut;
626
627   // constraint update params
628   // taken from property inputs every constraint update
629   Vector3       mPagePos;
630   Vector3       mScrollPos;
631   Vector3       mScrollMin;
632   Vector3       mScrollMax;
633   Vector3       mPageSize;
634   bool          mWrap:1;
635   bool          mPanning:1;
636   bool          mScrolling:1;
637   bool          mWasOutsideView:1;
638   bool          mIsStraightOnView:1;
639   bool          mWasStraightOnView:1;
640   bool          mWrapped:1;               ///< whether the scroll page was wrapped this frame
641   bool          mWasWrapped:1;            ///< whether the scroll page was wrapped last frame
642   bool          mCanChangeDirection:1;
643   bool          mSkipConstraints:1;       ///< whether we can skip the main constraints
644   bool          mPassedCentreThisFrame:1; ///< true if control has moved passed centre of screen
645   bool          mForceDirectionUpdate:1;
646   bool          mDirectionChanged:1;
647
648   // calculated each constraint update depending on flags set
649   int           mDirectionFlags;
650   int           mLastDirectionFlags;
651   Vector2       mLastScrollPosition;
652
653   Vector3       mPosition;
654   Vector3       mScrollAmount;
655   Vector3       mLastScrollAmount;
656   Vector3       mCurrentTranslation;
657   Quaternion    mCurrentGlobalRotation;
658   Vector3       mCurrentGlobalOrigin;
659   float         mCurrentSwingAngle;
660   Vector3       mCurrentSwingAxis;
661   Vector3       mCurrentSwingAnchor;
662   float         mCurrentOpacity;
663   AlphaFunction mCurrentOpacityAlphaFunction;
664 };
665
666 typedef IntrusivePtr<ScrollViewCustomEffectInfo> ScrollViewCustomEffectInfoPtr;
667
668 } // unnamed namespace
669
670 const std::string ScrollViewCustomEffect::SCROLL_AMOUNT_PROPERTY_STRING( "scroll-amount" );
671 const std::string ScrollViewCustomEffect::ANCHOR_POINT_PROPERTY_STRING( "custom-anchor-point" );
672
673 ScrollViewCustomEffect::ScrollViewCustomEffect() :
674   mFlags(0),
675   mPageSpacing(0,0),
676   mTranslateIn(0,0,0),
677   mTranslateOut(0,0,0),
678   mGlobalRotateIn(0.0f, Vector3(0, 1.0f, 0.0f)),
679   mGlobalRotateOut(0.0f, Vector3(0, 1.0f, 0.0f)),
680   mGlobalOriginIn(0,0,0),
681   mGlobalOriginOut(0,0,0),
682   mSwingAngleIn(0.0f),
683   mSwingAxisIn(0.0f, 1.0f, 0.0f),
684   mSwingAngleOut(0.0f),
685   mSwingAxisOut(0.0f, 1.0f, 0.0f),
686   mSwingAnchorIn(0,0,0),
687   mSwingAnchorOut(0,0,0),
688   mOpacityThresholdIn(0),
689   mOpacityThresholdOut(0),
690   mGlobalRotateAlphaFunctionIn(NULL),
691   mGlobalRotateAlphaFunctionOut(NULL),
692   mSwingAlphaFunctionIn(NULL),
693   mSwingAlphaFunctionOut(NULL),
694   mSwingAnchorAlphaFunctionIn(NULL),
695   mSwingAnchorAlphaFunctionOut(NULL),
696   mTranslateAlphaFunctionIn(NULL),
697   mTranslateAlphaFunctionOut(NULL),
698   mOpacityAlphaFunctionIn(NULL),
699   mOpacityAlphaFunctionOut(NULL)
700 {
701
702 }
703
704 ScrollViewCustomEffect::~ScrollViewCustomEffect()
705 {
706 }
707
708 void ScrollViewCustomEffect::SetPageSpacing(const Vector2& spacing)
709 {
710   mPageSpacing = spacing;
711 }
712
713 void ScrollViewCustomEffect::SetPageTranslation(const Vector3& translation)
714 {
715   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagTranslateMask) | Toolkit::ScrollViewCustomEffect::FlagTranslate;
716   mTranslateIn = mTranslateOut = translation;
717 }
718
719 void ScrollViewCustomEffect::SetPageTranslation(const Vector3& translationIn, const Vector3& translationOut)
720 {
721   // set flags describing translation with separate in out translation
722   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagTranslateMask)
723             | Toolkit::ScrollViewCustomEffect::FlagTranslate
724             | Toolkit::ScrollViewCustomEffect::FlagTranslateIn
725             | Toolkit::ScrollViewCustomEffect::FlagTranslateOut;
726
727   mTranslateIn = translationIn;
728   mTranslateOut = translationOut;
729 }
730
731 void ScrollViewCustomEffect::SetPageTranslationIn(const Vector3& translation)
732 {
733   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagTranslateMask | Toolkit::ScrollViewCustomEffect::FlagTranslateOut))
734             | Toolkit::ScrollViewCustomEffect::FlagTranslate
735             | Toolkit::ScrollViewCustomEffect::FlagTranslateIn;
736
737   mTranslateIn = translation;
738 }
739
740 void ScrollViewCustomEffect::SetPageTranslationOut(const Vector3& translation)
741 {
742   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagTranslateMask | Toolkit::ScrollViewCustomEffect::FlagTranslateIn))
743             | Toolkit::ScrollViewCustomEffect::FlagTranslate
744             | Toolkit::ScrollViewCustomEffect::FlagTranslateOut;
745
746   mTranslateOut = translation;
747 }
748
749 void ScrollViewCustomEffect::SetPageTranslateAlphaFunction(AlphaFunction func)
750 {
751   if(func)
752   {
753     mFlags |= Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionMask;
754   }
755   else
756   {
757     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionMask;
758   }
759   mTranslateAlphaFunctionIn = mTranslateAlphaFunctionOut = func;
760 }
761
762 void ScrollViewCustomEffect::SetPageTranslateAlphaFunction(AlphaFunction funcIn, AlphaFunction funcOut)
763 {
764   if(funcIn)
765   {
766     mFlags |= Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionIn;
767   }
768   else
769   {
770     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionIn;
771   }
772   if(funcOut)
773   {
774     mFlags |= Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionOut;
775   }
776   else
777   {
778     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionOut;
779   }
780   mTranslateAlphaFunctionIn = funcIn;
781   mTranslateAlphaFunctionOut = funcOut;
782 }
783
784 void ScrollViewCustomEffect::SetPageTranslateAlphaFunctionIn(AlphaFunction func)
785 {
786   if(func)
787   {
788     mFlags |= Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionIn;
789   }
790   else
791   {
792     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionIn;
793   }
794   mTranslateAlphaFunctionIn = func;
795 }
796
797 void ScrollViewCustomEffect::SetPageTranslateAlphaFunctionOut(AlphaFunction func)
798 {
799   if(func)
800   {
801     mFlags |= Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionOut;
802   }
803   else
804   {
805     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagTranslationAlphaFunctionOut;
806   }
807   mTranslateAlphaFunctionOut = func;
808 }
809
810 void ScrollViewCustomEffect::SetGlobalPageRotation(float angle, const Vector3& axis)
811 {
812   // set flags describing translation with separate in out translation
813   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagRotateMask) // reset rotate flags
814             | Toolkit::ScrollViewCustomEffect::FlagRotate;             // set new rotate flag
815
816   mGlobalRotateIn = mGlobalRotateOut = Quaternion(angle, axis);
817 }
818
819 void ScrollViewCustomEffect::SetAngledOriginPageRotation(const Vector3& angle)
820 {
821   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagRotateMask)
822             | Toolkit::ScrollViewCustomEffect::FlagRotate
823             | Toolkit::ScrollViewCustomEffect::FlagRotateAngleForcedOrigin;
824
825   // set this angle into global originin for now, the flag will let us know what value to use in constraints
826   mGlobalOriginIn = angle;
827 }
828
829 void ScrollViewCustomEffect::SetGlobalPageRotation(float angleIn, const Vector3& axisIn, float angleOut, const Vector3& axisOut)
830 {
831   // set flags describing translation with separate in out translation
832   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagRotateMask)
833             | Toolkit::ScrollViewCustomEffect::FlagRotate
834             | Toolkit::ScrollViewCustomEffect::FlagRotateIn
835             | Toolkit::ScrollViewCustomEffect::FlagRotateOut;
836
837   mGlobalRotateIn = Quaternion(angleIn, axisIn);
838   mGlobalRotateOut = Quaternion(angleOut, axisOut);
839 }
840
841 void ScrollViewCustomEffect::SetGlobalPageRotationIn(float angle, const Vector3& axis)
842 {
843   // set flags describing translation with separate in out translation
844   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagRotateMask | Toolkit::ScrollViewCustomEffect::FlagRotateOut)) // reset all rotation flags except RotateOut, since they may be calling these functions separately
845             | Toolkit::ScrollViewCustomEffect::FlagRotate
846             | Toolkit::ScrollViewCustomEffect::FlagRotateIn;
847
848   mGlobalRotateIn = Quaternion(angle, axis);
849 }
850
851 void ScrollViewCustomEffect::SetGlobalPageRotationOut(float angle, const Vector3& axis)
852 {
853   // set flags describing translation with separate in out translation
854   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagRotateMask | Toolkit::ScrollViewCustomEffect::FlagRotateIn)) // reset all rotation flags except RotateOut, since they may be calling these functions separately
855             | Toolkit::ScrollViewCustomEffect::FlagRotate
856             | Toolkit::ScrollViewCustomEffect::FlagRotateOut;
857
858   mGlobalRotateOut = Quaternion(angle, axis);
859 }
860
861 void ScrollViewCustomEffect::SetGlobalPageRotationOrigin(const Vector3& origin)
862 {
863   // set flags describing translation with separate in out translation
864   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagRotateOriginMask) // reset all rotation flags
865             | Toolkit::ScrollViewCustomEffect::FlagRotateOrigin;
866
867   mGlobalOriginIn = mGlobalOriginOut = origin;
868 }
869
870 void ScrollViewCustomEffect::SetGlobalPageRotationOrigin(const Vector3& originIn, const Vector3& originOut)
871 {
872   // set flags describing translation with separate in out translation
873   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagRotateOriginMask) // reset all rotation flags
874             | Toolkit::ScrollViewCustomEffect::FlagRotateOrigin
875             | Toolkit::ScrollViewCustomEffect::FlagRotateOriginIn
876             | Toolkit::ScrollViewCustomEffect::FlagRotateOriginOut;
877
878   mGlobalOriginIn = originIn;
879   mGlobalOriginOut = originOut;
880 }
881
882 void ScrollViewCustomEffect::SetGlobalPageRotationOriginIn(const Vector3& origin)
883 {
884   // set flags describing translation with separate in out translation
885   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagRotateOriginMask | Toolkit::ScrollViewCustomEffect::FlagRotateOriginOut)) // reset all rotation flags except RotateOut, since they may be calling these functions separately
886             | Toolkit::ScrollViewCustomEffect::FlagRotateOrigin
887             | Toolkit::ScrollViewCustomEffect::FlagRotateOriginIn;
888
889   mGlobalOriginIn = origin;
890 }
891
892 void ScrollViewCustomEffect::SetGlobalPageRotationOriginOut(const Vector3& origin)
893 {
894   // set flags describing translation with separate in out translation
895   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagRotateOriginMask | Toolkit::ScrollViewCustomEffect::FlagRotateOriginIn)) // reset all rotation flags except RotateOut, since they may be calling these functions separately
896             | Toolkit::ScrollViewCustomEffect::FlagRotateOrigin
897             | Toolkit::ScrollViewCustomEffect::FlagRotateOriginOut;
898
899   mGlobalOriginOut = origin;
900 }
901
902 void ScrollViewCustomEffect::SetSwingAngle(const float angle, const Vector3& axis)
903 {
904   // set flags describing translation with separate in out translation
905   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagSwingAngleMask) // reset rotate flags
906             | Toolkit::ScrollViewCustomEffect::FlagSwingAngle;             // set new rotate flag
907
908   mSwingAngleIn = mSwingAngleOut = angle;
909   mSwingAxisIn = mSwingAxisOut = axis;
910 }
911
912 void ScrollViewCustomEffect::SetSwingAngle(float angleIn, const Vector3& axisIn, float angleOut, const Vector3& axisOut)
913 {
914   // set flags describing translation with separate in out translation
915   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagSwingAngleMask)
916             | Toolkit::ScrollViewCustomEffect::FlagSwingAngle
917             | Toolkit::ScrollViewCustomEffect::FlagSwingAngleIn
918             | Toolkit::ScrollViewCustomEffect::FlagSwingAngleOut;
919
920   mSwingAngleIn = angleIn;
921   mSwingAngleOut = angleOut;
922   mSwingAxisIn = axisIn;
923   mSwingAxisOut = axisOut;
924 }
925
926 void ScrollViewCustomEffect::SetSwingAngleIn(float angle, const Vector3& axis)
927 {
928   // set flags describing translation with separate in out translation
929   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagSwingAngleMask | Toolkit::ScrollViewCustomEffect::FlagSwingAngleOut)) // reset all rotation flags except RotateOut, since they may be calling these functions separately
930             | Toolkit::ScrollViewCustomEffect::FlagSwingAngle
931             | Toolkit::ScrollViewCustomEffect::FlagSwingAngleIn;
932
933   mSwingAngleIn = angle;
934   mSwingAxisIn = axis;
935 }
936
937 void ScrollViewCustomEffect::SetSwingAngleOut(float angle, const Vector3& axis)
938 {
939   // set flags describing translation with separate in out translation
940   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagSwingAngleMask | Toolkit::ScrollViewCustomEffect::FlagSwingAngleIn)) // reset all rotation flags except RotateOut, since they may be calling these functions separately
941             | Toolkit::ScrollViewCustomEffect::FlagSwingAngle
942             | Toolkit::ScrollViewCustomEffect::FlagSwingAngleOut;
943
944   mSwingAngleOut = angle;
945   mSwingAxisOut = axis;
946 }
947
948 void ScrollViewCustomEffect::SetSwingAngleAlphaFunction(AlphaFunction func)
949 {
950   if(func)
951   {
952     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionMask;
953   }
954   else
955   {
956     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionMask;
957   }
958   mSwingAlphaFunctionIn = mSwingAlphaFunctionOut = func;
959 }
960
961 void ScrollViewCustomEffect::SetSwingAngleAlphaFunction(AlphaFunction funcIn, AlphaFunction funcOut)
962 {
963   if(funcIn)
964   {
965     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionIn;
966   }
967   else
968   {
969     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionIn;
970   }
971   if(funcOut)
972   {
973     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionOut;
974   }
975   else
976   {
977     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionOut;
978   }
979   mSwingAlphaFunctionIn = funcIn;
980   mSwingAlphaFunctionOut = funcOut;
981 }
982
983 void ScrollViewCustomEffect::SetSwingAngleAlphaFunctionIn(AlphaFunction func)
984 {
985   if(func)
986   {
987     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionIn;
988   }
989   else
990   {
991     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionIn;
992   }
993   mSwingAlphaFunctionIn = func;
994 }
995
996 void ScrollViewCustomEffect::SetSwingAngleAlphaFunctionOut(AlphaFunction func)
997 {
998   if(func)
999   {
1000     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionOut;
1001   }
1002   else
1003   {
1004     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAngleAlphaFunctionOut;
1005   }
1006   mSwingAlphaFunctionOut = func;
1007 }
1008
1009 void ScrollViewCustomEffect::SetSwingAnchor(const Vector3& anchor)
1010 {
1011   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorMask)
1012             | Toolkit::ScrollViewCustomEffect::FlagSwingAnchor;
1013   mSwingAnchorIn = mSwingAnchorOut = anchor;
1014 }
1015
1016 void ScrollViewCustomEffect::SetSwingAnchor(const Vector3& anchorIn, const Vector3& anchorOut)
1017 {
1018   // set flags describing translation with separate in out translation
1019   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorMask)
1020             | Toolkit::ScrollViewCustomEffect::FlagSwingAnchor
1021             | Toolkit::ScrollViewCustomEffect::FlagSwingAnchorIn
1022             | Toolkit::ScrollViewCustomEffect::FlagSwingAnchorOut;
1023
1024   mSwingAnchorIn = anchorIn;
1025   mSwingAnchorOut = anchorOut;
1026 }
1027
1028 void ScrollViewCustomEffect::SetSwingAnchorIn(const Vector3& anchor)
1029 {
1030   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorMask | Toolkit::ScrollViewCustomEffect::FlagSwingAnchorOut))
1031             | Toolkit::ScrollViewCustomEffect::FlagSwingAnchor
1032             | Toolkit::ScrollViewCustomEffect::FlagSwingAnchorIn;
1033
1034   mSwingAnchorIn = anchor;
1035 }
1036
1037 void ScrollViewCustomEffect::SetSwingAnchorOut(const Vector3& anchor)
1038 {
1039   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorMask | Toolkit::ScrollViewCustomEffect::FlagSwingAnchorIn))
1040             | Toolkit::ScrollViewCustomEffect::FlagSwingAnchor
1041             | Toolkit::ScrollViewCustomEffect::FlagSwingAnchorOut;
1042
1043   mSwingAnchorOut = anchor;
1044 }
1045
1046 void ScrollViewCustomEffect::SetSwingAnchorAlphaFunction(AlphaFunction func)
1047 {
1048   if(func)
1049   {
1050     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionMask;
1051   }
1052   else
1053   {
1054     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionMask;
1055   }
1056   mSwingAnchorAlphaFunctionIn = mSwingAnchorAlphaFunctionOut = func;
1057 }
1058
1059 void ScrollViewCustomEffect::SetSwingAnchorAlphaFunction(AlphaFunction funcIn, AlphaFunction funcOut)
1060 {
1061   if(funcIn)
1062   {
1063     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionIn;
1064   }
1065   else
1066   {
1067     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionIn;
1068   }
1069   if(funcOut)
1070   {
1071     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionOut;
1072   }
1073   else
1074   {
1075     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionOut;
1076   }
1077   mSwingAnchorAlphaFunctionIn = funcIn;
1078   mSwingAnchorAlphaFunctionOut = funcOut;
1079 }
1080
1081 void ScrollViewCustomEffect::SetSwingAnchorAlphaFunctionIn(AlphaFunction func)
1082 {
1083   if(func)
1084   {
1085     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionIn;
1086   }
1087   else
1088   {
1089     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionIn;
1090   }
1091   mSwingAnchorAlphaFunctionIn = func;
1092 }
1093
1094 void ScrollViewCustomEffect::SetSwingAnchorAlphaFunctionOut(AlphaFunction func)
1095 {
1096   if(func)
1097   {
1098     mFlags |= Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionOut;
1099   }
1100   else
1101   {
1102     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagSwingAnchorAlphaFunctionOut;
1103   }
1104   mSwingAnchorAlphaFunctionOut = func;
1105 }
1106
1107 void ScrollViewCustomEffect::SetOpacityThreshold(float thresh)
1108 {
1109   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdMask)
1110             | Toolkit::ScrollViewCustomEffect::FlagOpacityThreshold
1111             | Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdIn
1112             | Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdOut;
1113
1114   mOpacityThresholdIn = mOpacityThresholdOut = thresh;
1115 }
1116
1117 void ScrollViewCustomEffect::SetOpacityThreshold(float threshIn, float threshOut)
1118 {
1119   // set flags describing translation with separate in out translation
1120   mFlags = (mFlags & ~Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdMask)
1121             | Toolkit::ScrollViewCustomEffect::FlagOpacityThreshold
1122             | Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdIn
1123             | Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdOut;
1124
1125   mOpacityThresholdIn = threshIn;
1126   mOpacityThresholdOut = threshOut;
1127 }
1128
1129 void ScrollViewCustomEffect::SetOpacityThresholdIn(float thresh)
1130 {
1131   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdMask | Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdOut))
1132             | Toolkit::ScrollViewCustomEffect::FlagOpacityThreshold
1133             | Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdIn;
1134
1135   mOpacityThresholdIn = thresh;
1136 }
1137
1138 void ScrollViewCustomEffect::SetOpacityThresholdOut(float thresh)
1139 {
1140   mFlags = (mFlags & (~Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdMask | Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdIn))
1141             | Toolkit::ScrollViewCustomEffect::FlagOpacityThreshold
1142             | Toolkit::ScrollViewCustomEffect::FlagOpacityThresholdOut;
1143
1144   mOpacityThresholdOut = thresh;
1145 }
1146
1147 void ScrollViewCustomEffect::SetOpacityAlphaFunction(AlphaFunction func)
1148 {
1149   if(func)
1150   {
1151     mFlags |= Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionMask;
1152   }
1153   else
1154   {
1155     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionMask;
1156   }
1157   mOpacityAlphaFunctionIn = mOpacityAlphaFunctionOut = func;
1158 }
1159
1160 void ScrollViewCustomEffect::SetOpacityAlphaFunction(AlphaFunction funcIn, AlphaFunction funcOut)
1161 {
1162   if(funcIn)
1163   {
1164     mFlags |= Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionIn;
1165   }
1166   else
1167   {
1168     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionIn;
1169   }
1170   if(funcOut)
1171   {
1172     mFlags |= Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionOut;
1173   }
1174   else
1175   {
1176     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionOut;
1177   }
1178   mOpacityAlphaFunctionIn = funcIn;
1179   mOpacityAlphaFunctionOut = funcOut;
1180 }
1181
1182 void ScrollViewCustomEffect::SetOpacityAlphaFunctionIn(AlphaFunction func)
1183 {
1184   if(func)
1185   {
1186     mFlags |= Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionIn;
1187   }
1188   else
1189   {
1190     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionIn;
1191   }
1192   mOpacityAlphaFunctionIn = func;
1193 }
1194
1195 void ScrollViewCustomEffect::SetOpacityAlphaFunctionOut(AlphaFunction func)
1196 {
1197   if(func)
1198   {
1199     mFlags |= Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionOut;
1200   }
1201   else
1202   {
1203     mFlags &= ~Toolkit::ScrollViewCustomEffect::FlagOpacityAlphaFunctionOut;
1204   }
1205   mOpacityAlphaFunctionOut = func;
1206 }
1207
1208 void ScrollViewCustomEffect::ApplyToPage( Actor page, Vector3 pageSize)
1209 {
1210   // may have already called register for these properties, so check before registering
1211   Dali::Toolkit::ScrollView scrollView = GetScrollView();
1212   Property::Index scrollPropertyIndex = page.GetPropertyIndex(SCROLL_AMOUNT_PROPERTY_STRING);
1213   if(scrollPropertyIndex == Property::INVALID_INDEX)
1214   {
1215     scrollPropertyIndex = page.RegisterProperty(SCROLL_AMOUNT_PROPERTY_STRING, Vector3::ZERO);
1216   }
1217
1218   Property::Index anchorPropertyIndex = page.GetPropertyIndex(ANCHOR_POINT_PROPERTY_STRING);
1219   if(anchorPropertyIndex == Property::INVALID_INDEX)
1220   {
1221     anchorPropertyIndex = page.RegisterProperty(ANCHOR_POINT_PROPERTY_STRING, Vector3::ZERO);
1222   }
1223
1224   ScrollViewCustomEffectInfoPtr info(new ScrollViewCustomEffectInfo(
1225                                                                      mFlags,
1226                                                                      scrollPropertyIndex,
1227                                                                      anchorPropertyIndex,
1228                                                                      mPageSpacing,
1229                                                                      mTranslateIn, mTranslateOut,
1230                                                                      mGlobalRotateIn, mGlobalRotateOut,
1231                                                                      mGlobalOriginIn, mGlobalOriginOut,
1232                                                                      mSwingAngleIn, mSwingAxisIn, mSwingAngleOut, mSwingAxisOut,
1233                                                                      mSwingAnchorIn - AnchorPoint::CENTER, mSwingAnchorOut - AnchorPoint::CENTER,
1234                                                                      mOpacityThresholdIn, mOpacityThresholdOut,
1235                                                                      mGlobalRotateAlphaFunctionIn, mGlobalRotateAlphaFunctionOut,
1236                                                                      mSwingAlphaFunctionIn, mSwingAlphaFunctionOut,
1237                                                                      mSwingAnchorAlphaFunctionIn, mSwingAnchorAlphaFunctionOut,
1238                                                                      mTranslateAlphaFunctionIn, mTranslateAlphaFunctionOut,
1239                                                                      mOpacityAlphaFunctionIn, mOpacityAlphaFunctionOut));
1240
1241   ScrollViewCustomEffectInfo effectInfo( *info );
1242   Property::Index scrollAmountProperty = effectInfo.mScrollAmountProperty;
1243   Property::Index anchProperty = effectInfo.mAnchorProperty;
1244   // Apply constraints to this actor //
1245   Constraint constraint;
1246   constraint = Constraint::New<Vector3>( scrollAmountProperty,
1247                                             LocalSource(Actor::POSITION),
1248                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
1249                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
1250                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
1251                                             Source(scrollView, Actor::SIZE ),
1252                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
1253                                             boost::bind( &ScrollViewCustomEffectInfo::ScrollAmountConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
1254
1255   constraint.SetRemoveAction( Constraint::Discard );
1256   page.ApplyConstraint( constraint );
1257
1258   constraint = Constraint::New<Quaternion>( Actor::ROTATION,
1259                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
1260                                          Source( scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_PANNING_PROPERTY_NAME ) ),
1261                                          Source( scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_SCROLLING_PROPERTY_NAME ) ),
1262                                          boost::bind( &ScrollViewCustomEffectInfo::PageDirectionAndRotationConstraint, info, _1, _2, _3, _4) );
1263
1264   constraint.SetRemoveAction( Constraint::Discard );
1265   page.ApplyConstraint( constraint );
1266
1267   constraint = Constraint::New<Vector4>( Actor::COLOR,
1268                                          Source(page, scrollAmountProperty ),
1269                                          boost::bind( &ScrollViewCustomEffectInfo::ColorConstraint, info, _1, _2) );
1270
1271   constraint.SetRemoveAction( Constraint::Discard );
1272   page.ApplyConstraint( constraint );
1273
1274   constraint = Constraint::New<Vector3>( Actor::POSITION,
1275                                          Source(page, scrollAmountProperty ),
1276                                          Source(page, anchProperty ),
1277                                          LocalSource(Actor::ROTATION),
1278                                          boost::bind( &ScrollViewCustomEffectInfo::PositionConstraint, info, _1, _2, _3, _4) );
1279
1280   constraint.SetRemoveAction( Constraint::Discard );
1281   page.ApplyConstraint( constraint );
1282 }
1283
1284 void ScrollViewCustomEffect::OnAttach(Toolkit::ScrollView& scrollView)
1285 {
1286 }
1287
1288 void ScrollViewCustomEffect::OnDetach(Toolkit::ScrollView& scrollView)
1289 {
1290 }
1291
1292 } // namespace Internal
1293
1294 } // namespace Toolkit
1295
1296 } // namespace Dali