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