Added ScrollView demo & removed hello-world from demo launcher
[platform/core/uifw/dali-demo.git] / examples / scroll-view / scroll-view-example.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 // EXTERNAL INCLUDES
18 #include <sstream>
19
20 // INTERNAL INCLUDES
21 #include "../shared/view.h"
22 #include <dali/dali.h>
23 #include <dali-toolkit/dali-toolkit.h>
24
25 using namespace std;
26 using namespace Dali;
27 using namespace Dali::Toolkit;
28
29 namespace
30 {
31 const char * const BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-default.png" );
32 const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
33 const char * const APPLICATION_TITLE( "ScrollView" );
34 const char * const EFFECT_NORMAL_IMAGE( DALI_IMAGE_DIR "icon-scroll-view-normal.png" );
35 const char * const EFFECT_OUTER_CUBE_IMAGE( DALI_IMAGE_DIR "icon-scroll-view-outer-cube.png" );
36 const char * const EFFECT_DEPTH_IMAGE( DALI_IMAGE_DIR "icon-scroll-view-depth.png" );
37 const char * const EFFECT_INNER_CUBE_IMAGE( DALI_IMAGE_DIR "icon-scroll-view-inner-cube.png" );
38 const char * const EFFECT_CAROUSEL_IMAGE( DALI_IMAGE_DIR "icon-scroll-view-carousel.png" );
39 const char * const EFFECT_SPIRAL_IMAGE( DALI_IMAGE_DIR "icon-scroll-view-spiral.png" );
40
41 const Vector3 ICON_SIZE(100.0f, 100.0f, 0.0f);
42
43 const char* EFFECT_MODE_NAME[] = { "Normal",
44                                    "OuterCube",
45                                    "Depth",
46                                    "InnerCube",
47                                    "Carousel",
48                                    "Spiral",
49                                  };
50
51 const char* PEOPLE_IMAGE_PATHS[] =   { DALI_IMAGE_DIR "people-medium-1.jpg",
52                                        DALI_IMAGE_DIR "people-medium-2.jpg",
53                                        DALI_IMAGE_DIR "people-medium-3.jpg",
54                                        DALI_IMAGE_DIR "people-medium-4.jpg",
55                                        DALI_IMAGE_DIR "people-medium-5.jpg",
56                                        DALI_IMAGE_DIR "people-medium-6.jpg",
57                                        DALI_IMAGE_DIR "people-medium-7.jpg",
58                                        DALI_IMAGE_DIR "people-medium-8.jpg",
59                                        NULL};
60
61 const char* TODAY_IMAGE_PATHS[] =    { DALI_IMAGE_DIR "gallery-medium-1.jpg",
62                                        DALI_IMAGE_DIR "gallery-medium-2.jpg",
63                                        DALI_IMAGE_DIR "gallery-medium-3.jpg",
64                                        DALI_IMAGE_DIR "gallery-medium-4.jpg",
65                                        DALI_IMAGE_DIR "gallery-medium-5.jpg",
66                                        NULL};
67
68 const char* PHONE_IMAGE_PATHS[] =    { DALI_IMAGE_DIR "gallery-medium-5.jpg",
69                                        DALI_IMAGE_DIR "gallery-medium-6.jpg",
70                                        DALI_IMAGE_DIR "gallery-medium-7.jpg",
71                                        DALI_IMAGE_DIR "gallery-medium-8.jpg",
72                                        DALI_IMAGE_DIR "gallery-medium-9.jpg",
73                                        NULL};
74
75 const char* PICTURES_IMAGE_PATHS[] = { DALI_IMAGE_DIR "gallery-medium-10.jpg",
76                                        DALI_IMAGE_DIR "gallery-medium-11.jpg",
77                                        DALI_IMAGE_DIR "gallery-medium-12.jpg",
78                                        DALI_IMAGE_DIR "gallery-medium-13.jpg",
79                                        DALI_IMAGE_DIR "gallery-medium-14.jpg",
80                                        NULL};
81
82 const char* MUSIC_IMAGE_PATHS[] =    { DALI_IMAGE_DIR "gallery-medium-15.jpg",
83                                        DALI_IMAGE_DIR "gallery-medium-16.jpg",
84                                        DALI_IMAGE_DIR "gallery-medium-17.jpg",
85                                        DALI_IMAGE_DIR "gallery-medium-18.jpg",
86                                        DALI_IMAGE_DIR "gallery-medium-19.jpg",
87                                        DALI_IMAGE_DIR "gallery-medium-20.jpg",
88                                        NULL};
89
90 const char* MAGAZINE_IMAGE_PATHS[] = { DALI_IMAGE_DIR "gallery-medium-21.jpg",
91                                        DALI_IMAGE_DIR "gallery-medium-22.jpg",
92                                        DALI_IMAGE_DIR "gallery-medium-23.jpg",
93                                        DALI_IMAGE_DIR "gallery-medium-24.jpg",
94                                        DALI_IMAGE_DIR "gallery-medium-25.jpg",
95                                        DALI_IMAGE_DIR "gallery-medium-26.jpg",
96                                        NULL};
97
98 const char **IMAGE_GROUPS[] = {PEOPLE_IMAGE_PATHS,
99                                TODAY_IMAGE_PATHS,
100                                PHONE_IMAGE_PATHS,
101                                PICTURES_IMAGE_PATHS,
102                                MUSIC_IMAGE_PATHS,
103                                MAGAZINE_IMAGE_PATHS,
104                                NULL};
105
106 const int PAGE_COLUMNS = 10;                                                 ///< Number of Pages going across (columns)
107 const int PAGE_ROWS = 1;                                                    ///< Number of Pages going down (rows)
108 const int IMAGE_COLUMNS = 3;                                                ///< Number of Images going across (columns) within a Page
109 const int IMAGE_ROWS = 5;                                                   ///< Number of Images going down (rows) with a Page
110
111 // 3D Effect constants
112 const Vector3 ANGLE_CUBE_PAGE_ROTATE(Math::PI * 0.2f, Math::PI * 0.2f, 0.0f);  ///< Cube page rotates as if it has ten sides with the camera positioned inside
113 const Vector2 ANGLE_CUSTOM_CUBE_SWING(-Math::PI * 0.45f, -Math::PI * 0.45f);  ///< outer cube pages swing 90 degrees as they pan offscreen
114 const Vector2 ANGLE_SPIRAL_SWING_IN(Math::PI * 0.45f, Math::PI * 0.45f);
115 const Vector2 ANGLE_SPIRAL_SWING_OUT(Math::PI * 0.3f, Math::PI * 0.3f);
116
117 // Depth Effect constants
118 const Vector2 POSITION_EXTENT_DEPTH_EFFECT(0.5f, 2.5f);                     ///< Extent of X & Y position to alter function exponent.
119 const Vector2 OFFSET_EXTENT_DEPTH_EFFECT(1.0f, 1.0f);                       ///< Function exponent offset constant.
120 const float POSITION_SCALE_DEPTH_EFFECT(1.5f);                              ///< Position scaling.
121 const float SCALE_EXTENT_DEPTH_EFFECT(0.5f);                                ///< Maximum scale factor when Actors scrolled one page away (50% size)
122
123 const unsigned int IMAGE_THUMBNAIL_WIDTH  = 256;                            ///< Width of Thumbnail Image in texels
124 const unsigned int IMAGE_THUMBNAIL_HEIGHT = 256;                            ///< Height of Thumbnail Image in texels
125
126 const float SPIN_DURATION = 5.0f;                                           ///< Times to spin an Image by upon touching, each spin taking a second.
127
128 const float EFFECT_SNAP_DURATION(0.66f);                                    ///< Scroll Snap Duration for Effects
129 const float EFFECT_FLICK_DURATION(0.5f);                                    ///< Scroll Flick Duration for Effects
130
131 /**
132  * WrapActorOffsetedConstraint
133  * Wraps an Actor's position based on its position
134  * within a scroll domain taking into account its
135  * size, anchor point, and an offset.
136  */
137 struct WrapActorOffsetedConstraint
138 {
139   WrapActorOffsetedConstraint(Vector2 offset)
140   : mOffset(offset)
141   {
142   }
143
144   Vector3 operator()(const Vector3&    current,
145                      const PropertyInput& actorScaleProperty,
146                      const PropertyInput& actorAnchorPointProperty,
147                      const PropertyInput& actorSizeProperty,
148                      const PropertyInput& scrollPositionMin,
149                      const PropertyInput& scrollPositionMax,
150                      const PropertyInput& scrollWrap)
151   {
152     Vector3 position = current;
153     bool wrap = scrollWrap.GetBoolean();
154
155     if(wrap)
156     {
157       Vector3 min = scrollPositionMin.GetVector3();
158       Vector3 max = scrollPositionMax.GetVector3();
159
160       Vector3 anchor = actorAnchorPointProperty.GetVector3();
161       Vector3 scale = actorScaleProperty.GetVector3();
162       Vector3 size = actorSizeProperty.GetVector3();
163
164       if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
165       {
166         // WRAP X (based on the position of the right side)
167         float offsetX = (1.0f - anchor.x) * size.x * scale.x;
168         offsetX += mOffset.x;
169         position.x = WrapInDomain(position.x + offsetX, min.x, max.x) - offsetX;
170       }
171
172       if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
173       {
174         // WRAP Y (based on the position of the bottom side)
175         float offsetY = (1.0f - anchor.y) * size.y * scale.y;
176         offsetY += mOffset.y;
177         position.y = WrapInDomain(position.y + offsetY, min.y, max.y) - offsetY;
178       }
179     }
180
181     return position;
182   }
183
184 private:
185
186   const Vector2 mOffset;
187
188 };
189
190
191 } // unnamed namespace
192
193 /**
194  * This example shows how to do custom Scroll Effects
195  */
196 class ExampleController : public ConnectionTracker
197 {
198 public:
199
200   /**
201    * Constructor
202    * @param application class, stored as reference
203    */
204   ExampleController( Application& application )
205   : mApplication( application ),
206     mView(),
207     mScrolling(false),
208     mEffectMode(CarouselEffect)
209   {
210     // Connect to the Application's Init and orientation changed signal
211     mApplication.InitSignal().Connect(this, &ExampleController::OnInit);
212   }
213
214   ~ExampleController()
215   {
216     // Nothing to do here; everything gets deleted automatically
217   }
218
219   /**
220    * This method gets called once the main loop of application is up and running
221    */
222   void OnInit(Application& app)
223   {
224     Stage::GetCurrent().KeyEventSignal().Connect(this, &ExampleController::OnKeyEvent);
225
226     // Hide the indicator bar
227     mApplication.GetWindow().ShowIndicator(false);
228
229     // Creates a default view with a default tool bar.
230     // The view is added to the stage.
231
232     mContentLayer = DemoHelper::CreateView( app,
233                                             mView,
234                                             mToolBar,
235                                             BACKGROUND_IMAGE,
236                                             TOOLBAR_IMAGE,
237                                             "" );
238
239     mEffectIcon[ Normal ]          = Image::New( EFFECT_NORMAL_IMAGE );
240     mEffectIcon[ OuterCubeEffect ] = Image::New( EFFECT_OUTER_CUBE_IMAGE );
241     mEffectIcon[ DepthEffect ]     = Image::New( EFFECT_DEPTH_IMAGE );
242     mEffectIcon[ InnerCubeEffect ] = Image::New( EFFECT_INNER_CUBE_IMAGE );
243     mEffectIcon[ CarouselEffect ]  = Image::New( EFFECT_CAROUSEL_IMAGE );
244     mEffectIcon[ SpiralEffect ]    = Image::New( EFFECT_SPIRAL_IMAGE );
245
246     // Create a effect change button. (right of toolbar)
247     mEffectChangeButton = Toolkit::PushButton::New();
248     mEffectChangeButton.ClickedSignal().Connect( this, &ExampleController::OnEffectTouched );
249     mToolBar.AddControl( mEffectChangeButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
250
251     // Create the content layer.
252     AddContentLayer();
253
254     // Hack to force screen refresh.
255     Animation animation = Animation::New(1.0f);
256     animation.AnimateTo(Property(mContentLayer, Actor::POSITION), Vector3::ZERO );
257     animation.Play();
258   }
259
260 private:
261
262   /**
263    * Adds content to the ContentLayer. This is everything we see
264    * excluding the toolbar at the top.
265    */
266   void AddContentLayer()
267   {
268     Stage stage = Stage::GetCurrent();
269     Vector2 stageSize = stage.GetSize();
270
271     mScrollView = ScrollView::New();
272     mScrollView.SetAnchorPoint(AnchorPoint::CENTER);
273     mScrollView.SetParentOrigin(ParentOrigin::CENTER);
274     mContentLayer.Add( mScrollView );
275     mScrollView.SetSize( stageSize );
276     mScrollView.SetAxisAutoLock( true );
277     mScrollView.SetAxisAutoLockGradient( 1.0f );
278
279     mScrollView.ScrollStartedSignal().Connect( this, &ExampleController::OnScrollStarted );
280     mScrollView.ScrollCompletedSignal().Connect( this, &ExampleController::OnScrollCompleted );
281
282     int groupIndex = 0;
283     for(int row = 0;row<PAGE_ROWS;row++)
284     {
285       for(int column = 0;column<PAGE_COLUMNS;column++)
286       {
287         Actor page = CreatePage(IMAGE_GROUPS[groupIndex]);
288
289         page.SetPosition( column * stageSize.x, row * stageSize.y );
290         mScrollView.Add( page );
291
292         groupIndex++;
293         if(!IMAGE_GROUPS[groupIndex])
294         {
295           groupIndex = 0;
296         }
297
298         mPages.push_back(page);
299       }
300     }
301
302     Update();
303   }
304
305   /**
306    * Updates the ScrollView and it's children based
307    * on the current effect.
308    */
309   void Update()
310   {
311     std::stringstream ss(APPLICATION_TITLE);
312     ss << APPLICATION_TITLE << ": " << EFFECT_MODE_NAME[mEffectMode];
313     SetTitle(ss.str());
314
315     mEffectChangeButton.SetBackgroundImage( mEffectIcon[ mEffectMode ] );
316
317     // remove old Effect if exists.
318     if(mScrollViewEffect)
319     {
320       mScrollView.RemoveEffect(mScrollViewEffect);
321     }
322
323     // apply new Effect to ScrollView
324     ApplyEffectToScrollView();
325
326     for(ActorIter pageIter = mPages.begin(); pageIter != mPages.end(); ++pageIter)
327     {
328       Actor page = *pageIter;
329       ApplyEffectToPage( page );
330
331       unsigned int numChildren = (*pageIter).GetChildCount();
332       for(unsigned int i=0; i<numChildren; ++i)
333       {
334         Actor image = (*pageIter).GetChildAt(i);
335
336         // Remove old effect's manual constraints.
337         image.RemoveConstraints();
338
339         // Apply new effect's manual constraints.
340         ApplyEffectToActor( image, page, (rand()&1) );
341       }
342     }
343   }
344
345   /**
346    * Creates a page using a source of images.
347    * @param[in] paths pointer to Null-terminated array of Null-terminated strings.
348    */
349   Actor CreatePage(const char **paths)
350   {
351     int pathIndex = 0;
352     Actor page = Actor::New();
353     page.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
354     page.SetParentOrigin( ParentOrigin::CENTER );
355     page.SetAnchorPoint( AnchorPoint::CENTER );
356
357     Stage stage = Stage::GetCurrent();
358     Vector2 stageSize = stage.GetSize();
359
360     const float margin = 10.0f;
361
362     const Vector3 imageSize((stageSize.x / IMAGE_COLUMNS) - margin, (stageSize.y / IMAGE_ROWS) - margin, 0.0f);
363
364     for(int row = 0;row<IMAGE_ROWS;row++)
365     {
366       for(int column = 0;column<IMAGE_COLUMNS;column++)
367       {
368         ImageActor image = CreateImage(paths[pathIndex]);
369
370         image.SetParentOrigin( ParentOrigin::CENTER );
371         image.SetAnchorPoint( AnchorPoint::CENTER );
372
373         Vector3 position( margin * 0.5f + (imageSize.x + margin) * column - stageSize.width * 0.5f,
374                          margin * 0.5f + (imageSize.y + margin) * row - stageSize.height * 0.5f,
375                           0.0f);
376         image.SetPosition( position + imageSize * 0.5f );
377         image.SetSize( imageSize );
378         page.Add(image);
379
380         pathIndex++;
381         if(!paths[pathIndex])
382         {
383           pathIndex = 0;
384         }
385       }
386     }
387
388     return page;
389   }
390
391   /**
392    * [ScrollView]
393    * Applies effect to scrollView
394    */
395   void ApplyEffectToScrollView()
396   {
397     bool wrap(true);
398     bool snap(true);
399
400     Stage stage = Stage::GetCurrent();
401     Vector2 stageSize = stage.GetSize();
402
403     switch(mEffectMode)
404     {
405       case Normal:
406       {
407         SetupNormalPageEffect();
408         break;
409       }
410
411       case OuterCubeEffect:
412       {
413         SetupOuterPageCubeEffect();
414         break;
415       }
416
417       case DepthEffect:
418       {
419         mScrollViewEffect = ScrollViewDepthEffect::New();
420         mScrollView.SetScrollSnapDuration(EFFECT_SNAP_DURATION);
421         mScrollView.SetScrollFlickDuration(EFFECT_FLICK_DURATION);
422         mScrollView.SetScrollSnapAlphaFunction(AlphaFunctions::EaseOut);
423         mScrollView.SetScrollFlickAlphaFunction(AlphaFunctions::EaseOut);
424         mScrollView.RemoveConstraintsFromChildren();
425         break;
426       }
427
428       case InnerCubeEffect:
429       {
430         SetupInnerPageCubeEffect();
431         break;
432       }
433
434       case CarouselEffect:
435       {
436         SetupCarouselPageEffect();
437         break;
438       }
439
440       case SpiralEffect:
441       {
442         SetupSpiralPageEffect();
443         break;
444       }
445
446       default:
447       {
448         break;
449       }
450     } // end switch
451
452     if(mScrollViewEffect)
453     {
454       mScrollView.ApplyEffect(mScrollViewEffect);
455     }
456
457     mScrollView.SetWrapMode(wrap);
458
459     RulerPtr rulerX = CreateRuler(snap ? stageSize.width : 0.0f);
460     RulerPtr rulerY = new DefaultRuler;
461     rulerX->SetDomain(RulerDomain(0.0f, stageSize.x * PAGE_COLUMNS, !wrap));
462     rulerY->Disable();
463
464     mScrollView.SetRulerX( rulerX );
465     mScrollView.SetRulerY( rulerY );
466   }
467
468   /**
469    * Creates a Ruler that snaps to a specified grid size.
470    * If that grid size is 0.0 then this ruler does not
471    * snap.
472    *
473    * @param[in] gridSize (optional) The grid size for the ruler,
474    * (Default = 0.0 i.e. no snapping)
475    * @return The ruler is returned.
476    */
477   RulerPtr CreateRuler(float gridSize = 0.0f)
478   {
479     if(gridSize <= Math::MACHINE_EPSILON_0)
480     {
481         return new DefaultRuler();
482     }
483     return new FixedRuler(gridSize);
484   }
485
486   void SetupNormalPageEffect()
487   {
488     mScrollViewEffect.Reset();
489     mScrollView.SetScrollSnapDuration(ScrollView::DEFAULT_SLOW_SNAP_ANIMATION_DURATION);
490     mScrollView.SetScrollFlickDuration(ScrollView::DEFAULT_FAST_SNAP_ANIMATION_DURATION);
491     mScrollView.SetScrollSnapAlphaFunction(AlphaFunctions::EaseOut);
492     mScrollView.SetScrollFlickAlphaFunction(AlphaFunctions::EaseOut);
493     mScrollView.RemoveConstraintsFromChildren();
494   }
495
496   void SetupInnerPageCubeEffect()
497   {
498     ScrollViewCustomEffect customEffect;
499     mScrollViewEffect = customEffect = ScrollViewCustomEffect::New();
500     mScrollView.SetScrollSnapDuration(EFFECT_SNAP_DURATION);
501     mScrollView.SetScrollFlickDuration(EFFECT_FLICK_DURATION);
502     mScrollView.SetScrollSnapAlphaFunction(AlphaFunctions::EaseOutBack);
503     mScrollView.SetScrollFlickAlphaFunction(AlphaFunctions::EaseOutBack);
504     mScrollView.RemoveConstraintsFromChildren();
505
506     customEffect.SetPageSpacing(Vector2(30.0f, 30.0f));
507     customEffect.SetAngledOriginPageRotation(ANGLE_CUBE_PAGE_ROTATE);
508     customEffect.SetSwingAngle(ANGLE_CUBE_PAGE_ROTATE.x, Vector3(0,-1,0));
509     customEffect.SetOpacityThreshold(0.7f);
510   }
511
512   void SetupOuterPageCubeEffect()
513   {
514     ScrollViewCustomEffect customEffect;
515     mScrollViewEffect = customEffect = ScrollViewCustomEffect::New();
516     mScrollView.SetScrollSnapDuration(EFFECT_SNAP_DURATION);
517     mScrollView.SetScrollFlickDuration(EFFECT_FLICK_DURATION);
518     mScrollView.SetScrollSnapAlphaFunction(AlphaFunctions::EaseOut);
519     mScrollView.SetScrollFlickAlphaFunction(AlphaFunctions::EaseOut);
520     mScrollView.RemoveConstraintsFromChildren();
521
522     Vector2 pageSize = Stage::GetCurrent().GetSize();
523     customEffect.SetPageTranslation(Vector3(pageSize.x, pageSize.y, 0));
524     customEffect.SetSwingAngleOut(ANGLE_CUSTOM_CUBE_SWING.x, Vector3(0.0f, -1.0f, 0.0f));
525     customEffect.SetSwingAnchor(AnchorPoint::CENTER, AnchorPoint::CENTER_LEFT);
526     customEffect.SetOpacityThreshold(0.5f);
527   }
528
529   void SetupCarouselPageEffect()
530   {
531     ScrollViewCustomEffect customEffect;
532     mScrollViewEffect = customEffect = ScrollViewCustomEffect::New();
533     mScrollView.SetScrollSnapDuration(EFFECT_SNAP_DURATION);
534     mScrollView.SetScrollFlickDuration(EFFECT_FLICK_DURATION);
535     mScrollView.SetScrollSnapAlphaFunction(AlphaFunctions::EaseOutBack);
536     mScrollView.SetScrollFlickAlphaFunction(AlphaFunctions::EaseOutBack);
537     mScrollView.RemoveConstraintsFromChildren();
538
539     customEffect.SetPageTranslation(Vector3(0,0,0), Vector3(-30, 0, 0));
540     customEffect.SetPageSpacing(Vector2(60.0f, 60.0f));
541     customEffect.SetAngledOriginPageRotation(-ANGLE_CUBE_PAGE_ROTATE);
542     customEffect.SetOpacityThreshold(0.2f, 0.6f);
543   }
544
545   void SetupSpiralPageEffect()
546   {
547     ScrollViewCustomEffect customEffect;
548     mScrollViewEffect = customEffect = ScrollViewCustomEffect::New();
549     mScrollView.SetScrollSnapDuration(EFFECT_SNAP_DURATION);
550     mScrollView.SetScrollFlickDuration(EFFECT_FLICK_DURATION);
551     mScrollView.SetScrollSnapAlphaFunction(AlphaFunctions::EaseOutBack);
552     mScrollView.SetScrollFlickAlphaFunction(AlphaFunctions::EaseOutBack);
553     mScrollView.RemoveConstraintsFromChildren();
554
555     Vector2 pageSize = Stage::GetCurrent().GetSize();
556     customEffect.SetPageTranslation(Vector3(pageSize.x, pageSize.y, 0.0f));
557     customEffect.SetSwingAngle(-ANGLE_SPIRAL_SWING_IN.x, Vector3(0.0f, -1.0f, 0.0f), ANGLE_SPIRAL_SWING_OUT.x, Vector3(0.0f, -1.0f, 0.0f));
558     customEffect.SetSwingAnchor(AnchorPoint::CENTER_RIGHT);
559     customEffect.SetPageTranslation(Vector3(pageSize.x, pageSize.y, 0), Vector3(pageSize.x, pageSize.y, 0) * 0.5f);
560     customEffect.SetOpacityThreshold(0.66f);
561   }
562
563   /**
564    * [Page]
565    * Applies effect to the pages within scroll view.
566    *
567    * @param[in] page The page Actor to apply effect to.
568    */
569   void ApplyEffectToPage(Actor page)
570   {
571     page.RemoveConstraints();
572     page.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
573
574     if( mEffectMode == Normal )
575     {
576       Constraint constraint;
577
578       // MoveActor (scrolling)
579       constraint = Constraint::New<Vector3>( Actor::POSITION,
580                                              Source( mScrollView, mScrollView.GetPropertyIndex( ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
581                                              MoveActorConstraint );
582       constraint.SetRemoveAction(Constraint::Discard);
583       page.ApplyConstraint(constraint);
584
585       // WrapActor (wrap functionality) - takes into account parent origin
586       constraint = Constraint::New<Vector3>( Actor::POSITION,
587                                              LocalSource( Actor::SCALE ),
588                                              LocalSource( Actor::ANCHOR_POINT ),
589                                              LocalSource( Actor::SIZE ),
590                                              Source( mScrollView, mScrollView.GetPropertyIndex( ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
591                                              Source( mScrollView, mScrollView.GetPropertyIndex( ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
592                                              Source( mScrollView, mScrollView.GetPropertyIndex( ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
593                                              WrapActorOffsetedConstraint( Stage::GetCurrent().GetSize() * 0.5f ) );
594       constraint.SetRemoveAction(Constraint::Discard);
595       page.ApplyConstraint(constraint);
596     }
597     else if( ( mEffectMode == InnerCubeEffect ) ||
598              ( mEffectMode == OuterCubeEffect ) ||
599              ( mEffectMode == SpiralEffect )    ||
600              ( mEffectMode == CarouselEffect) )
601     {
602       ApplyCustomEffectToPage(page);
603     }
604   }
605
606   void ApplyCustomEffectToPage(Actor page)
607   {
608     ScrollViewCustomEffect customEffect = ScrollViewCustomEffect::DownCast(mScrollViewEffect);
609     Vector2 vStageSize(Stage::GetCurrent().GetSize());
610     customEffect.ApplyToPage(page, Vector3(vStageSize.x, vStageSize.y, 1.0f));
611   }
612
613   /**
614    * [Actor]
615    * Applies effect to child which resides in page (which in turn resides in scrollview)
616    *
617    * @note Page is typically the Parent of child, although in
618    * some scenarios Page is simply a container which has a child as
619    * a descendent.
620    *
621    * @param[in] child The child actor to apply effect to
622    * @param[in] page The page which this child is inside
623    * @param[in] style The style of effect either 0 or 1. (changes anchor point)
624    */
625   void ApplyEffectToActor(Actor child, Actor page, int style)
626   {
627     if( mEffectMode == DepthEffect )
628     {
629       ApplyDepthEffectToActor(child, style);
630     }
631   }
632
633   /**
634    * Applies depth effect to the child which resides in page (which in turn resides in scrollview)
635    *
636    * @param[in] child The child actor to apply depth effect to
637    * @param[in] style The style of effect either 0 or 1. (changes anchor point)
638    */
639   void ApplyDepthEffectToActor(Actor child, int style)
640   {
641     ScrollViewDepthEffect depthEffect = ScrollViewDepthEffect::DownCast(mScrollViewEffect);
642     depthEffect.ApplyToActor( child,
643                               POSITION_EXTENT_DEPTH_EFFECT,
644                               OFFSET_EXTENT_DEPTH_EFFECT,
645                               POSITION_SCALE_DEPTH_EFFECT,
646                               SCALE_EXTENT_DEPTH_EFFECT );
647   }
648
649   /**
650    * Creates an Image (Helper)
651    *
652    * @param[in] filename the path of the image.
653    * @param[in] width the width of the image in texels
654    * @param[in] height the height of the image in texels.
655    */
656   ImageActor CreateImage( const std::string& filename, unsigned int width = IMAGE_THUMBNAIL_WIDTH, unsigned int height = IMAGE_THUMBNAIL_HEIGHT )
657   {
658     ImageAttributes attributes;
659
660     attributes.SetSize(width, height);
661     attributes.SetScalingMode(ImageAttributes::ShrinkToFit);
662     Image img = Image::New(filename, attributes);
663     ImageActor actor = ImageActor::New(img);
664     actor.SetName( filename );
665     actor.SetParentOrigin(ParentOrigin::CENTER);
666     actor.SetAnchorPoint(AnchorPoint::CENTER);
667
668     actor.TouchedSignal().Connect( this, &ExampleController::OnTouchImage );
669     return actor;
670   }
671
672   /**
673    * When scroll starts (i.e. user starts to drag scrollview),
674    * note this state (mScrolling = true)
675    * @param[in] position Current Scroll Position
676    */
677   void OnScrollStarted( const Vector3& position )
678   {
679     mScrolling = true;
680   }
681
682   /**
683    * When scroll starts (i.e. user stops dragging scrollview, and scrollview has snapped to destination),
684    * note this state (mScrolling = false)
685    * @param[in] position Current Scroll Position
686    */
687   void OnScrollCompleted( const Vector3& position )
688   {
689     mScrolling = false;
690   }
691
692   /**
693    * Upon Touching an image (Release), make it spin
694    * (provided we're not scrolling).
695    * @param[in] actor The actor touched
696    * @param[in] event The TouchEvent.
697    */
698   bool OnTouchImage( Actor actor, const TouchEvent& event )
699   {
700     if( (event.points.size() > 0) && (!mScrolling) )
701     {
702       TouchPoint point = event.points[0];
703       if(point.state == TouchPoint::Up)
704       {
705         // Spin the Image a few times.
706         Animation animation = Animation::New(SPIN_DURATION);
707         animation.RotateBy( actor, Degree(360.0f * SPIN_DURATION), Vector3::XAXIS, AlphaFunctions::EaseOut);
708         animation.Play();
709       }
710     }
711     return false;
712   }
713
714   /**
715    * Signal handler, called when the 'Effect' button has been touched.
716    *
717    * @param[in] button The button that was pressed.
718    */
719   bool OnEffectTouched(Button button)
720   {
721     mEffectMode = static_cast<EffectMode>((static_cast<int>(mEffectMode) + 1) % static_cast<int>(Total));
722     Update();
723     return true;
724   }
725
726   /**
727    * Sets/Updates the title of the View
728    * @param[in] title The new title for the view.
729    */
730   void SetTitle(const std::string& title)
731   {
732     if(!mTitleActor)
733     {
734       mTitleActor = TextView::New();
735       // Add title to the tool bar.
736       mToolBar.AddControl( mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HorizontalCenter );
737     }
738
739     Font font = Font::New();
740     mTitleActor.SetText( title );
741     mTitleActor.SetSize( font.MeasureText( title ) );
742     mTitleActor.SetStyleToCurrentText(DemoHelper::GetDefaultTextStyle());
743   }
744
745   /**
746    * Main key event handler
747    */
748   void OnKeyEvent(const KeyEvent& event)
749   {
750     if(event.state == KeyEvent::Down)
751     {
752       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
753       {
754         mApplication.Quit();
755       }
756     }
757   }
758
759 private:
760
761   Application& mApplication;                            ///< Application instance
762   Toolkit::View mView;                                  ///< The View instance.
763   Toolkit::ToolBar mToolBar;                            ///< The View's Toolbar.
764   TextView mTitleActor;                                 ///< The Toolbar's Title.
765   Layer mContentLayer;                                  ///< The content layer (contains game actors)
766   ScrollView mScrollView;                               ///< ScrollView UI Component
767   bool mScrolling;                                      ///< ScrollView scrolling state (true = scrolling, false = stationary)
768   ScrollViewEffect mScrollViewEffect;                   ///< ScrollView Effect instance.
769   ActorContainer mPages;                                ///< Keeps track of all the pages for applying effects.
770
771   /**
772    * Enumeration of different effects this scrollview can operate under.
773    */
774   enum EffectMode
775   {
776     Normal,                                             ///< No Effect (Standard ScrollView)
777     OuterCubeEffect,                                    ///< 3D Rotating Cube Effect
778     DepthEffect,                                        ///< Depth Effect
779     InnerCubeEffect,                                    ///< Page Cube Effect
780     CarouselEffect,                                     ///< Page Carousel Effect
781     SpiralEffect,                                       ///< Page Spiral Effect
782
783     Total,
784   };
785
786   EffectMode mEffectMode;                               ///< Current Effect mode
787
788   Image mEffectIcon[Total];                             ///< Icons for the effect button
789   Toolkit::PushButton mEffectChangeButton;              ///< Effect Change Button
790 };
791
792 int main(int argc, char **argv)
793 {
794   Application app = Application::New(&argc, &argv);
795   ExampleController test(app);
796   app.MainLoop();
797   return 0;
798 }