Changes after TouchedSignal changes
[platform/core/uifw/dali-demo.git] / examples / scroll-view / scroll-view-example.cpp
1 /*
2  * Copyright (c) 2020 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 // EXTERNAL INCLUDES
19 #include <sstream>
20
21 // INTERNAL INCLUDES
22 #include "shared/view.h"
23 #include <dali/dali.h>
24 #include <dali-toolkit/dali-toolkit.h>
25
26 using namespace Dali;
27 using namespace Dali::Toolkit;
28
29 namespace
30 {
31 const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-default.png" );
32 const char * const TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
33 const char * const APPLICATION_TITLE( "ScrollView" );
34 const char * const EFFECT_CAROUSEL_IMAGE( DEMO_IMAGE_DIR "icon-scroll-view-carousel.png" );
35 const char * const EFFECT_CAROUSEL_IMAGE_SELECTED( DEMO_IMAGE_DIR "icon-scroll-view-carousel-selected.png" );
36 const char * const EFFECT_CUBE_IMAGE( DEMO_IMAGE_DIR "icon-scroll-view-inner-cube.png" );
37 const char * const EFFECT_CUBE_IMAGE_SELECTED( DEMO_IMAGE_DIR "icon-scroll-view-inner-cube-selected.png" );
38 const char * const EFFECT_SPIRAL_IMAGE( DEMO_IMAGE_DIR "icon-scroll-view-spiral.png" );
39 const char * const EFFECT_SPIRAL_IMAGE_SELECTED( DEMO_IMAGE_DIR "icon-scroll-view-spiral-selected.png" );
40 const char * const EFFECT_WAVE_IMAGE( DEMO_IMAGE_DIR "icon-effect-wave.png" );
41 const char * const EFFECT_WAVE_IMAGE_SELECTED( DEMO_IMAGE_DIR "icon-effect-wave-selected.png" );
42
43 const Vector3 ICON_SIZE(100.0f, 100.0f, 0.0f);
44
45 const char* EFFECT_MODE_NAME[] = {
46     "PageCarousel",
47     "PageCube",
48     "PageSpiral",
49     "PageWave"
50 };
51
52 const char * const IMAGE_PATHS[] = {
53     DEMO_IMAGE_DIR "gallery-medium-1.jpg",
54     DEMO_IMAGE_DIR "gallery-medium-2.jpg",
55     DEMO_IMAGE_DIR "gallery-medium-3.jpg",
56     DEMO_IMAGE_DIR "gallery-medium-4.jpg",
57     DEMO_IMAGE_DIR "gallery-medium-5.jpg",
58     DEMO_IMAGE_DIR "gallery-medium-6.jpg",
59     DEMO_IMAGE_DIR "gallery-medium-7.jpg",
60     DEMO_IMAGE_DIR "gallery-medium-8.jpg",
61     DEMO_IMAGE_DIR "gallery-medium-9.jpg",
62     DEMO_IMAGE_DIR "gallery-medium-10.jpg",
63     DEMO_IMAGE_DIR "gallery-medium-11.jpg",
64     DEMO_IMAGE_DIR "gallery-medium-12.jpg",
65     DEMO_IMAGE_DIR "gallery-medium-13.jpg",
66     DEMO_IMAGE_DIR "gallery-medium-14.jpg",
67     DEMO_IMAGE_DIR "gallery-medium-15.jpg",
68     DEMO_IMAGE_DIR "gallery-medium-16.jpg",
69     DEMO_IMAGE_DIR "gallery-medium-17.jpg",
70     DEMO_IMAGE_DIR "gallery-medium-18.jpg",
71     DEMO_IMAGE_DIR "gallery-medium-19.jpg",
72     DEMO_IMAGE_DIR "gallery-medium-20.jpg",
73     DEMO_IMAGE_DIR "gallery-medium-21.jpg",
74     DEMO_IMAGE_DIR "gallery-medium-22.jpg",
75     DEMO_IMAGE_DIR "gallery-medium-23.jpg",
76     DEMO_IMAGE_DIR "gallery-medium-24.jpg",
77     DEMO_IMAGE_DIR "gallery-medium-25.jpg",
78     DEMO_IMAGE_DIR "gallery-medium-26.jpg",
79     DEMO_IMAGE_DIR "gallery-medium-27.jpg",
80     DEMO_IMAGE_DIR "gallery-medium-28.jpg",
81     DEMO_IMAGE_DIR "gallery-medium-29.jpg",
82     DEMO_IMAGE_DIR "gallery-medium-30.jpg",
83     DEMO_IMAGE_DIR "gallery-medium-31.jpg",
84     DEMO_IMAGE_DIR "gallery-medium-32.jpg",
85     DEMO_IMAGE_DIR "gallery-medium-33.jpg",
86     DEMO_IMAGE_DIR "gallery-medium-34.jpg",
87     DEMO_IMAGE_DIR "gallery-medium-35.jpg",
88     DEMO_IMAGE_DIR "gallery-medium-36.jpg",
89     DEMO_IMAGE_DIR "gallery-medium-37.jpg",
90     DEMO_IMAGE_DIR "gallery-medium-38.jpg",
91     DEMO_IMAGE_DIR "gallery-medium-39.jpg",
92     DEMO_IMAGE_DIR "gallery-medium-40.jpg",
93     DEMO_IMAGE_DIR "gallery-medium-41.jpg",
94     DEMO_IMAGE_DIR "gallery-medium-42.jpg",
95     DEMO_IMAGE_DIR "gallery-medium-43.jpg",
96     DEMO_IMAGE_DIR "gallery-medium-44.jpg",
97     DEMO_IMAGE_DIR "gallery-medium-45.jpg",
98     DEMO_IMAGE_DIR "gallery-medium-46.jpg",
99     DEMO_IMAGE_DIR "gallery-medium-47.jpg",
100     DEMO_IMAGE_DIR "gallery-medium-48.jpg",
101     DEMO_IMAGE_DIR "gallery-medium-49.jpg",
102     DEMO_IMAGE_DIR "gallery-medium-50.jpg",
103     DEMO_IMAGE_DIR "gallery-medium-51.jpg",
104     DEMO_IMAGE_DIR "gallery-medium-52.jpg",
105     DEMO_IMAGE_DIR "gallery-medium-53.jpg",
106
107     NULL
108 };
109
110 const char * const GetNextImagePath()
111 {
112   static const char * const * imagePtr = &IMAGE_PATHS[0];
113
114   if ( *(++imagePtr) == NULL )
115   {
116     imagePtr = &IMAGE_PATHS[0];
117   }
118
119   return *imagePtr;
120 }
121
122 const int PAGE_COLUMNS = 10;                                                ///< Number of Pages going across (columns)
123 const int PAGE_ROWS = 1;                                                    ///< Number of Pages going down (rows)
124 const int IMAGE_ROWS = 5;                                                   ///< Number of Images going down (rows) with a Page
125
126 const unsigned int IMAGE_THUMBNAIL_WIDTH  = 256;                            ///< Width of Thumbnail Image in texels
127 const unsigned int IMAGE_THUMBNAIL_HEIGHT = 256;                            ///< Height of Thumbnail Image in texels
128
129 const float SPIN_DURATION = 1.0f;                                           ///< Times to spin an Image by upon touching, each spin taking a second.
130
131 const float EFFECT_SNAP_DURATION(0.66f);                                    ///< Scroll Snap Duration for Effects
132 const float EFFECT_FLICK_DURATION(0.5f);                                    ///< Scroll Flick Duration for Effects
133
134 } // unnamed namespace
135
136 /**
137  * This example shows how to do custom Scroll Effects
138  */
139 class ExampleController : public ConnectionTracker
140 {
141 public:
142
143   /**
144    * Constructor
145    * @param application class, stored as reference
146    */
147   ExampleController( Application& application )
148   : mApplication( application ),
149     mView(),
150     mScrolling(false),
151     mEffectMode(PageCarouselEffect)
152   {
153     // Connect to the Application's Init and orientation changed signal
154     mApplication.InitSignal().Connect(this, &ExampleController::OnInit);
155   }
156
157   ~ExampleController()
158   {
159     // Nothing to do here; everything gets deleted automatically
160   }
161
162   /**
163    * This method gets called once the main loop of application is up and running
164    */
165   void OnInit(Application& app)
166   {
167     Window window = app.GetWindow();
168     window.KeyEventSignal().Connect(this, &ExampleController::OnKeyEvent);
169
170     // Creates a default view with a default tool bar.
171     // The view is added to the window.
172     mContentLayer = DemoHelper::CreateView( app,
173                                             mView,
174                                             mToolBar,
175                                             BACKGROUND_IMAGE,
176                                             TOOLBAR_IMAGE,
177                                             "" );
178
179     mEffectIcon[ PageCarouselEffect ] = EFFECT_CAROUSEL_IMAGE;
180     mEffectIconSelected[ PageCarouselEffect ] = EFFECT_CAROUSEL_IMAGE_SELECTED;
181     mEffectIcon[ PageCubeEffect ]     = EFFECT_CUBE_IMAGE;
182     mEffectIconSelected[ PageCubeEffect ]     = EFFECT_CUBE_IMAGE_SELECTED;
183     mEffectIcon[ PageSpiralEffect ]   = EFFECT_SPIRAL_IMAGE;
184     mEffectIconSelected[ PageSpiralEffect ]   = EFFECT_SPIRAL_IMAGE_SELECTED;
185     mEffectIcon[ PageWaveEffect ]     = EFFECT_WAVE_IMAGE;
186     mEffectIconSelected[ PageWaveEffect ]     = EFFECT_WAVE_IMAGE_SELECTED;
187
188     // Create a effect change button. (right of toolbar)
189     mEffectChangeButton = Toolkit::PushButton::New();
190     mEffectChangeButton.ClickedSignal().Connect( this, &ExampleController::OnEffectTouched );
191     mToolBar.AddControl( mEffectChangeButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_RIGHT, DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
192
193     // Create the content layer.
194     AddContentLayer();
195
196     // Hack to force screen refresh.
197     Animation animation = Animation::New(1.0f);
198     animation.AnimateTo(Property(mContentLayer, Actor::Property::POSITION), Vector3::ZERO );
199     animation.Play();
200   }
201
202 private:
203
204   /**
205    * Adds content to the ContentLayer. This is everything we see
206    * excluding the toolbar at the top.
207    */
208   void AddContentLayer()
209   {
210     Window window = mApplication.GetWindow();
211     Vector2 windowSize = window.GetSize();
212
213     mScrollView = ScrollView::New();
214     mScrollView.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::CENTER);
215     mScrollView.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
216     mContentLayer.Add( mScrollView );
217     mScrollView.SetProperty( Actor::Property::SIZE, windowSize );
218     mScrollView.SetAxisAutoLock( true );
219     mScrollView.SetAxisAutoLockGradient( 1.0f );
220
221     mScrollView.ScrollStartedSignal().Connect( this, &ExampleController::OnScrollStarted );
222     mScrollView.ScrollCompletedSignal().Connect( this, &ExampleController::OnScrollCompleted );
223
224     for(int row = 0;row<PAGE_ROWS;row++)
225     {
226       for(int column = 0;column<PAGE_COLUMNS;column++)
227       {
228         Actor page = CreatePage();
229
230         page.SetProperty( Actor::Property::POSITION, Vector2( column * windowSize.x, row * windowSize.y ));
231         mScrollView.Add( page );
232
233         mPages.push_back(page);
234       }
235     }
236
237     Update();
238   }
239
240   /**
241    * Updates the ScrollView and it's children based
242    * on the current effect.
243    */
244   void Update()
245   {
246     std::stringstream ss(APPLICATION_TITLE);
247     ss << APPLICATION_TITLE << ": " << EFFECT_MODE_NAME[mEffectMode];
248     SetTitle(ss.str());
249
250     mEffectChangeButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, mEffectIcon[ mEffectMode ] );
251     mEffectChangeButton.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, mEffectIconSelected[ mEffectMode ] );
252
253     // remove old Effect if exists.
254     if(mScrollViewEffect)
255     {
256       mScrollView.RemoveEffect(mScrollViewEffect);
257     }
258
259     // apply new Effect to ScrollView
260     ApplyEffectToScrollView();
261     unsigned int pageCount(0);
262     for( std::vector< Actor >::iterator pageIter = mPages.begin(); pageIter != mPages.end(); ++pageIter)
263     {
264       Actor page = *pageIter;
265       ApplyEffectToPage( page, pageCount++ );
266     }
267   }
268
269   /**
270    * Creates a page using a source of images.
271    */
272   Actor CreatePage()
273   {
274     Actor page = Actor::New();
275     page.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
276     page.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
277     page.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
278
279     Window window = mApplication.GetWindow();
280     Vector2 windowSize = window.GetSize();
281
282     const float margin = 10.0f;
283
284     // Calculate the number of images going across (columns) within a page, according to the screen resolution
285     int imageColumns = round(IMAGE_ROWS * (windowSize.x / windowSize.y));
286     const Vector3 imageSize((windowSize.x / imageColumns) - margin, (windowSize.y / IMAGE_ROWS) - margin, 0.0f);
287
288     for(int row = 0;row<IMAGE_ROWS;row++)
289     {
290       for(int column = 0;column<imageColumns;column++)
291       {
292         ImageView image = CreateImage( GetNextImagePath(), imageSize.x, imageSize.y );
293
294         image.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
295         image.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
296
297         Vector3 position( margin * 0.5f + (imageSize.x + margin) * column - windowSize.width * 0.5f,
298                          margin * 0.5f + (imageSize.y + margin) * row - windowSize.height * 0.5f,
299                           0.0f);
300         image.SetProperty( Actor::Property::POSITION, position + imageSize * 0.5f );
301         image.SetProperty( Actor::Property::SIZE, imageSize );
302         page.Add(image);
303       }
304     }
305
306     return page;
307   }
308
309   /**
310    * [ScrollView]
311    * Applies effect to scrollView
312    */
313   void ApplyEffectToScrollView()
314   {
315     bool snap(true);
316
317     Window window = mApplication.GetWindow();
318     Vector2 windowSize = window.GetSize();
319
320     RulerPtr rulerX = CreateRuler(snap ? windowSize.width : 0.0f);
321     RulerPtr rulerY = new DefaultRuler;
322     rulerX->SetDomain(RulerDomain(0.0f, windowSize.x * PAGE_COLUMNS, false));
323     rulerY->Disable();
324
325     Dali::Path path = Dali::Path::New();
326     Dali::Property::Array points;
327         points.Resize(3);
328     Dali::Property::Array controlPoints;
329         controlPoints.Resize(4);
330     Vector3 forward;
331     if( mEffectMode == PageCarouselEffect)
332     {
333
334       points[0] = Vector3( windowSize.x*0.75, 0.0f,  -windowSize.x*0.75f);
335       points[1] = Vector3( 0.0f, 0.0f, 0.0f );
336       points[2] = Vector3( -windowSize.x*0.75f, 0.0f,  -windowSize.x*0.75f);
337       path.SetProperty( Path::Property::POINTS, points );
338
339       controlPoints[0] = Vector3( windowSize.x*0.5f, 0.0f, 0.0f );
340       controlPoints[1] = Vector3( windowSize.x*0.5f, 0.0f, 0.0f );
341       controlPoints[2] = Vector3(-windowSize.x*0.5f, 0.0f, 0.0f );
342       controlPoints[3] = Vector3(-windowSize.x*0.5f, 0.0f, 0.0f );
343       path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
344
345       forward = Vector3::ZERO;
346     }
347     else if( mEffectMode == PageCubeEffect)
348     {
349       points[0] = Vector3( windowSize.x*0.5, 0.0f,  windowSize.x*0.5f);
350       points[1] = Vector3( 0.0f, 0.0f, 0.0f );
351       points[2] = Vector3( -windowSize.x*0.5f, 0.0f, windowSize.x*0.5f);
352       path.SetProperty( Path::Property::POINTS, points );
353
354       controlPoints[0] = Vector3( windowSize.x*0.5f, 0.0f, windowSize.x*0.3f );
355       controlPoints[1] = Vector3( windowSize.x*0.3f, 0.0f, 0.0f );
356       controlPoints[2] = Vector3(-windowSize.x*0.3f, 0.0f, 0.0f );
357       controlPoints[3] = Vector3(-windowSize.x*0.5f, 0.0f,  windowSize.x*0.3f );
358       path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
359
360       forward = Vector3(-1.0f,0.0f,0.0f);
361     }
362     else if( mEffectMode == PageSpiralEffect)
363     {
364       points[0] = Vector3( windowSize.x*0.5, 0.0f,  -windowSize.x*0.5f);
365       points[1] = Vector3( 0.0f, 0.0f, 0.0f );
366       points[2] = Vector3( -windowSize.x*0.5f, 0.0f, -windowSize.x*0.5f);
367       path.SetProperty( Path::Property::POINTS, points );
368
369       controlPoints[0] = Vector3( windowSize.x*0.5f, 0.0f, 0.0f );
370       controlPoints[1] = Vector3( windowSize.x*0.5f, 0.0f, 0.0f );
371       controlPoints[2] = Vector3(-windowSize.x*0.5f, 0.0f, 0.0f );
372       controlPoints[3] = Vector3(-windowSize.x*0.5f, 0.0f, 0.0f );
373       path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
374
375       forward = Vector3(-1.0f,0.0f,0.0f);
376     }
377     else if( mEffectMode == PageWaveEffect)
378     {
379       points[0] = Vector3( windowSize.x, 0.0f,  -windowSize.x);
380       points[1] = Vector3( 0.0f, 0.0f, 0.0f );
381       points[2] = Vector3( -windowSize.x, 0.0f, -windowSize.x);
382       path.SetProperty( Path::Property::POINTS, points );
383
384       controlPoints[0] = Vector3( 0.0f, 0.0f, -windowSize.x );
385       controlPoints[1] = Vector3( windowSize.x*0.5f, 0.0f, 0.0f );
386       controlPoints[2] = Vector3( -windowSize.x*0.5f, 0.0f, 0.0f);
387       controlPoints[3] = Vector3(0.0f, 0.0f,-windowSize.x  );
388       path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
389
390       forward = Vector3(-1.0f,0.0f,0.0f);
391     }
392
393     mScrollViewEffect = ScrollViewPagePathEffect::New(path, forward,Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(windowSize.x,windowSize.y,0.0f),PAGE_COLUMNS);
394     mScrollView.SetScrollSnapDuration(EFFECT_SNAP_DURATION);
395     mScrollView.SetScrollFlickDuration(EFFECT_FLICK_DURATION);
396     mScrollView.SetScrollSnapAlphaFunction(AlphaFunction::EASE_OUT);
397     mScrollView.SetScrollFlickAlphaFunction(AlphaFunction::EASE_OUT);
398     mScrollView.RemoveConstraintsFromChildren();
399
400     rulerX = CreateRuler(snap ? windowSize.width * 0.5f : 0.0f);
401     rulerX->SetDomain( RulerDomain( 0.0f, windowSize.x * 0.5f * PAGE_COLUMNS, false ) );
402
403     unsigned int currentPage = mScrollView.GetCurrentPage();
404     if( mScrollViewEffect )
405     {
406       mScrollView.ApplyEffect(mScrollViewEffect);
407     }
408
409     mScrollView.SetWrapMode( true );
410     mScrollView.SetRulerX( rulerX );
411     mScrollView.SetRulerY( rulerY );
412
413     mScrollView.ScrollTo( currentPage, 0.0f );
414   }
415
416   /**
417    * Creates a Ruler that snaps to a specified grid size.
418    * If that grid size is 0.0 then this ruler does not
419    * snap.
420    *
421    * @param[in] gridSize (optional) The grid size for the ruler,
422    * (Default = 0.0 i.e. no snapping)
423    * @return The ruler is returned.
424    */
425   RulerPtr CreateRuler(float gridSize = 0.0f)
426   {
427     if(gridSize <= Math::MACHINE_EPSILON_0)
428     {
429         return new DefaultRuler();
430     }
431     return new FixedRuler(gridSize);
432   }
433   // end switch
434   /**
435     * [Page]
436     * Applies effect to the pages within scroll view.
437     *
438     * @param[in] page The page Actor to apply effect to.
439     */
440    void ApplyEffectToPage(Actor page, unsigned int pageOrder )
441    {
442      page.RemoveConstraints();
443      page.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
444
445      ScrollViewPagePathEffect effect = ScrollViewPagePathEffect::DownCast( mScrollViewEffect );
446      effect.ApplyToPage( page, pageOrder );
447    }
448
449   /**
450    * Creates an Image (Helper)
451    *
452    * @param[in] filename the path of the image.
453    * @param[in] width the width of the image in texels
454    * @param[in] height the height of the image in texels.
455    */
456   ImageView CreateImage( const std::string& filename, int width = IMAGE_THUMBNAIL_WIDTH, int height = IMAGE_THUMBNAIL_HEIGHT )
457   {
458     ImageView actor = ImageView::New();
459     Property::Map map;
460     map[Visual::Property::TYPE] = Visual::IMAGE;
461     map[ImageVisual::Property::URL] = filename;
462     map[ImageVisual::Property::DESIRED_WIDTH] = width;
463     map[ImageVisual::Property::DESIRED_HEIGHT] = height;
464     map[ImageVisual::Property::FITTING_MODE] = FittingMode::SCALE_TO_FILL;
465     map[ImageVisual::Property::SAMPLING_MODE] = SamplingMode::BOX_THEN_LINEAR;
466     actor.SetProperty( ImageView::Property::IMAGE, map );
467
468     actor.SetProperty( Dali::Actor::Property::NAME, filename );
469     actor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
470     actor.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::CENTER);
471
472     actor.TouchedSignal().Connect( this, &ExampleController::OnTouchImage );
473     return actor;
474   }
475
476   /**
477    * When scroll starts (i.e. user starts to drag scrollview),
478    * note this state (mScrolling = true)
479    * @param[in] position Current Scroll Position
480    */
481   void OnScrollStarted( const Vector2& position )
482   {
483     mScrolling = true;
484   }
485
486   /**
487    * When scroll starts (i.e. user stops dragging scrollview, and scrollview has snapped to destination),
488    * note this state (mScrolling = false)
489    * @param[in] position Current Scroll Position
490    */
491   void OnScrollCompleted( const Vector2& position )
492   {
493     mScrolling = false;
494   }
495
496   /**
497    * Upon Touching an image (Release), make it spin
498    * (provided we're not scrolling).
499    * @param[in] actor The actor touched
500    * @param[in] event The touch information.
501    */
502   bool OnTouchImage( Actor actor, const TouchEvent& event )
503   {
504     if( (event.GetPointCount() > 0) && (!mScrolling) )
505     {
506       if( event.GetState( 0 ) == PointState::UP )
507       {
508         // Spin the Image a few times.
509         Animation animation = Animation::New(SPIN_DURATION);
510         animation.AnimateBy( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f * SPIN_DURATION) ), Vector3::XAXIS ), AlphaFunction::EASE_OUT );
511         animation.Play();
512       }
513     }
514     return false;
515   }
516
517   /**
518    * Signal handler, called when the 'Effect' button has been touched.
519    *
520    * @param[in] button The button that was pressed.
521    */
522   bool OnEffectTouched(Button button)
523   {
524     mEffectMode = static_cast<EffectMode>((static_cast<int>(mEffectMode) + 1) % static_cast<int>(Total));
525     Update();
526     return true;
527   }
528
529   /**
530    * Sets/Updates the title of the View
531    * @param[in] title The new title for the view.
532    */
533   void SetTitle(const std::string& title)
534   {
535     if(!mTitleActor)
536     {
537       mTitleActor = DemoHelper::CreateToolBarLabel( "" );
538       // Add title to the tool bar.
539       mToolBar.AddControl( mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HORIZONTAL_CENTER );
540     }
541
542     mTitleActor.SetProperty( Toolkit::TextLabel::Property::TEXT, title );
543   }
544
545   /**
546    * Main key event handler
547    */
548   void OnKeyEvent(const KeyEvent& event)
549   {
550     if(event.GetState() == KeyEvent::DOWN)
551     {
552       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
553       {
554         mApplication.Quit();
555       }
556     }
557   }
558
559 private:
560
561   Application& mApplication;                            ///< Application instance
562   Toolkit::Control mView;                               ///< The View instance.
563   Toolkit::ToolBar mToolBar;                            ///< The View's Toolbar.
564   TextLabel mTitleActor;                                ///< The Toolbar's Title.
565   Layer mContentLayer;                                  ///< The content layer (contains game actors)
566   ScrollView mScrollView;                               ///< ScrollView UI Component
567   bool mScrolling;                                      ///< ScrollView scrolling state (true = scrolling, false = stationary)
568   ScrollViewEffect mScrollViewEffect;                   ///< ScrollView Effect instance.
569   std::vector< Actor > mPages;                          ///< Keeps track of all the pages for applying effects.
570
571   /**
572    * Enumeration of different effects this scrollview can operate under.
573    */
574   enum EffectMode
575   {
576     PageCarouselEffect,                                 ///< Page carousel effect
577     PageCubeEffect,                                     ///< Page cube effect
578     PageSpiralEffect,                                   ///< Page spiral effect
579     PageWaveEffect,                                     ///< Page wave effect
580
581     Total
582   };
583
584   EffectMode mEffectMode;                               ///< Current Effect mode
585
586   std::string mEffectIcon[Total];                       ///< Icons for the effect button
587   std::string mEffectIconSelected[Total];               ///< Icons for the effect button when its selected
588   Toolkit::PushButton mEffectChangeButton;              ///< Effect Change Button
589 };
590
591 int DALI_EXPORT_API main(int argc, char **argv)
592 {
593   Application app = Application::New(&argc, &argv, DEMO_THEME_PATH);
594   ExampleController test(app);
595   app.MainLoop();
596   return 0;
597 }