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