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