(demo) fix klocwork issues
[platform/core/uifw/dali-demo.git] / examples / cluster / cluster-example.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <sstream>
19 #include <iomanip>
20
21 #include "../shared/view.h"
22 #include <dali/dali.h>
23 #include <dali-toolkit/dali-toolkit.h>
24
25 using namespace Dali;
26 using namespace Dali::Toolkit;
27 using namespace DemoHelper;
28
29 namespace // unnamed namespace
30 {
31
32 const char * const BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-default.png" );
33 const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
34 const char * const APPLICATION_TITLE( "Clusters" );
35 const char * const LAYOUT_NONE_IMAGE( DALI_IMAGE_DIR "icon-cluster-none.png" );
36 const char * const LAYOUT_WOBBLE_IMAGE( DALI_IMAGE_DIR "icon-cluster-wobble.png" );
37 const char * const LAYOUT_CAROUSEL_IMAGE( DALI_IMAGE_DIR "icon-cluster-carousel.png" );
38 const char * const LAYOUT_SPHERE_IMAGE( DALI_IMAGE_DIR "icon-cluster-sphere.png" );
39
40 enum ClusterType
41 {
42   PEOPLE,
43   TODAY,
44   PHONE,
45   PICTURES,
46   MUSIC,
47   MAGAZINE,
48
49   CLUSTER_COUNT
50 };
51
52 const char* PEOPLE_IMAGE_PATHS[] =   { DALI_IMAGE_DIR "people-medium-1.jpg",
53                                        DALI_IMAGE_DIR "people-medium-2.jpg",
54                                        DALI_IMAGE_DIR "people-medium-3.jpg",
55                                        DALI_IMAGE_DIR "people-medium-4.jpg",
56                                        DALI_IMAGE_DIR "people-medium-5.jpg",
57                                        DALI_IMAGE_DIR "people-medium-6.jpg",
58                                        DALI_IMAGE_DIR "people-medium-7.jpg",
59                                        DALI_IMAGE_DIR "people-medium-8.jpg",
60                                        NULL };
61
62 const char* TODAY_IMAGE_PATHS[] =    { DALI_IMAGE_DIR "gallery-medium-1.jpg",
63                                        DALI_IMAGE_DIR "gallery-medium-2.jpg",
64                                        DALI_IMAGE_DIR "gallery-medium-3.jpg",
65                                        DALI_IMAGE_DIR "gallery-medium-4.jpg",
66                                        DALI_IMAGE_DIR "gallery-medium-5.jpg",
67                                        DALI_IMAGE_DIR "gallery-medium-6.jpg",
68                                        NULL };
69
70 const char* PHONE_IMAGE_PATHS[] =    { DALI_IMAGE_DIR "gallery-medium-7.jpg",
71                                        DALI_IMAGE_DIR "gallery-medium-8.jpg",
72                                        DALI_IMAGE_DIR "gallery-medium-9.jpg",
73                                        DALI_IMAGE_DIR "gallery-medium-10.jpg",
74                                        DALI_IMAGE_DIR "gallery-medium-11.jpg",
75                                        DALI_IMAGE_DIR "gallery-medium-12.jpg",
76                                        NULL };
77
78 const char* PICTURES_IMAGE_PATHS[] = { DALI_IMAGE_DIR "gallery-medium-13.jpg",
79                                        DALI_IMAGE_DIR "gallery-medium-14.jpg",
80                                        DALI_IMAGE_DIR "gallery-medium-15.jpg",
81                                        DALI_IMAGE_DIR "gallery-medium-16.jpg",
82                                        DALI_IMAGE_DIR "gallery-medium-17.jpg",
83                                        DALI_IMAGE_DIR "gallery-medium-18.jpg",
84                                        NULL };
85
86 const char* MUSIC_IMAGE_PATHS[] =    { DALI_IMAGE_DIR "gallery-medium-19.jpg",
87                                        DALI_IMAGE_DIR "gallery-medium-20.jpg",
88                                        DALI_IMAGE_DIR "gallery-medium-21.jpg",
89                                        DALI_IMAGE_DIR "gallery-medium-22.jpg",
90                                        DALI_IMAGE_DIR "gallery-medium-23.jpg",
91                                        DALI_IMAGE_DIR "gallery-medium-24.jpg",
92                                        NULL };
93
94 const char* MAGAZINE_IMAGE_PATHS[] = { DALI_IMAGE_DIR "gallery-medium-25.jpg",
95                                        DALI_IMAGE_DIR "gallery-medium-26.jpg",
96                                        DALI_IMAGE_DIR "gallery-medium-27.jpg",
97                                        DALI_IMAGE_DIR "gallery-medium-28.jpg",
98                                        DALI_IMAGE_DIR "gallery-medium-29.jpg",
99                                        DALI_IMAGE_DIR "gallery-medium-30.jpg",
100                                        NULL };
101
102 const char **IMAGE_GROUPS[] = {PEOPLE_IMAGE_PATHS,
103                                TODAY_IMAGE_PATHS,
104                                PHONE_IMAGE_PATHS,
105                                PICTURES_IMAGE_PATHS,
106                                MUSIC_IMAGE_PATHS,
107                                MAGAZINE_IMAGE_PATHS,
108                                NULL};
109
110 const float CLUSTER_IMAGE_THUMBNAIL_WIDTH  = 256.0f;
111 const float CLUSTER_IMAGE_THUMBNAIL_HEIGHT = 256.0f;
112
113 const char* CLUSTER_SHADOW_IMAGE_PATH = DALI_IMAGE_DIR "cluster-image-shadow.png";
114 const char* CLUSTER_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "cluster-image-frame.png";
115 const char* CLUSTER_BACKGROUND_IMAGE_PATH = DALI_IMAGE_DIR "cluster-background.png";
116
117 const float CLUSTER_IMAGE_BORDER_INDENT = 14.0f;            ///< Indent of border in pixels.
118 const float CLUSTER_IMAGE_BORDER_WIDTH = 128;               ///< Width of border in pixels.
119 const float CLUSTER_IMAGE_BORDER_HEIGHT = 128;              ///< Height of border in pixels.
120
121 const Vector4 CLUSTER_IMAGE_BORDER_ABSOLUTE( 16.0f, 16.0f, 16.0f, 16.0f ); // Border dimensions in absolute pixel coordinates.
122
123 // These values depend on the border image
124 const float CLUSTER_RELATIVE_SIZE = 0.65f;                  ///< Cluster size relative to screen width
125
126 const float CLUSTER_GROUP_DELAY_TOP = 0.25f;                ///< Delay for top Clusters in seconds.
127 const float CLUSTER_GROUP_DELAY_BOTTOM = 0.0f;              ///< Delay for bottom Clusters in seconds.
128
129 const float CLUSTER_COLUMN_INDENT = 0.1f;                   ///< Left Indentation in screen coordinates.
130 const float CLUSTER_ROW_INDENT = 0.13f;                     ///< Top Indentation in screen coordinates.
131
132 const Vector3 SHEAR_EFFECT_ANCHOR_POINT(0.5f, 1.0f, 0.5f);  ///< Anchor Point used for the shear effect (extends outside of Cluster)
133 const float SHEAR_EFFECT_MAX_OVERSHOOT = 30.0f;             ///< Max Overshoot for shear effect (in degrees).
134
135 const float UI_MARGIN = 10.0f;                              ///< Screen Margin for placement of UI buttons
136
137 const float CAROUSEL_EFFECT_RADIUS = 500.0f;                ///< In Carousel Effect mode: Radius of carousel (Z peak depth)
138 const float CAROUSEL_EFFECT_ANGLE_SWEEP = 90.0f;            ///< In Carousel Effect mode: Angle sweep from left to right of screen
139 const float SPHERE_EFFECT_RADIUS = 1000.0f;                 ///< In Sphere Effect mode: Radius of sphere carousel (Z peak depth)
140 const float SPHERE_EFFECT_POSITION_Z = -700.0f;             ///< In Sphere Effect mode: Z position alter (as carousel is coming out to screen we move back)
141 const float SPHERE_EFFECT_ANGLE_SWEEP = 90.0f;              ///< In Sphere Effect mode: Angle sweep from edge to opposite side of circle.
142 const float SPHERE_EFFECT_VERTICAL_DOMAIN = 0.15f;          ///< In Sphere Effect mode: How much the user can pan in the vertical axis. (in stageHeights)
143
144 /**
145  * List of effect types that user can select through.
146  */
147 enum ExampleEffectType
148 {
149   NO_EFFECT,
150   WOBBLE_EFFECT,
151   CAROUSEL_EFFECT,
152   SPHERE_EFFECT,
153   TOTAL_EFFECTS
154 };
155
156 /**
157  * List of effect type names that appear on the Effect button.
158  */
159 const char* EXAMPLE_EFFECT_LABEL[] = { "NONE",
160                                        "WOBBLE",
161                                        "CAROUSEL",
162                                        "SPHERE",
163                                      };
164
165 /**
166  * CarouselEffectOrientationConstraint
167  * Based on the View orientation i.e. portrait (0 degrees), landscape (90 degrees) etc.
168  * carousel shader effect should bend differently (as a function of this orientation),
169  * as shader effect is applied to the screen coordinates.
170  */
171 struct CarouselEffectOrientationConstraint
172 {
173   /**
174    * Constructor
175    * @param[in] angleSweep The amount of degrees to rotate by per pixel.
176    */
177   CarouselEffectOrientationConstraint( const Vector2 angleSweep )
178   : mAngleSweep( angleSweep )
179   {
180   }
181
182   /**
183    * @param[in] current The object's current property value
184    * @return The object's new property value
185    */
186   Vector2 operator()(const Vector2& current,
187                      const PropertyInput& propertyOrientation)
188   {
189     Vector3 axis;
190     float angle;
191     propertyOrientation.GetQuaternion().ToAxisAngle( axis, angle );
192     Vector2 direction( cosf(angle), sinf(angle) );
193
194     return mAngleSweep * direction;
195   }
196
197   Vector2 mAngleSweep;
198
199 };
200
201 /**
202  * RescaleConstraint
203  * Rescales the inputer scale by the ratio of the height:width of it's parent.
204  */
205 struct RescaleConstraint
206 {
207   /**
208    * Constructor
209    * @param[in] value0 Constant multiplication operand (K).
210    */
211   RescaleConstraint()
212   {
213   }
214
215   /**
216    * @param[in] current The object's current property value
217    * @param[in] property0 The first property to multiplication operand
218    * @return The object's new property value
219    */
220   Vector3 operator()(const Vector3&    current,
221                      const PropertyInput& property0)
222   {
223     return current * Vector3( property0.GetVector3().y / property0.GetVector3().x, 1.0f, 1.0f );
224   }
225
226 };
227
228 /**
229  * ClusterImageBorderSizeConstraint
230  */
231 struct ClusterImageBorderSizeConstraint
232 {
233   ClusterImageBorderSizeConstraint()
234   : mSizeOffset(Vector3(CLUSTER_IMAGE_BORDER_INDENT - 1, CLUSTER_IMAGE_BORDER_INDENT - 1, 0.0f) * 2.0f)
235   {
236   }
237
238   Vector3 operator()(const Vector3&    current,
239                      const PropertyInput& referenceSizeProperty)
240   {
241     const Vector3& referenceSize = referenceSizeProperty.GetVector3();
242
243     return referenceSize + mSizeOffset;
244   }
245
246   Vector3 mSizeOffset;                        ///< The amount to offset the size from referenceSize
247 };
248
249 /**
250  * ShearEffectConstraint
251  *
252  * Constrains ShearEffect's tilt to be a function of scrollview's
253  * horizontal overshoot amount.
254  */
255 struct ShearEffectConstraint
256 {
257   /**
258    * @param[in] stageSize The stage size (not subject to orientation)
259    * @param[in] maxOvershoot Maximum amount overshoot can affect shear.
260    * @param[in] componentMask Whether constraint should take the X shear
261    * or the Y shear component.
262    */
263   ShearEffectConstraint(Vector2 stageSize, float maxOvershoot, Vector2 componentMask)
264   : mStageSize(stageSize),
265     mMaxOvershoot(maxOvershoot),
266     mComponentMask(componentMask)
267   {
268   }
269
270   /**
271    * @param[in] current The current shear effect Angle.
272    * @param[in] scrollOvershootProperty The overshoot property from ScrollView
273    * @param[in] propertyViewOrientation The orientation of the view e.g. Portrait, Landscape.
274    * @return angle to provide ShearShaderEffect
275    */
276   float operator()(const float&    current,
277                    const PropertyInput& scrollOvershootProperty,
278                    const PropertyInput& propertyViewOrientation)
279   {
280     float f = scrollOvershootProperty.GetVector3().x;
281
282     float mag = fabsf(f);
283     float halfWidth = mStageSize.x * 0.5f;
284
285     // inverse exponential tail-off
286     float overshoot = 1.0f - halfWidth / (halfWidth + mag);
287     if (f > 0.0f)
288     {
289       overshoot = -overshoot;
290     }
291
292     // Channel this shear value into either the X or Y axis depending on
293     // the component mask passed in.
294     Vector3 axis;
295     float angle;
296     propertyViewOrientation.GetQuaternion().ToAxisAngle( axis, angle );
297     Vector2 direction( cosf(angle), sinf(angle) );
298     float yield = direction.x * mComponentMask.x + direction.y * mComponentMask.y;
299
300     return overshoot * mMaxOvershoot * yield;
301   }
302
303   Vector2 mStageSize;
304   float mMaxOvershoot;
305   Vector2 mComponentMask;
306 };
307
308 /**
309  * ShearEffectCenterConstraint
310  *
311  * Sets ShearEffect's center to be a function of the
312  * screen orientation (portrait or landscape).
313  */
314 struct ShearEffectCenterConstraint
315 {
316   /**
317    * @param[in] stageSize The stage size (not subject to orientation)
318    * @param[in] center Shear Center position based on initial orientation.
319    */
320   ShearEffectCenterConstraint(Vector2 stageSize, Vector2 center)
321   : mStageSize(stageSize),
322     mCenter(center)
323   {
324   }
325
326   /**
327    * @param[in] current The current center
328    * @param[in] propertyViewSize The current view size
329    * @return vector to provide ShearShaderEffect
330    */
331   Vector2 operator()(const Vector2&    current,
332                      const PropertyInput& propertyViewSize)
333   {
334     float f = propertyViewSize.GetVector3().width / mStageSize.width;
335     return Vector2( f * mCenter.x, mCenter.y );
336   }
337
338   Vector2 mStageSize;
339   Vector2 mCenter;
340 };
341
342 /**
343  * SphereEffectOffsetConstraint
344  *
345  * Sets SphereEffect's center to be a function of the
346  * screen orientation (portrait or landscape).
347  */
348 struct SphereEffectOffsetConstraint
349 {
350   /**
351    * @param[in] stageSize The stage size (not subject to orientation)
352    * @param[in] center Shear Center position based on initial orientation.
353    */
354   SphereEffectOffsetConstraint(float offset)
355   : mOffset(offset)
356   {
357   }
358
359   /**
360    * @param[in] current The current center
361    * @param[in] propertyViewSize The current view size
362    * @return vector to provide SphereShaderEffect
363    */
364   float operator()(const float& current)
365   {
366     return current + mOffset;
367   }
368
369   float mOffset;
370 };
371
372 /**
373  * ClusterInfo struct
374  *
375  * Contains information about each cluster in mClusterInfo list.
376  */
377 struct ClusterInfo
378 {
379   /**
380    * Constructor
381    *
382    * @param[in] cluster The cluster instance
383    * @param[in] index The cluster's index (starting from 0 for the first cluster)
384    * @param[in] position The cluster's original position
385    * @param[in] size The cluster's original size
386    */
387   ClusterInfo(Cluster cluster, int index, const Vector3& position, const Vector3& size)
388   : mCluster(cluster),
389     mIndex(index),
390     mPosition(position),
391     mSize(size)
392   {
393
394   }
395
396   /**
397    * Copy constructor
398    *
399    * @param[in] rhs The ClusterInfo struct to be copied.
400    */
401   ClusterInfo( const ClusterInfo& rhs )
402   : mCluster(rhs.mCluster),
403     mIndex(rhs.mIndex),
404     mPosition(rhs.mPosition),
405     mSize(rhs.mSize)
406   {
407
408   }
409
410   /**
411    * Assignment operator
412    */
413   ClusterInfo& operator=( const ClusterInfo& rhs )
414   {
415     if( this != &rhs )
416     {
417       mCluster = rhs.mCluster;
418       mIndex = rhs.mIndex;
419       mPosition = rhs.mPosition;
420       mSize = rhs.mSize;
421     }
422     return *this;
423   }
424
425
426   Cluster mCluster;                   ///< Cluster instance
427   int mIndex;                         ///< Cluster index
428   Vector3 mPosition;                  ///< Cluster original position
429   Vector3 mSize;                      ///< Cluster original size
430   ActiveConstraint mEffectConstraint; ///< Cluster constraint
431 };
432
433 /**
434  * Shrinks Actor based on parent's aspect ratio.
435  */
436 struct ShrinkConstraint
437 {
438   /**
439    * Constructor
440    */
441   ShrinkConstraint()
442   {
443   }
444
445   /**
446    * @param[in] current The object's current scale value
447    * @param[in] parentScale The parent's scale
448    * @return The object's new scale value
449    */
450   Vector3 operator()(const Vector3&    current,
451                      const PropertyInput& parentScale)
452   {
453     return Vector3( parentScale.GetVector3().x / parentScale.GetVector3().y, 1.0f, 1.0f );
454   }
455 };
456
457 } // unnamed namespace
458
459 /**
460  * Custom position and size of shadow image
461  */
462 namespace ShadowProperty
463 {
464 const Vector3 ANCHOR_POINT      (0.54f, 0.6f, 0.5f);
465 const Vector3 RELATIVE_POSITION (0.0f, 0.0f, -0.1f);
466 const Vector3 SIZE_SCALE        (1.4f, 1.4f, 1.0f);
467 }
468
469 // This example shows how to use Cluster UI control
470 //
471 class ClusterController : public ConnectionTracker
472 {
473 public:
474
475   /**
476    * Constructor
477    * @param application class, stored as reference
478    */
479   ClusterController(Application &app)
480   : mApplication(app),
481     mClusterCount(0),
482     mExampleEffect(NO_EFFECT)
483   {
484     // Connect to the Application's Init signal
485     app.InitSignal().Connect(this, &ClusterController::Create);
486   }
487
488   ~ClusterController()
489   {
490     // Nothing to do here; everything gets deleted automatically
491   }
492
493   /**
494    * This method gets called once the main loop of application is up and running
495    */
496   void Create(Application& application)
497   {
498     Stage::GetCurrent().KeyEventSignal().Connect(this, &ClusterController::OnKeyEvent);
499
500     Vector2 stageSize = Stage::GetCurrent().GetSize();
501
502     // The Init signal is received once (only) during the Application lifetime
503
504     // Hide the indicator bar
505     application.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
506
507     // Creates a default view with a default tool bar.
508     // The view is added to the stage.
509     mContentLayer = DemoHelper::CreateView( application,
510                                             mView,
511                                             mToolBar,
512                                             BACKGROUND_IMAGE,
513                                             TOOLBAR_IMAGE,
514                                             "" );
515
516     // Create a effect toggle button. (right of toolbar)
517     mLayoutButtonImages[ NO_EFFECT ] = Image::New( LAYOUT_NONE_IMAGE );
518     mLayoutButtonImages[ WOBBLE_EFFECT ] = Image::New( LAYOUT_WOBBLE_IMAGE );
519     mLayoutButtonImages[ CAROUSEL_EFFECT ] = Image::New( LAYOUT_CAROUSEL_IMAGE );
520     mLayoutButtonImages[ SPHERE_EFFECT ] = Image::New( LAYOUT_SPHERE_IMAGE );
521
522     mLayoutButton = Toolkit::PushButton::New();
523     mLayoutButton.ClickedSignal().Connect( this, &ClusterController::OnEffectTouched );
524     mToolBar.AddControl( mLayoutButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
525
526     // create and setup the scroll view...
527     mScrollView = ScrollView::New();
528     mScrollView.SetSize(stageSize);
529
530     // attach Wobble Effect to ScrollView
531     mScrollViewEffect = ScrollViewWobbleEffect::New();
532     mScrollView.ApplyEffect(mScrollViewEffect);
533
534     // anchor the scroll view from its center point to the middle of its parent
535     mScrollView.SetAnchorPoint(AnchorPoint::CENTER);
536     mScrollView.SetParentOrigin(ParentOrigin::CENTER);
537
538     // Scale ScrollView to fit within parent (mContentLayer)
539     Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
540                                                     LocalSource( Actor::SIZE ),
541                                                     ParentSource( Actor::SIZE ),
542                                                     ScaleToFitConstraint() );
543     mScrollView.ApplyConstraint(constraint);
544
545     // Add the scroll view to the content layer
546     mContentLayer.Add(mScrollView);
547
548     // Create the image border shared by all the cluster image actors
549     mClusterBorderImage = Image::New(CLUSTER_BORDER_IMAGE_PATH);
550
551     AddCluster( PEOPLE,   ClusterStyleStandard::New(ClusterStyleStandard::ClusterStyle1) );
552     AddCluster( TODAY,    ClusterStyleStandard::New(ClusterStyleStandard::ClusterStyle2) );
553     AddCluster( PHONE,    ClusterStyleStandard::New(ClusterStyleStandard::ClusterStyle3) );
554     AddCluster( PICTURES, ClusterStyleStandard::New(ClusterStyleStandard::ClusterStyle4) );
555     AddCluster( MUSIC,    ClusterStyleStandard::New(ClusterStyleStandard::ClusterStyle2) );
556     AddCluster( MAGAZINE, ClusterStyleStandard::New(ClusterStyleStandard::ClusterStyle3) );
557
558     SetEffect(WOBBLE_EFFECT);
559   }
560
561   /**
562    * Helper to create the cluster actors
563    */
564   Cluster CreateClusterActor(ClusterType clusterType, ClusterStyle style)
565   {
566     // Create the cluster actor with the given cluster style
567     Cluster clusterActor = Cluster::New(style);
568     clusterActor.SetParentOrigin(ParentOrigin::CENTER);
569     clusterActor.SetAnchorPoint(AnchorPoint::CENTER);
570
571     Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
572     float minStageDimension = std::min(stageSize.x, stageSize.y);
573     clusterActor.SetSize(minStageDimension * CLUSTER_RELATIVE_SIZE, minStageDimension * CLUSTER_RELATIVE_SIZE, 0.0f);
574
575     DALI_ASSERT_ALWAYS(clusterType < CLUSTER_COUNT);
576     const char **paths = IMAGE_GROUPS[clusterType];
577     DALI_ASSERT_ALWAYS(paths);
578
579     // Add a background image to the cluster
580     Image bg = Image::New( CLUSTER_BACKGROUND_IMAGE_PATH );
581     ImageActor image = ImageActor::New(bg);
582     clusterActor.SetBackgroundImage(image);
583
584     // Add actors (pictures) as the children of the cluster
585     for (unsigned int i = 0; (i < style.GetMaximumNumberOfChildren()) && (*paths); i++, paths++)
586     {
587       clusterActor.AddChild(CreateClusterPictureActor(clusterType, *paths), i);
588     }
589
590     return clusterActor;
591   }
592
593   /**
594    * Helper to create the picture actors in the cluster
595    */
596   Actor CreateClusterPictureActor(ClusterType clusterType, const std::string& imagePath)
597   {
598     // Create a picture for this cluster image
599     // actor|->shadow
600     //      |->image
601     //      |->border
602     Actor actor = Actor::New();
603     actor.SetSize(CLUSTER_IMAGE_THUMBNAIL_WIDTH, CLUSTER_IMAGE_THUMBNAIL_HEIGHT);
604     actor.SetParentOrigin( ParentOrigin::CENTER );
605     actor.SetAnchorPoint( AnchorPoint::CENTER );
606
607     // Load the thumbnail
608     ImageAttributes attribs = ImageAttributes::New();
609     attribs.SetSize(CLUSTER_IMAGE_THUMBNAIL_WIDTH, CLUSTER_IMAGE_THUMBNAIL_HEIGHT);
610     attribs.SetScalingMode(Dali::ImageAttributes::ShrinkToFit);
611     attribs.SetPixelFormat( Pixel::RGB888  );
612
613     // Add a shadow image child actor
614     Image shadowImage = Image::New( CLUSTER_SHADOW_IMAGE_PATH, attribs );
615     ImageActor shadowActor = ImageActor::New(shadowImage);
616
617     // Shadow is not exactly located on the center of the image, so it is moved to a little
618     // upper-left side of the image relatively using customised AnchorPoint.
619     shadowActor.SetParentOrigin(ShadowProperty::ANCHOR_POINT);
620     shadowActor.SetAnchorPoint(AnchorPoint::CENTER);
621     shadowActor.SetPosition(Vector3(0.0f, 0.0f, -1.0f));
622
623     // Apply size constraint to the image shadow
624     shadowActor.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), RelativeToConstraint( ShadowProperty::SIZE_SCALE ) ) );
625     actor.Add(shadowActor);
626
627     // Add a picture image actor to actor.
628     Image image = Image::New( imagePath, attribs );
629     ImageActor imageActor = ImageActor::New(image);
630     imageActor.SetParentOrigin( ParentOrigin::CENTER );
631     imageActor.SetAnchorPoint( AnchorPoint::CENTER );
632     imageActor.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
633     actor.Add(imageActor);
634
635     // Add a border image child actor
636     ImageActor borderActor = ImageActor::New(mClusterBorderImage);
637     borderActor.SetParentOrigin( ParentOrigin::CENTER );
638     borderActor.SetAnchorPoint( AnchorPoint::CENTER );
639     borderActor.SetStyle( ImageActor::STYLE_NINE_PATCH );
640     borderActor.SetNinePatchBorder( CLUSTER_IMAGE_BORDER_ABSOLUTE );
641     borderActor.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
642
643     // Apply size constraint to the image border
644     Constraint constraint = Constraint::New<Vector3>(Actor::SIZE,
645                                                      ParentSource(Actor::SIZE),
646                                                      ClusterImageBorderSizeConstraint());
647     borderActor.ApplyConstraint(constraint);
648     actor.Add(borderActor);
649
650     return actor;
651   }
652
653
654   /**
655    * Adds a Cluster to the ScrollView
656    *
657    * @param[in] clusterType The type of cluster (determines the image content)
658    * @param[in] style The style to be used for this cluster.
659    */
660   void AddCluster(ClusterType clusterType, ClusterStyle style)
661   {
662     Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
663
664     int column = mClusterCount>>1;
665     int row = mClusterCount&1;
666
667     float minStageDimension = std::min(stageSize.x, stageSize.y);
668     float clusterRightShift = 1.0f - CLUSTER_COLUMN_INDENT * 2.0f;
669     Vector3 clusterPosition = Vector3(CLUSTER_COLUMN_INDENT * stageSize.width + row * (clusterRightShift * stageSize.width - minStageDimension * CLUSTER_RELATIVE_SIZE),
670                                       CLUSTER_ROW_INDENT * stageSize.height + row * (clusterRightShift * stageSize.height - minStageDimension * CLUSTER_RELATIVE_SIZE), 0.0f);
671
672     Actor pageView = Actor::New();
673     mScrollView.Add(pageView);
674     pageView.SetParentOrigin(ParentOrigin::CENTER);
675     pageView.SetPosition(Vector3(stageSize.width * column, 0.0f, 0.0f));
676     pageView.SetSize(stageSize);
677
678     // Resize pageView (which contains a Cluster)
679     Constraint constraintScale = Constraint::New<Vector3>( Actor::SCALE,
680                                                            ParentSource( Actor::SCALE ),
681                                                            RescaleConstraint() );
682     constraintScale.SetRemoveAction(Constraint::Discard);
683     pageView.ApplyConstraint(constraintScale);
684
685     // Create cluster actors, add them to scroll view, and set the shear effect with the given center point.
686     Cluster cluster = CreateClusterActor(clusterType, style);
687     cluster.SetParentOrigin(ParentOrigin::TOP_LEFT);
688     cluster.SetAnchorPoint(AnchorPoint::TOP_LEFT);
689     cluster.SetPosition( clusterPosition );
690
691     pageView.Add(cluster);
692     Vector3 clusterSize = cluster.GetCurrentSize();
693
694     mClusterInfo.push_back(ClusterInfo( cluster, mClusterCount, clusterPosition, clusterSize ));
695
696     mClusterCount++;
697   }
698
699   /**
700    * Resets ScrollView and Clusters settings
701    * to reflect the new ExampleEffectType
702    *
703    * TODO: Add animation transition to fade out of existing effect,
704    * and into new effect.
705    *
706    * @param[in] type The desired effect to switch to.
707    */
708   void SetEffect(ExampleEffectType type)
709   {
710     Vector2 stageSize(Dali::Stage::GetCurrent().GetSize());
711
712     mExampleEffect = type;
713
714     std::stringstream ss(APPLICATION_TITLE);
715     ss << APPLICATION_TITLE << ": " << EXAMPLE_EFFECT_LABEL[mExampleEffect];
716     SetTitle(ss.str());
717
718     // Set up default ruler settings (fixed in horizontal, disabled in vertical)
719     RulerPtr rulerX;
720     rulerX = new FixedRuler(stageSize.x);
721     int columns = (mClusterCount + 1) >> 1;
722     rulerX->SetDomain(RulerDomain(0.0f, stageSize.x * columns, true));
723     mScrollView.SetRulerX(rulerX);
724
725     RulerPtr rulerY = new DefaultRuler();
726     rulerY->Disable();
727     mScrollView.SetRulerY(rulerY);
728
729     mScrollView.SetActorAutoSnap(false);
730
731     // Remove all shader-effects from mScrollView and it's children (the clusters)
732     mScrollView.SetPosition(Vector3::ZERO);
733
734     mLayoutButton.SetBackgroundImage( mLayoutButtonImages[ type ] );
735
736     for( std::vector<ClusterInfo>::iterator i = mClusterInfo.begin(); i != mClusterInfo.end(); ++i )
737     {
738       Cluster cluster = i->mCluster;
739       RemoveShaderEffectRecursively( cluster );
740       if( i->mEffectConstraint )
741       {
742         cluster.RemoveConstraint(i->mEffectConstraint);
743         i->mEffectConstraint.Reset();
744       }
745     }
746
747     // Apply new shader-effects.
748     // Move Y to origin incase we came from an effect where user could free pan in y axis.
749     const Vector3 currentScrollPosition(mScrollView.GetCurrentScrollPosition());
750     mScrollView.ScrollTo(Vector3(currentScrollPosition.x, 0.0f, 0.0f));
751
752     switch(type)
753     {
754       case NO_EFFECT:
755       {
756         break;
757       }
758
759       case WOBBLE_EFFECT:
760       {
761         for( std::vector<ClusterInfo>::iterator i = mClusterInfo.begin(); i != mClusterInfo.end(); ++i )
762         {
763           Cluster cluster = i->mCluster;
764           Vector3 position = i->mPosition;
765           Vector3 size = i->mSize;
766
767           ShearEffect shaderEffect = ShearEffect::New();
768           Vector3 shearAnchor = SHEAR_EFFECT_ANCHOR_POINT;
769
770           Vector2 shearCenter( Vector2(position.x + size.width * shearAnchor.x, position.y + size.height * shearAnchor.y) );
771           Property::Index centerProperty = shaderEffect.GetPropertyIndex(shaderEffect.GetCenterPropertyName());
772           Constraint constraint = Constraint::New<Vector2>( centerProperty,
773                                                             Source(mView, Actor::SIZE),
774                                                             ShearEffectCenterConstraint(stageSize, shearCenter) );
775           shaderEffect.ApplyConstraint(constraint);
776
777           SetShaderEffectRecursively( cluster,shaderEffect );
778
779           // Apply Constraint to Shader Effect
780           Property::Index scrollOvershootProperty = /*targetGroup*/mScrollView.GetPropertyIndex(ScrollViewWobbleEffect::EFFECT_OVERSHOOT);
781           Property::Index angleXAxisProperty = shaderEffect.GetPropertyIndex(shaderEffect.GetAngleXAxisPropertyName());
782           Property::Index angleYAxisProperty = shaderEffect.GetPropertyIndex(shaderEffect.GetAngleYAxisPropertyName());
783
784           constraint = Constraint::New<float>( angleXAxisProperty,
785                                                Source(mScrollView, scrollOvershootProperty),
786                                                Source(mView, Actor::ROTATION),
787                                                ShearEffectConstraint(stageSize, SHEAR_EFFECT_MAX_OVERSHOOT, Vector2::XAXIS) );
788           shaderEffect.ApplyConstraint(constraint);
789           constraint = Constraint::New<float>( angleYAxisProperty,
790                                                Source(mScrollView, scrollOvershootProperty),
791                                                Source(mView, Actor::ROTATION),
792                                                ShearEffectConstraint(stageSize, SHEAR_EFFECT_MAX_OVERSHOOT, Vector2::YAXIS) );
793           shaderEffect.ApplyConstraint(constraint);
794
795
796         }
797         break;
798       }
799
800       case CAROUSEL_EFFECT:
801       {
802         // Apply Carousel Shader Effect to scrollView
803         CarouselEffect shaderEffect = CarouselEffect::New();
804         shaderEffect.SetRadius( -CAROUSEL_EFFECT_RADIUS );
805         // dont apply shader effect to scrollview as it might override internal shaders for bounce effect etc
806         for( std::vector<ClusterInfo>::iterator i = mClusterInfo.begin(); i != mClusterInfo.end(); ++i )
807         {
808           Cluster cluster = i->mCluster;
809           SetShaderEffectRecursively( cluster, shaderEffect );
810         }
811         mScrollView.SetPosition( Vector3( 0.0f, 0.0f, CAROUSEL_EFFECT_RADIUS ) );
812
813         const Vector2 angleSweep( CAROUSEL_EFFECT_ANGLE_SWEEP / stageSize.width,
814                                   CAROUSEL_EFFECT_ANGLE_SWEEP / stageSize.width );
815
816         Property::Index anglePerUnit = shaderEffect.GetPropertyIndex( shaderEffect.GetAnglePerUnitPropertyName() );
817         shaderEffect.ApplyConstraint( Constraint::New<Vector2>( anglePerUnit,
818                                                                 Source(mView, Actor::ROTATION),
819                                                                 CarouselEffectOrientationConstraint( angleSweep ) ) );
820
821         break;
822       }
823
824       case SPHERE_EFFECT:
825       {
826         // Change ruler to free panning...
827         RulerPtr rulerX;
828         rulerX = new DefaultRuler();
829         int columns = (mClusterCount + 1) >> 1;
830         rulerX->SetDomain(RulerDomain(0.0f, stageSize.x * columns, true));
831         mScrollView.SetRulerX(rulerX);
832
833         RulerPtr rulerY = new DefaultRuler();
834         rulerY->SetDomain(RulerDomain( -stageSize.y * SPHERE_EFFECT_VERTICAL_DOMAIN, stageSize.y * (1.0f + SPHERE_EFFECT_VERTICAL_DOMAIN), true));
835         mScrollView.SetRulerY(rulerY);
836
837         // Apply Carousel Shader Effect to scrollView (Spherical style)
838         CarouselEffect shaderEffect = CarouselEffect::New();
839
840         shaderEffect.SetRadius( SPHERE_EFFECT_RADIUS );
841         shaderEffect.SetAnglePerUnit( Vector2( SPHERE_EFFECT_ANGLE_SWEEP / stageSize.y, SPHERE_EFFECT_ANGLE_SWEEP / stageSize.y ) );
842         // dont apply shader effect to scrollview as it might override internal shaders for bounce effect etc
843         for( std::vector<ClusterInfo>::iterator i = mClusterInfo.begin(); i != mClusterInfo.end(); ++i )
844         {
845           Constraint constraint = Constraint::New<float>(Actor::POSITION_Z, SphereEffectOffsetConstraint(SPHERE_EFFECT_POSITION_Z));
846           constraint.SetRemoveAction(Constraint::Discard);
847           Cluster cluster = i->mCluster;
848           SetShaderEffectRecursively( cluster, shaderEffect );
849           i->mEffectConstraint = cluster.ApplyConstraint(constraint);
850         }
851         break;
852       }
853
854       default:
855         break;
856     }
857
858   }
859
860   /**
861    * Signal handler, called when quit button is pressed
862    */
863   bool OnEffectTouched( Toolkit::Button button )
864   {
865     // quit the application
866     SetEffect(static_cast<ExampleEffectType>( (mExampleEffect + 1) % TOTAL_EFFECTS) );
867     return true;
868   }
869
870   /**
871    * Sets/Updates the title of the View
872    * @param[in] title The new title for the view.
873    */
874   void SetTitle(const std::string& title)
875   {
876     if(!mTitleActor)
877     {
878       mTitleActor = TextView::New();
879       // Add title to the tool bar.
880       mToolBar.AddControl( mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HorizontalCenter );
881     }
882
883     Font font = Font::New();
884     mTitleActor.SetText( title );
885     mTitleActor.SetSize( font.MeasureText( title ) );
886     mTitleActor.SetStyleToCurrentText(DemoHelper::GetDefaultTextStyle());
887   }
888
889   /**
890    * Main key event handler
891    */
892   void OnKeyEvent(const KeyEvent& event)
893   {
894     if(event.state == KeyEvent::Down)
895     {
896       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
897       {
898         mApplication.Quit();
899       }
900     }
901   }
902
903 private:
904
905   Application&               mApplication;                       ///< Application instance
906   Toolkit::View              mView;                              ///< The View instance.
907   Toolkit::ToolBar           mToolBar;                           ///< The View's Toolbar.
908   TextView                   mTitleActor;                        ///< The Toolbar's Title.
909
910   Layer                      mContentLayer;                      ///< Content layer (scrolling cluster content)
911
912   ScrollView                 mScrollView;                        ///< The ScrollView container for all clusters
913   ScrollViewWobbleEffect     mScrollViewEffect;                  ///< ScrollView Wobble effect
914   Image                      mClusterBorderImage;                ///< The border frame that appears on each image
915
916   std::vector<ClusterInfo>   mClusterInfo;                       ///< Keeps track of each cluster's information.
917   int                        mClusterCount;                      ///< Current number of clusters in use
918   ExampleEffectType          mExampleEffect;                     ///< Current example effect.
919
920   Toolkit::PushButton        mLayoutButton;                      ///< The layout button
921   Image                      mLayoutButtonImages[TOTAL_EFFECTS]; ///< Image when no layout
922 };
923
924 void RunTest(Application& app)
925 {
926   ClusterController test(app);
927
928   app.MainLoop();
929 }
930
931 // Entry point for Linux & SLP applications
932 //
933 int main(int argc, char **argv)
934 {
935   Application app = Application::New(&argc, &argv);
936
937   RunTest(app);
938
939   return 0;
940 }