Fixed dali-demo bubbles non-linear movement and stopping
[platform/core/uifw/dali-demo.git] / demo / dali-table-view.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 // CLASS HEADER
19 #include "dali-table-view.h"
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23 #include <sstream>
24 #include <unistd.h>
25 #include <dali/devel-api/images/distance-field.h>
26 #include <dali-toolkit/devel-api/shader-effects/alpha-discard-effect.h>
27 #include <dali-toolkit/devel-api/shader-effects/distance-field-effect.h>
28
29 // INTERNAL INCLUDES
30 #include "shared/view.h"
31
32 using namespace Dali;
33 using namespace Dali::Toolkit;
34
35 ///////////////////////////////////////////////////////////////////////////////
36
37 namespace
38 {
39
40 const std::string LOGO_PATH( DEMO_IMAGE_DIR "Logo-for-demo.png" );
41 const std::string DEFAULT_TOOLBAR_IMAGE_PATH( DEMO_IMAGE_DIR "top-bar.png" );
42 const std::string TILE_BACKGROUND(DEMO_IMAGE_DIR "item-background.9.png");
43 const std::string TILE_BACKGROUND_ALPHA(DEMO_IMAGE_DIR "item-background-alpha.9.png");
44
45 const char * const DEFAULT_TOOLBAR_TEXT( "TOUCH TO LAUNCH EXAMPLE" );
46
47 const float BUTTON_PRESS_ANIMATION_TIME = 0.25f;                ///< Time to perform button scale effect.
48 const float ROTATE_ANIMATION_TIME = 0.5f;                       ///< Time to perform rotate effect.
49 const int MAX_PAGES = 256;                                      ///< Maximum pages (arbitrary safety limit)
50 const int EXAMPLES_PER_ROW = 3;
51 const int ROWS_PER_PAGE = 3;
52 const int EXAMPLES_PER_PAGE = EXAMPLES_PER_ROW * ROWS_PER_PAGE;
53 const float LOGO_MARGIN_RATIO = 0.1f / 0.3f;
54 const float BOTTOM_PADDING_RATIO = 0.4f / 0.9f;
55 const Vector3 SCROLLVIEW_RELATIVE_SIZE(0.9f, 1.0f, 0.8f );     ///< ScrollView's relative size to its parent
56 const Vector3 TABLE_RELATIVE_SIZE(0.95f, 0.9f, 0.8f );          ///< TableView's relative size to the entire stage. The Y value means sum of the logo and table relative heights.
57 const float STENCIL_RELATIVE_SIZE = 1.0f;
58
59 const float EFFECT_SNAP_DURATION = 0.66f;                       ///< Scroll Snap Duration for Effects
60 const float EFFECT_FLICK_DURATION = 0.5f;                       ///< Scroll Flick Duration for Effects
61 const Vector3 ANGLE_CUBE_PAGE_ROTATE(Math::PI * 0.5f, Math::PI * 0.5f, 0.0f);
62
63 const Vector4 BUBBLE_COLOR[] =
64 {
65   Vector4( 0.3255f, 0.3412f, 0.6353f, 0.38f ),
66   Vector4( 0.3647f, 0.7569f, 0.8157f, 0.38f ),
67   Vector4( 0.3804f, 0.7412f, 0.6510f, 0.38f ),
68   Vector4( 1.f, 1.f, 1.f, 0.2f )
69 };
70 const int NUMBER_OF_BUBBLE_COLOR( sizeof(BUBBLE_COLOR) / sizeof(BUBBLE_COLOR[0]) );
71
72 const int NUM_BACKGROUND_IMAGES = 18;
73 const float BACKGROUND_SWIPE_SCALE = 0.025f;
74 const float BACKGROUND_SPREAD_SCALE = 1.5f;
75 const float SCALE_MOD = 1000.0f * Math::PI * 2.0f;
76 const float SCALE_SPEED = 10.0f;
77 const float SCALE_SPEED_SIN = 0.1f;
78
79 const unsigned int BACKGROUND_ANIMATION_DURATION = 15000; // 15 secs
80
81 const Vector4 BACKGROUND_COLOR( 0.3569f, 0.5451f, 0.7294f, 1.0f );
82
83 const float BUBBLE_MIN_Z = -1.0;
84 const float BUBBLE_MAX_Z = 0.0f;
85
86 /**
87  * Creates the background image
88  */
89 Control CreateBackground( std::string stylename )
90 {
91   Control background = Control::New();
92   Stage::GetCurrent().Add( background );
93   background.SetProperty( Control::Property::STYLE_NAME,stylename);
94   background.SetName( "BACKGROUND" );
95   background.SetAnchorPoint( AnchorPoint::CENTER );
96   background.SetParentOrigin( ParentOrigin::CENTER );
97   background.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
98
99   return background;
100 }
101
102 /**
103  * Constraint to return a position for a bubble based on the scroll value and vertical wrapping
104  */
105 struct AnimateBubbleConstraint
106 {
107 public:
108   AnimateBubbleConstraint( const Vector3& initialPos, float scale )
109   : mInitialX( initialPos.x ),
110     mScale( scale )
111   {
112   }
113
114   void operator()( Vector3& position, const PropertyInputContainer& inputs )
115   {
116     const Vector3& parentSize = inputs[1]->GetVector3();
117     const Vector3& childSize = inputs[2]->GetVector3();
118
119     // Wrap bubbles vertically.
120     float range = parentSize.y + childSize.y;
121     // This performs a float mod (we don't use fmod as we want the arithmetic modulus as opposed to the remainder).
122     position.y -= range * ( floor( position.y / range ) + 0.5f );
123
124     // Bubbles X position moves parallax to horizontal
125     // panning by a scale factor unique to each bubble.
126     position.x = mInitialX + ( inputs[0]->GetVector2().x * mScale );
127   }
128
129 private:
130   float mInitialX;
131   float mScale;
132 };
133
134 bool CompareByTitle( const Example& lhs, const Example& rhs )
135 {
136   return lhs.title < rhs.title;
137 }
138
139 } // namespace
140
141 DaliTableView::DaliTableView( Application& application )
142 : mApplication( application ),
143   mBackgroundLayer(),
144   mRootActor(),
145   mRotateAnimation(),
146   mPressedAnimation(),
147   mScrollViewLayer(),
148   mScrollView(),
149   mScrollViewEffect(),
150   mScrollRulerX(),
151   mScrollRulerY(),
152   mPressedActor(),
153   mAnimationTimer(),
154   mLogoTapDetector(),
155   mVersionPopup(),
156   mPages(),
157   mBackgroundAnimations(),
158   mExampleList(),
159   mTotalPages(),
160   mScrolling( false ),
161   mSortAlphabetically( false ),
162   mBackgroundAnimsPlaying( false )
163 {
164   application.InitSignal().Connect( this, &DaliTableView::Initialize );
165 }
166
167 DaliTableView::~DaliTableView()
168 {
169 }
170
171 void DaliTableView::AddExample( Example example )
172 {
173   mExampleList.push_back( example );
174 }
175
176 void DaliTableView::SortAlphabetically( bool sortAlphabetically )
177 {
178   mSortAlphabetically = sortAlphabetically;
179 }
180
181 void DaliTableView::Initialize( Application& application )
182 {
183   Stage::GetCurrent().KeyEventSignal().Connect( this, &DaliTableView::OnKeyEvent );
184
185   const Vector2 stageSize = Stage::GetCurrent().GetSize();
186
187   // Background
188   Control background = CreateBackground( "launcherbackground" );
189   Stage::GetCurrent().Add( background );
190
191   // Add root actor
192   mRootActor = TableView::New( 4, 1 );
193   mRootActor.SetAnchorPoint( AnchorPoint::CENTER );
194   mRootActor.SetParentOrigin( ParentOrigin::CENTER );
195   mRootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
196   Stage::GetCurrent().Add( mRootActor );
197
198   // Toolbar at top
199   Dali::Toolkit::ToolBar toolbar;
200   Dali::Layer toolBarLayer = DemoHelper::CreateToolbar(toolbar,
201                                                        DEFAULT_TOOLBAR_IMAGE_PATH,
202                                                        DEFAULT_TOOLBAR_TEXT,
203                                                        DemoHelper::DEFAULT_VIEW_STYLE);
204
205   mRootActor.AddChild( toolBarLayer, TableView::CellPosition( 0, 0 ) );
206   mRootActor.SetFitHeight( 0 );
207
208   // Add logo
209   ImageView logo = CreateLogo( LOGO_PATH );
210   logo.SetName( "LOGO_IMAGE" );
211   logo.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
212   const float paddingHeight = ( ( 1.f-TABLE_RELATIVE_SIZE.y ) * stageSize.y );
213   const float logoMargin = paddingHeight * LOGO_MARGIN_RATIO;
214
215   // Show version in a popup when log is tapped
216   mLogoTapDetector = TapGestureDetector::New();
217   mLogoTapDetector.Attach( logo );
218   mLogoTapDetector.DetectedSignal().Connect( this, &DaliTableView::OnLogoTapped );
219
220   const float bottomMargin = paddingHeight * BOTTOM_PADDING_RATIO;
221
222   Alignment alignment = Alignment::New();
223   alignment.SetName( "LOGO_ALIGNMENT" );
224   alignment.Add( logo );
225   alignment.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
226   alignment.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
227   Actor alignmentActor = alignment;
228   alignmentActor.SetPadding( Padding( 0.0f, 0.0f, logoMargin, logoMargin ));
229   mRootActor.AddChild( alignment, TableView::CellPosition( 1, 0 ) );
230   mRootActor.SetFitHeight( 1 );
231
232   // scrollview occupying the majority of the screen
233   mScrollView = ScrollView::New();
234
235   mScrollView.SetAnchorPoint( AnchorPoint::CENTER );
236   mScrollView.SetParentOrigin( ParentOrigin::CENTER );
237   mScrollView.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
238   const float buttonsPageMargin = ( 1.0f - TABLE_RELATIVE_SIZE.x ) * 0.5f * stageSize.width;
239   mScrollView.SetPadding( Padding( buttonsPageMargin, buttonsPageMargin, 0.0f, 0.0f ) );
240
241   mScrollView.SetAxisAutoLock( true );
242   mScrollView.ScrollCompletedSignal().Connect( this, &DaliTableView::OnScrollComplete );
243   mScrollView.ScrollStartedSignal().Connect( this, &DaliTableView::OnScrollStart );
244   mScrollView.TouchedSignal().Connect( this, &DaliTableView::OnScrollTouched );
245
246   mScrollViewLayer = Layer::New();
247
248   // Disable the depth test for performance
249   mScrollViewLayer.SetDepthTestDisabled( true );
250   mScrollViewLayer.SetAnchorPoint( AnchorPoint::CENTER );
251   mScrollViewLayer.SetParentOrigin( ParentOrigin::CENTER );
252   mScrollViewLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
253
254   // Create solid background colour.
255   Control backgroundColourActor = Control::New();
256   backgroundColourActor.SetBackgroundColor( BACKGROUND_COLOR );
257   backgroundColourActor.SetAnchorPoint( AnchorPoint::CENTER );
258   backgroundColourActor.SetParentOrigin( ParentOrigin::CENTER );
259   backgroundColourActor.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
260   backgroundColourActor.SetSizeModeFactor( Vector3( 1.0f, 1.5f, 1.0f ) );
261
262   mScrollViewLayer.Add( backgroundColourActor );
263
264   // Populate background and bubbles - needs to be scrollViewLayer so scroll ends show
265   Actor bubbleContainer = Actor::New();
266   bubbleContainer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
267   bubbleContainer.SetAnchorPoint( AnchorPoint::CENTER );
268   bubbleContainer.SetParentOrigin( ParentOrigin::CENTER );
269   backgroundColourActor.Add( bubbleContainer );
270
271   SetupBackground( bubbleContainer );
272
273   Alignment buttonsAlignment = Alignment::New();
274   buttonsAlignment.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
275   buttonsAlignment.Add( mScrollViewLayer );
276
277   mScrollViewLayer.Add( mScrollView );
278
279   mRootActor.AddChild( buttonsAlignment, TableView::CellPosition( 2, 0 ) );
280
281   mRootActor.SetFixedHeight( 3, bottomMargin );
282
283   // Add scroll view effect and setup constraints on pages
284   ApplyScrollViewEffect();
285
286   // Add pages and tiles
287   Populate();
288
289   // Remove constraints for inner cube effect
290   ApplyCubeEffectToPages();
291
292   Dali::Window winHandle = application.GetWindow();
293   winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT );
294   winHandle.RemoveAvailableOrientation( Dali::Window::LANDSCAPE );
295   winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT_INVERSE );
296   winHandle.RemoveAvailableOrientation( Dali::Window::LANDSCAPE_INVERSE );
297
298   // Set initial orientation
299   unsigned int degrees = 0;
300   Rotate( degrees );
301
302   //orientation.ChangedSignal().Connect( this, &DaliTableView::OrientationChanged );
303
304   winHandle.ShowIndicator( Dali::Window::INVISIBLE );
305
306   // Background animation
307   mAnimationTimer = Timer::New( BACKGROUND_ANIMATION_DURATION );
308   mAnimationTimer.TickSignal().Connect( this, &DaliTableView::PauseBackgroundAnimation );
309   mAnimationTimer.Start();
310   mBackgroundAnimsPlaying = true;
311
312   KeyboardFocusManager::Get().PreFocusChangeSignal().Connect( this, &DaliTableView::OnKeyboardPreFocusChange );
313   KeyboardFocusManager::Get().FocusedActorEnterKeySignal().Connect( this, &DaliTableView::OnFocusedActorActivated );
314   AccessibilityManager::Get().FocusedActorActivatedSignal().Connect( this, &DaliTableView::OnFocusedActorActivated );
315 }
316
317 void DaliTableView::ApplyCubeEffectToPages()
318 {
319   ScrollViewPagePathEffect effect = ScrollViewPagePathEffect::DownCast( mScrollViewEffect );
320   unsigned int pageCount(0);
321   for( std::vector< Actor >::iterator pageIter = mPages.begin(); pageIter != mPages.end(); ++pageIter )
322   {
323     Actor page = *pageIter;
324     effect.ApplyToPage( page, pageCount++ );
325   }
326 }
327
328 void DaliTableView::OnButtonsPageRelayout( const Dali::Actor& actor )
329 {
330
331 }
332
333 void DaliTableView::Populate()
334 {
335   const Vector2 stageSize = Stage::GetCurrent().GetSize();
336
337   mTotalPages = ( mExampleList.size() + EXAMPLES_PER_PAGE - 1 ) / EXAMPLES_PER_PAGE;
338
339   // Populate ScrollView.
340   if( mExampleList.size() > 0 )
341   {
342     if( mSortAlphabetically )
343     {
344       sort( mExampleList.begin(), mExampleList.end(), CompareByTitle );
345     }
346
347     unsigned int exampleCount = 0;
348     ExampleListConstIter iter = mExampleList.begin();
349
350     for( int t = 0; t < mTotalPages; t++ )
351     {
352       // Create Table
353       TableView page = TableView::New( ROWS_PER_PAGE, EXAMPLES_PER_ROW );
354       page.SetAnchorPoint( AnchorPoint::CENTER );
355       page.SetParentOrigin( ParentOrigin::CENTER );
356       page.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
357       mScrollView.Add( page );
358
359       // Calculate the number of images going across (columns) within a page, according to the screen resolution and dpi.
360       const float margin = 2.0f;
361       const float tileParentMultiplier = 1.0f / EXAMPLES_PER_ROW;
362
363       for(int row = 0; row < ROWS_PER_PAGE; row++)
364       {
365         for(int column = 0; column < EXAMPLES_PER_ROW; column++)
366         {
367           const Example& example = ( *iter );
368
369           Actor tile = CreateTile( example.name, example.title, Vector3( tileParentMultiplier, tileParentMultiplier, 1.0f ), true );
370           AccessibilityManager accessibilityManager = AccessibilityManager::Get();
371           accessibilityManager.SetFocusOrder( tile, ++exampleCount );
372           accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_LABEL,
373                                                   example.title );
374           accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_TRAIT, "Tile" );
375           accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_HINT,
376                                                   "You can run this example" );
377
378           tile.SetPadding( Padding( margin, margin, margin, margin ) );
379
380           page.AddChild( tile, TableView::CellPosition( row, column ) );
381
382           iter++;
383
384           if( iter == mExampleList.end() )
385           {
386             break;
387           }
388         }
389
390         if( iter == mExampleList.end() )
391         {
392           break;
393         }
394       }
395
396       // Set tableview position
397       Vector3 pagePos( stageSize.width * TABLE_RELATIVE_SIZE.x * t, 0.0f, 0.0f );
398       page.SetPosition( pagePos );
399
400       mPages.push_back( page );
401
402       if( iter == mExampleList.end() )
403       {
404         break;
405       }
406     }
407   }
408
409   // Update Ruler info.
410   mScrollRulerX = new FixedRuler( stageSize.width * TABLE_RELATIVE_SIZE.x * 0.5f );
411   mScrollRulerY = new DefaultRuler();
412   mScrollRulerX->SetDomain( RulerDomain( 0.0f, (mTotalPages+1) * stageSize.width * TABLE_RELATIVE_SIZE.x * 0.5f, true ) );
413   mScrollRulerY->Disable();
414   mScrollView.SetRulerX( mScrollRulerX );
415   mScrollView.SetRulerY( mScrollRulerY );
416 }
417
418 void DaliTableView::OrientationChanged( Orientation orientation )
419 {
420   // TODO: Implement if orientation change required
421 }
422
423 void DaliTableView::Rotate( unsigned int degrees )
424 {
425   // Resize the root actor
426   Vector2 stageSize = Stage::GetCurrent().GetSize();
427   Vector3 targetSize( stageSize.x, stageSize.y, 1.0f );
428
429   if( degrees == 90 || degrees == 270 )
430   {
431     targetSize = Vector3( stageSize.y, stageSize.x, 1.0f );
432   }
433
434   if( mRotateAnimation )
435   {
436     mRotateAnimation.Stop();
437     mRotateAnimation.Clear();
438   }
439
440   mRotateAnimation = Animation::New( ROTATE_ANIMATION_TIME );
441   mRotateAnimation.AnimateTo( Property( mRootActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( 360 - degrees ) ), Vector3::ZAXIS ), AlphaFunction::EASE_OUT );
442   mRotateAnimation.AnimateTo( Property( mRootActor, Actor::Property::SIZE ), targetSize, AlphaFunction::EASE_OUT );
443   mRotateAnimation.Play();
444 }
445
446 Actor DaliTableView::CreateTile( const std::string& name, const std::string& title, const Dali::Vector3& sizeMultiplier, bool addBackground )
447 {
448   Actor content = Actor::New();
449   content.SetName( name );
450   content.SetAnchorPoint( AnchorPoint::CENTER );
451   content.SetParentOrigin( ParentOrigin::CENTER );
452   content.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
453   content.SetSizeModeFactor( sizeMultiplier );
454
455   // create background image
456   if( addBackground )
457   {
458     ImageView image = ImageView::New( TILE_BACKGROUND );
459     image.SetAnchorPoint( AnchorPoint::CENTER );
460     image.SetParentOrigin( ParentOrigin::CENTER );
461     // make the image 100% of tile
462     image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
463
464     content.Add( image );
465
466     // Add stencil
467     Toolkit::ImageView stencil = NewStencilImage();
468     stencil.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
469     image.Add( stencil );
470   }
471
472   TextLabel label = TextLabel::New();
473   label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
474   label.SetProperty( Control::Property::STYLE_NAME, "launcherlabel" );
475   label.SetProperty( TextLabel::Property::MULTI_LINE, true );
476   label.SetProperty( TextLabel::Property::TEXT, title );
477   label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
478   label.SetProperty( TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
479   label.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
480   content.Add( label );
481
482   // Set the tile to be keyboard focusable
483   content.SetKeyboardFocusable(true);
484
485   // connect to the touch events
486   content.TouchedSignal().Connect( this, &DaliTableView::OnTilePressed );
487   content.HoveredSignal().Connect( this, &DaliTableView::OnTileHovered );
488
489   return content;
490 }
491
492 Toolkit::ImageView DaliTableView::NewStencilImage()
493 {
494   Toolkit::ImageView stencil = ImageView::New( TILE_BACKGROUND_ALPHA );
495
496   stencil.SetParentOrigin( ParentOrigin::CENTER );
497   stencil.SetAnchorPoint( AnchorPoint::CENTER );
498   stencil.SetDrawMode( DrawMode::STENCIL );
499
500   Property::Map shaderEffect = CreateAlphaDiscardEffect();
501   stencil.SetProperty( Toolkit::ImageView::Property::IMAGE, shaderEffect );
502
503   return stencil;
504 }
505
506 bool DaliTableView::OnTilePressed( Actor actor, const TouchEvent& event )
507 {
508   bool consumed = false;
509
510   const TouchPoint& point = event.GetPoint( 0 );
511   if( TouchPoint::Down == point.state )
512   {
513     mPressedActor = actor;
514     consumed = true;
515   }
516
517   // A button press is only valid if the Down & Up events
518   // both occurred within the button.
519   if( ( TouchPoint::Up == point.state ) &&
520       ( mPressedActor == actor ) )
521   {
522     // ignore Example button presses when scrolling or button animating.
523     if( ( !mScrolling ) && ( !mPressedAnimation ) )
524     {
525       std::string name = actor.GetName();
526       const ExampleListIter end = mExampleList.end();
527       for( ExampleListIter iter = mExampleList.begin(); iter != end; ++iter )
528       {
529         if( (*iter).name == name )
530         {
531           // do nothing, until pressed animation finished.
532           consumed = true;
533           break;
534         }
535       }
536     }
537
538     if( consumed )
539     {
540       mPressedAnimation = Animation::New( BUTTON_PRESS_ANIMATION_TIME );
541       mPressedAnimation.SetEndAction( Animation::Discard );
542
543       // scale the content actor within the Tile, as to not affect the placement within the Table.
544       Actor content = actor.GetChildAt(0);
545       mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3( 0.9f, 0.9f, 1.0f ), AlphaFunction::EASE_IN_OUT,
546                                  TimePeriod( 0.0f, BUTTON_PRESS_ANIMATION_TIME * 0.5f ) );
547       mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT,
548                                  TimePeriod( BUTTON_PRESS_ANIMATION_TIME * 0.5f, BUTTON_PRESS_ANIMATION_TIME * 0.5f ) );
549       mPressedAnimation.Play();
550       mPressedAnimation.FinishedSignal().Connect( this, &DaliTableView::OnPressedAnimationFinished );
551     }
552   }
553   return consumed;
554 }
555
556 void DaliTableView::OnPressedAnimationFinished( Dali::Animation& source )
557 {
558   mPressedAnimation.Reset();
559   if( mPressedActor )
560   {
561     std::string name = mPressedActor.GetName();
562
563     std::stringstream stream;
564     stream << DEMO_EXAMPLE_BIN << name.c_str();
565     pid_t pid = fork();
566     if( pid == 0)
567     {
568       execlp( stream.str().c_str(), name.c_str(), NULL );
569       DALI_ASSERT_ALWAYS(false && "exec failed!");
570     }
571     mPressedActor.Reset();
572   }
573 }
574
575 void DaliTableView::OnScrollStart( const Dali::Vector2& position )
576 {
577   mScrolling = true;
578
579   PlayAnimation();
580 }
581
582 void DaliTableView::OnScrollComplete( const Dali::Vector2& position )
583 {
584   mScrolling = false;
585
586   // move focus to 1st item of new page
587   AccessibilityManager accessibilityManager = AccessibilityManager::Get();
588   accessibilityManager.SetCurrentFocusActor(mPages[mScrollView.GetCurrentPage()].GetChildAt(0) );
589 }
590
591 bool DaliTableView::OnScrollTouched( Actor actor, const TouchEvent& event )
592 {
593   const TouchPoint& point = event.GetPoint( 0 );
594   if( TouchPoint::Down == point.state )
595   {
596     mPressedActor = actor;
597   }
598
599   return false;
600 }
601
602 void DaliTableView::ApplyScrollViewEffect()
603 {
604   // Remove old effect if exists.
605
606   if( mScrollViewEffect )
607   {
608     mScrollView.RemoveEffect( mScrollViewEffect );
609   }
610
611   // Just one effect for now
612   SetupInnerPageCubeEffect();
613
614   mScrollView.ApplyEffect( mScrollViewEffect );
615 }
616
617 void DaliTableView::SetupInnerPageCubeEffect()
618 {
619   const Vector2 stageSize = Stage::GetCurrent().GetSize();
620
621   Dali::Path path = Dali::Path::New();
622   Dali::Property::Array points;
623   points.Resize(3);
624   points[0] = Vector3( stageSize.x*0.5, 0.0f,  stageSize.x*0.5f);
625   points[1] = Vector3( 0.0f, 0.0f, 0.0f );
626   points[2] = Vector3( -stageSize.x*0.5f, 0.0f, stageSize.x*0.5f);
627   path.SetProperty( Path::Property::POINTS, points );
628
629   Dali::Property::Array controlPoints;
630   controlPoints.Resize(4);
631   controlPoints[0] = Vector3( stageSize.x*0.5f, 0.0f, stageSize.x*0.3f );
632   controlPoints[1] = Vector3( stageSize.x*0.3f, 0.0f, 0.0f );
633   controlPoints[2] = Vector3(-stageSize.x*0.3f, 0.0f, 0.0f );
634   controlPoints[3] = Vector3(-stageSize.x*0.5f, 0.0f,  stageSize.x*0.3f );
635   path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
636
637
638   mScrollViewEffect = ScrollViewPagePathEffect::New(path,
639                                                     Vector3(-1.0f,0.0f,0.0f),
640                                                     Toolkit::ScrollView::Property::SCROLL_FINAL_X,
641                                                     Vector3(stageSize.x*TABLE_RELATIVE_SIZE.x,stageSize.y*TABLE_RELATIVE_SIZE.y,0.0f),mTotalPages);
642 }
643
644 void DaliTableView::OnKeyEvent( const KeyEvent& event )
645 {
646   if( event.state == KeyEvent::Down )
647   {
648     if ( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
649     {
650       // If there's a Popup, Hide it if it's contributing to the display in any way (EG. transitioning in or out).
651       // Otherwise quit.
652       if ( mVersionPopup && ( mVersionPopup.GetDisplayState() != Toolkit::Popup::HIDDEN ) )
653       {
654         mVersionPopup.SetDisplayState( Popup::HIDDEN );
655       }
656       else
657       {
658         mApplication.Quit();
659       }
660     }
661   }
662 }
663
664 void DaliTableView::SetupBackground( Actor bubbleContainer )
665 {
666   // Create distance field shape.
667   BufferImage distanceField;
668   Size imageSize( 512, 512 );
669   CreateShapeImage( CIRCLE, imageSize, distanceField );
670
671   // Add bubbles to the bubbleContainer.
672   // Note: The bubbleContainer is parented externally to this function.
673   AddBackgroundActors( bubbleContainer, NUM_BACKGROUND_IMAGES, distanceField );
674 }
675
676 void DaliTableView::InitialiseBackgroundActors( Actor actor )
677 {
678   // Delete current animations
679   mBackgroundAnimations.clear();
680
681   // Create new animations
682   const Vector3 size = actor.GetTargetSize();
683
684   for( unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i )
685   {
686     Actor child = actor.GetChildAt( i );
687
688     // Calculate a random position
689     Vector3 childPos( Random::Range( -size.x * 0.5f * BACKGROUND_SPREAD_SCALE, size.x * 0.5f * BACKGROUND_SPREAD_SCALE ),
690                       Random::Range( -size.y, size.y ),
691                       Random::Range( BUBBLE_MIN_Z, BUBBLE_MAX_Z ) );
692
693     child.SetPosition( childPos );
694
695     // Define bubble horizontal parallax and vertical wrapping
696     Constraint animConstraint = Constraint::New < Vector3 > ( child, Actor::Property::POSITION, AnimateBubbleConstraint( childPos, Random::Range( -0.85f, 0.25f ) ) );
697     animConstraint.AddSource( Source( mScrollView, ScrollView::Property::SCROLL_POSITION ) );
698     animConstraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) );
699     animConstraint.AddSource( Dali::LocalSource( Dali::Actor::Property::SIZE ) );
700     animConstraint.SetRemoveAction( Constraint::Discard );
701     animConstraint.Apply();
702
703     // Kickoff animation
704     Animation animation = Animation::New( Random::Range( 30.0f, 160.0f ) );
705     animation.AnimateBy( Property( child, Actor::Property::POSITION ), Vector3( 0.0f, -2000.0f, 0.0f ), AlphaFunction::LINEAR );
706     animation.SetLooping( true );
707     animation.Play();
708     mBackgroundAnimations.push_back( animation );
709   }
710 }
711
712 void DaliTableView::AddBackgroundActors( Actor layer, int count, BufferImage distanceField )
713 {
714   for( int i = 0; i < count; ++i )
715   {
716     float randSize = Random::Range( 10.0f, 400.0f );
717     ImageView dfActor = ImageView::New( distanceField );
718     dfActor.SetSize( Vector2( randSize, randSize ) );
719     dfActor.SetParentOrigin( ParentOrigin::CENTER );
720
721     Dali::Property::Map effect = Toolkit::CreateDistanceFieldEffect();
722     dfActor.SetProperty( Toolkit::ImageView::Property::IMAGE, effect );
723     dfActor.SetColor( BUBBLE_COLOR[ i%NUMBER_OF_BUBBLE_COLOR ] );
724     layer.Add( dfActor );
725   }
726
727   // Positioning will occur when the layer is relaid out
728   layer.OnRelayoutSignal().Connect( this, &DaliTableView::InitialiseBackgroundActors );
729 }
730
731 void DaliTableView::CreateShapeImage( ShapeType shapeType, const Size& size, BufferImage& distanceFieldOut )
732 {
733   // this bitmap will hold the alpha map for the distance field shader
734   distanceFieldOut = BufferImage::New( size.width, size.height, Pixel::A8 );
735
736   // Generate bit pattern
737   std::vector< unsigned char > imageDataA8;
738   imageDataA8.reserve( size.width * size.height ); // A8
739
740   switch( shapeType )
741   {
742     case CIRCLE:
743       GenerateCircle( size, imageDataA8 );
744       break;
745     case SQUARE:
746       GenerateSquare( size, imageDataA8 );
747       break;
748     default:
749       break;
750   }
751
752   PixelBuffer* buffer = distanceFieldOut.GetBuffer();
753   if( buffer )
754   {
755     GenerateDistanceFieldMap( &imageDataA8[ 0 ], size, buffer, size, 8.0f, size );
756     distanceFieldOut.Update();
757   }
758 }
759
760 void DaliTableView::GenerateSquare( const Size& size, std::vector< unsigned char >& distanceFieldOut )
761 {
762   for( int h = 0; h < size.height; ++h )
763   {
764     for( int w = 0; w < size.width; ++w )
765     {
766       distanceFieldOut.push_back( 0xFF );
767     }
768   }
769 }
770
771 void DaliTableView::GenerateCircle( const Size& size, std::vector< unsigned char >& distanceFieldOut )
772 {
773   const float radius = size.width * 0.5f * size.width * 0.5f;
774   Vector2 center( size.width / 2, size.height / 2 );
775
776   for( int h = 0; h < size.height; ++h )
777   {
778     for( int w = 0; w < size.width; ++w )
779     {
780       Vector2 pos( w, h );
781       Vector2 dist = pos - center;
782
783       if( dist.x * dist.x + dist.y * dist.y > radius )
784       {
785         distanceFieldOut.push_back( 0x00 );
786       }
787       else
788       {
789         distanceFieldOut.push_back( 0xFF );
790       }
791     }
792   }
793 }
794
795 ImageView DaliTableView::CreateLogo( std::string imagePath )
796 {
797   Image image = ResourceImage::New( imagePath );
798   ImageView logo = ImageView::New( image );
799
800   logo.SetAnchorPoint( AnchorPoint::CENTER );
801   logo.SetParentOrigin( ParentOrigin::CENTER );
802
803   return logo;
804 }
805
806 bool DaliTableView::PauseBackgroundAnimation()
807 {
808   PauseAnimation();
809
810   return false;
811 }
812
813 void DaliTableView::PauseAnimation()
814 {
815   if( mBackgroundAnimsPlaying )
816   {
817     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
818     {
819       Animation anim = *animIter;
820
821       anim.Stop();
822     }
823
824     mBackgroundAnimsPlaying = false;
825   }
826 }
827
828 void DaliTableView::PlayAnimation()
829 {
830   if ( !mBackgroundAnimsPlaying )
831   {
832     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
833     {
834       Animation anim = *animIter;
835
836       anim.Play();
837     }
838
839     mBackgroundAnimsPlaying = true;
840   }
841
842   mAnimationTimer.SetInterval( BACKGROUND_ANIMATION_DURATION );
843 }
844
845 Dali::Actor DaliTableView::OnKeyboardPreFocusChange( Dali::Actor current, Dali::Actor proposed, Dali::Toolkit::Control::KeyboardFocus::Direction direction )
846 {
847   Actor nextFocusActor = proposed;
848
849   if ( !current && !proposed  )
850   {
851     // Set the initial focus to the first tile in the current page should be focused.
852     nextFocusActor = mPages[mScrollView.GetCurrentPage()].GetChildAt(0);
853   }
854   else if( !proposed || (proposed && proposed == mScrollViewLayer) )
855   {
856     // ScrollView is being focused but nothing in the current page can be focused further
857     // in the given direction. We should work out which page to scroll to next.
858     int currentPage = mScrollView.GetCurrentPage();
859     int newPage = currentPage;
860     if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
861     {
862       newPage--;
863     }
864     else if( direction == Dali::Toolkit::Control::KeyboardFocus::RIGHT )
865     {
866       newPage++;
867     }
868
869     newPage = std::max(0, std::min(mTotalPages - 1, newPage));
870     if( newPage == currentPage )
871     {
872       if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
873       {
874         newPage = mTotalPages - 1;
875       } else if( direction == Dali::Toolkit::Control::KeyboardFocus::RIGHT )
876       {
877         newPage = 0;
878       }
879     }
880
881     // Scroll to the page in the given direction
882     mScrollView.ScrollTo(newPage);
883
884     if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
885     {
886       // Work out the cell position for the last tile
887       int remainingExamples = mExampleList.size() - newPage * EXAMPLES_PER_PAGE;
888       int rowPos = (remainingExamples >= EXAMPLES_PER_PAGE) ? ROWS_PER_PAGE - 1 : ( (remainingExamples % EXAMPLES_PER_PAGE + EXAMPLES_PER_ROW) / EXAMPLES_PER_ROW - 1 );
889       int colPos = remainingExamples >= EXAMPLES_PER_PAGE ? EXAMPLES_PER_ROW - 1 : ( remainingExamples % EXAMPLES_PER_PAGE - rowPos * EXAMPLES_PER_ROW - 1 );
890
891       // Move the focus to the last tile in the new page.
892       nextFocusActor = mPages[newPage].GetChildAt(rowPos * EXAMPLES_PER_ROW + colPos);
893     }
894     else
895     {
896       // Move the focus to the first tile in the new page.
897       nextFocusActor = mPages[newPage].GetChildAt(0);
898     }
899   }
900
901   return nextFocusActor;
902 }
903
904 void DaliTableView::OnFocusedActorActivated( Dali::Actor activatedActor )
905 {
906   if(activatedActor)
907   {
908     mPressedActor = activatedActor;
909
910     // Activate the current focused actor;
911     TouchEvent touchEventUp;
912     touchEventUp.points.push_back( TouchPoint ( 0, TouchPoint::Up, 0.0f, 0.0f ) );
913     OnTilePressed(mPressedActor, touchEventUp);
914   }
915 }
916
917 bool DaliTableView::OnTileHovered( Actor actor, const HoverEvent& event )
918 {
919   KeyboardFocusManager::Get().SetCurrentFocusActor( actor );
920   return true;
921 }
922
923 void DaliTableView::OnLogoTapped( Dali::Actor actor, const Dali::TapGesture& tap )
924 {
925   // Only show if currently fully hidden. If transitioning-out, the transition will not be interrupted.
926   if ( !mVersionPopup || ( mVersionPopup.GetDisplayState() == Toolkit::Popup::HIDDEN ) )
927   {
928     if ( !mVersionPopup )
929     {
930       std::ostringstream stream;
931       stream << "DALi Core: "    << CORE_MAJOR_VERSION << "." << CORE_MINOR_VERSION << "." << CORE_MICRO_VERSION << std::endl << "(" << CORE_BUILD_DATE << ")\n";
932       stream << "DALi Adaptor: " << ADAPTOR_MAJOR_VERSION << "." << ADAPTOR_MINOR_VERSION << "." << ADAPTOR_MICRO_VERSION << std::endl << "(" << ADAPTOR_BUILD_DATE << ")\n";
933       stream << "DALi Toolkit: " << TOOLKIT_MAJOR_VERSION << "." << TOOLKIT_MINOR_VERSION << "." << TOOLKIT_MICRO_VERSION << std::endl << "(" << TOOLKIT_BUILD_DATE << ")\n";
934
935       mVersionPopup = Dali::Toolkit::Popup::New();
936
937       Toolkit::TextLabel titleActor = Toolkit::TextLabel::New( "Version information" );
938       titleActor.SetName( "titleActor" );
939       titleActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
940
941       Toolkit::TextLabel contentActor = Toolkit::TextLabel::New( stream.str() );
942       contentActor.SetName( "contentActor" );
943       contentActor.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, true );
944       contentActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
945       contentActor.SetPadding( Padding( 0.0f, 0.0f, 20.0f, 0.0f ) );
946
947       mVersionPopup.SetTitle( titleActor );
948       mVersionPopup.SetContent( contentActor );
949
950       mVersionPopup.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
951       mVersionPopup.SetSizeModeFactor( Vector3( 0.75f, 1.0f, 1.0f ) );
952       mVersionPopup.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
953
954       mVersionPopup.OutsideTouchedSignal().Connect( this, &DaliTableView::HideVersionPopup );
955       Stage::GetCurrent().Add( mVersionPopup );
956     }
957
958     mVersionPopup.SetDisplayState( Popup::SHOWN );
959   }
960 }
961
962 void DaliTableView::HideVersionPopup()
963 {
964   // Only hide if currently fully shown. If transitioning-in, the transition will not be interrupted.
965   if ( mVersionPopup && ( mVersionPopup.GetDisplayState() == Toolkit::Popup::SHOWN ) )
966   {
967     mVersionPopup.SetDisplayState( Popup::HIDDEN );
968   }
969 }