Merge "Updated demos following StyleManager move to the public API" into devel/master
[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   winHandle.ShowIndicator( Dali::Window::INVISIBLE );
303
304   // Background animation
305   mAnimationTimer = Timer::New( BACKGROUND_ANIMATION_DURATION );
306   mAnimationTimer.TickSignal().Connect( this, &DaliTableView::PauseBackgroundAnimation );
307   mAnimationTimer.Start();
308   mBackgroundAnimsPlaying = true;
309
310   KeyboardFocusManager::Get().PreFocusChangeSignal().Connect( this, &DaliTableView::OnKeyboardPreFocusChange );
311   KeyboardFocusManager::Get().FocusedActorEnterKeySignal().Connect( this, &DaliTableView::OnFocusedActorActivated );
312   AccessibilityManager::Get().FocusedActorActivatedSignal().Connect( this, &DaliTableView::OnFocusedActorActivated );
313 }
314
315 void DaliTableView::ApplyCubeEffectToPages()
316 {
317   ScrollViewPagePathEffect effect = ScrollViewPagePathEffect::DownCast( mScrollViewEffect );
318   unsigned int pageCount(0);
319   for( std::vector< Actor >::iterator pageIter = mPages.begin(); pageIter != mPages.end(); ++pageIter )
320   {
321     Actor page = *pageIter;
322     effect.ApplyToPage( page, pageCount++ );
323   }
324 }
325
326 void DaliTableView::OnButtonsPageRelayout( const Dali::Actor& actor )
327 {
328
329 }
330
331 void DaliTableView::Populate()
332 {
333   const Vector2 stageSize = Stage::GetCurrent().GetSize();
334
335   mTotalPages = ( mExampleList.size() + EXAMPLES_PER_PAGE - 1 ) / EXAMPLES_PER_PAGE;
336
337   // Populate ScrollView.
338   if( mExampleList.size() > 0 )
339   {
340     if( mSortAlphabetically )
341     {
342       sort( mExampleList.begin(), mExampleList.end(), CompareByTitle );
343     }
344
345     unsigned int exampleCount = 0;
346     ExampleListConstIter iter = mExampleList.begin();
347
348     for( int t = 0; t < mTotalPages; t++ )
349     {
350       // Create Table
351       TableView page = TableView::New( ROWS_PER_PAGE, EXAMPLES_PER_ROW );
352       page.SetAnchorPoint( AnchorPoint::CENTER );
353       page.SetParentOrigin( ParentOrigin::CENTER );
354       page.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
355       mScrollView.Add( page );
356
357       // Calculate the number of images going across (columns) within a page, according to the screen resolution and dpi.
358       const float margin = 2.0f;
359       const float tileParentMultiplier = 1.0f / EXAMPLES_PER_ROW;
360
361       for(int row = 0; row < ROWS_PER_PAGE; row++)
362       {
363         for(int column = 0; column < EXAMPLES_PER_ROW; column++)
364         {
365           const Example& example = ( *iter );
366
367           Actor tile = CreateTile( example.name, example.title, Vector3( tileParentMultiplier, tileParentMultiplier, 1.0f ), true );
368           AccessibilityManager accessibilityManager = AccessibilityManager::Get();
369           accessibilityManager.SetFocusOrder( tile, ++exampleCount );
370           accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_LABEL,
371                                                   example.title );
372           accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_TRAIT, "Tile" );
373           accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_HINT,
374                                                   "You can run this example" );
375
376           tile.SetPadding( Padding( margin, margin, margin, margin ) );
377
378           page.AddChild( tile, TableView::CellPosition( row, column ) );
379
380           iter++;
381
382           if( iter == mExampleList.end() )
383           {
384             break;
385           }
386         }
387
388         if( iter == mExampleList.end() )
389         {
390           break;
391         }
392       }
393
394       // Set tableview position
395       Vector3 pagePos( stageSize.width * TABLE_RELATIVE_SIZE.x * t, 0.0f, 0.0f );
396       page.SetPosition( pagePos );
397
398       mPages.push_back( page );
399
400       if( iter == mExampleList.end() )
401       {
402         break;
403       }
404     }
405   }
406
407   // Update Ruler info.
408   mScrollRulerX = new FixedRuler( stageSize.width * TABLE_RELATIVE_SIZE.x * 0.5f );
409   mScrollRulerY = new DefaultRuler();
410   mScrollRulerX->SetDomain( RulerDomain( 0.0f, (mTotalPages+1) * stageSize.width * TABLE_RELATIVE_SIZE.x * 0.5f, true ) );
411   mScrollRulerY->Disable();
412   mScrollView.SetRulerX( mScrollRulerX );
413   mScrollView.SetRulerY( mScrollRulerY );
414 }
415
416 void DaliTableView::Rotate( unsigned int degrees )
417 {
418   // Resize the root actor
419   Vector2 stageSize = Stage::GetCurrent().GetSize();
420   Vector3 targetSize( stageSize.x, stageSize.y, 1.0f );
421
422   if( degrees == 90 || degrees == 270 )
423   {
424     targetSize = Vector3( stageSize.y, stageSize.x, 1.0f );
425   }
426
427   if( mRotateAnimation )
428   {
429     mRotateAnimation.Stop();
430     mRotateAnimation.Clear();
431   }
432
433   mRotateAnimation = Animation::New( ROTATE_ANIMATION_TIME );
434   mRotateAnimation.AnimateTo( Property( mRootActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( 360 - degrees ) ), Vector3::ZAXIS ), AlphaFunction::EASE_OUT );
435   mRotateAnimation.AnimateTo( Property( mRootActor, Actor::Property::SIZE ), targetSize, AlphaFunction::EASE_OUT );
436   mRotateAnimation.Play();
437 }
438
439 Actor DaliTableView::CreateTile( const std::string& name, const std::string& title, const Dali::Vector3& sizeMultiplier, bool addBackground )
440 {
441   Actor content = Actor::New();
442   content.SetName( name );
443   content.SetAnchorPoint( AnchorPoint::CENTER );
444   content.SetParentOrigin( ParentOrigin::CENTER );
445   content.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
446   content.SetSizeModeFactor( sizeMultiplier );
447
448   // create background image
449   if( addBackground )
450   {
451     ImageView image = ImageView::New( TILE_BACKGROUND );
452     image.SetAnchorPoint( AnchorPoint::CENTER );
453     image.SetParentOrigin( ParentOrigin::CENTER );
454     // make the image 100% of tile
455     image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
456
457     content.Add( image );
458
459     // Add stencil
460     Toolkit::ImageView stencil = NewStencilImage();
461     stencil.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
462     image.Add( stencil );
463   }
464
465   TextLabel label = TextLabel::New();
466   label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
467   label.SetProperty( Control::Property::STYLE_NAME, "launcherlabel" );
468   label.SetProperty( TextLabel::Property::MULTI_LINE, true );
469   label.SetProperty( TextLabel::Property::TEXT, title );
470   label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
471   label.SetProperty( TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
472   label.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
473   content.Add( label );
474
475   // Set the tile to be keyboard focusable
476   content.SetKeyboardFocusable(true);
477
478   // connect to the touch events
479   content.TouchedSignal().Connect( this, &DaliTableView::OnTilePressed );
480   content.HoveredSignal().Connect( this, &DaliTableView::OnTileHovered );
481
482   return content;
483 }
484
485 Toolkit::ImageView DaliTableView::NewStencilImage()
486 {
487   Toolkit::ImageView stencil = ImageView::New( TILE_BACKGROUND_ALPHA );
488
489   stencil.SetParentOrigin( ParentOrigin::CENTER );
490   stencil.SetAnchorPoint( AnchorPoint::CENTER );
491   stencil.SetDrawMode( DrawMode::STENCIL );
492
493   Property::Map shaderEffect = CreateAlphaDiscardEffect();
494   stencil.SetProperty( Toolkit::ImageView::Property::IMAGE, shaderEffect );
495
496   return stencil;
497 }
498
499 bool DaliTableView::OnTilePressed( Actor actor, const TouchEvent& event )
500 {
501   bool consumed = false;
502
503   const TouchPoint& point = event.GetPoint( 0 );
504   if( TouchPoint::Down == point.state )
505   {
506     mPressedActor = actor;
507     consumed = true;
508   }
509
510   // A button press is only valid if the Down & Up events
511   // both occurred within the button.
512   if( ( TouchPoint::Up == point.state ) &&
513       ( mPressedActor == actor ) )
514   {
515     // ignore Example button presses when scrolling or button animating.
516     if( ( !mScrolling ) && ( !mPressedAnimation ) )
517     {
518       std::string name = actor.GetName();
519       const ExampleListIter end = mExampleList.end();
520       for( ExampleListIter iter = mExampleList.begin(); iter != end; ++iter )
521       {
522         if( (*iter).name == name )
523         {
524           // do nothing, until pressed animation finished.
525           consumed = true;
526           break;
527         }
528       }
529     }
530
531     if( consumed )
532     {
533       mPressedAnimation = Animation::New( BUTTON_PRESS_ANIMATION_TIME );
534       mPressedAnimation.SetEndAction( Animation::Discard );
535
536       // scale the content actor within the Tile, as to not affect the placement within the Table.
537       Actor content = actor.GetChildAt(0);
538       mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3( 0.9f, 0.9f, 1.0f ), AlphaFunction::EASE_IN_OUT,
539                                  TimePeriod( 0.0f, BUTTON_PRESS_ANIMATION_TIME * 0.5f ) );
540       mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT,
541                                  TimePeriod( BUTTON_PRESS_ANIMATION_TIME * 0.5f, BUTTON_PRESS_ANIMATION_TIME * 0.5f ) );
542       mPressedAnimation.Play();
543       mPressedAnimation.FinishedSignal().Connect( this, &DaliTableView::OnPressedAnimationFinished );
544     }
545   }
546   return consumed;
547 }
548
549 void DaliTableView::OnPressedAnimationFinished( Dali::Animation& source )
550 {
551   mPressedAnimation.Reset();
552   if( mPressedActor )
553   {
554     std::string name = mPressedActor.GetName();
555
556     std::stringstream stream;
557     stream << DEMO_EXAMPLE_BIN << name.c_str();
558     pid_t pid = fork();
559     if( pid == 0)
560     {
561       execlp( stream.str().c_str(), name.c_str(), NULL );
562       DALI_ASSERT_ALWAYS(false && "exec failed!");
563     }
564     mPressedActor.Reset();
565   }
566 }
567
568 void DaliTableView::OnScrollStart( const Dali::Vector2& position )
569 {
570   mScrolling = true;
571
572   PlayAnimation();
573 }
574
575 void DaliTableView::OnScrollComplete( const Dali::Vector2& position )
576 {
577   mScrolling = false;
578
579   // move focus to 1st item of new page
580   AccessibilityManager accessibilityManager = AccessibilityManager::Get();
581   accessibilityManager.SetCurrentFocusActor(mPages[mScrollView.GetCurrentPage()].GetChildAt(0) );
582 }
583
584 bool DaliTableView::OnScrollTouched( Actor actor, const TouchEvent& event )
585 {
586   const TouchPoint& point = event.GetPoint( 0 );
587   if( TouchPoint::Down == point.state )
588   {
589     mPressedActor = actor;
590   }
591
592   return false;
593 }
594
595 void DaliTableView::ApplyScrollViewEffect()
596 {
597   // Remove old effect if exists.
598
599   if( mScrollViewEffect )
600   {
601     mScrollView.RemoveEffect( mScrollViewEffect );
602   }
603
604   // Just one effect for now
605   SetupInnerPageCubeEffect();
606
607   mScrollView.ApplyEffect( mScrollViewEffect );
608 }
609
610 void DaliTableView::SetupInnerPageCubeEffect()
611 {
612   const Vector2 stageSize = Stage::GetCurrent().GetSize();
613
614   Dali::Path path = Dali::Path::New();
615   Dali::Property::Array points;
616   points.Resize(3);
617   points[0] = Vector3( stageSize.x*0.5, 0.0f,  stageSize.x*0.5f);
618   points[1] = Vector3( 0.0f, 0.0f, 0.0f );
619   points[2] = Vector3( -stageSize.x*0.5f, 0.0f, stageSize.x*0.5f);
620   path.SetProperty( Path::Property::POINTS, points );
621
622   Dali::Property::Array controlPoints;
623   controlPoints.Resize(4);
624   controlPoints[0] = Vector3( stageSize.x*0.5f, 0.0f, stageSize.x*0.3f );
625   controlPoints[1] = Vector3( stageSize.x*0.3f, 0.0f, 0.0f );
626   controlPoints[2] = Vector3(-stageSize.x*0.3f, 0.0f, 0.0f );
627   controlPoints[3] = Vector3(-stageSize.x*0.5f, 0.0f,  stageSize.x*0.3f );
628   path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
629
630
631   mScrollViewEffect = ScrollViewPagePathEffect::New(path,
632                                                     Vector3(-1.0f,0.0f,0.0f),
633                                                     Toolkit::ScrollView::Property::SCROLL_FINAL_X,
634                                                     Vector3(stageSize.x*TABLE_RELATIVE_SIZE.x,stageSize.y*TABLE_RELATIVE_SIZE.y,0.0f),mTotalPages);
635 }
636
637 void DaliTableView::OnKeyEvent( const KeyEvent& event )
638 {
639   if( event.state == KeyEvent::Down )
640   {
641     if ( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
642     {
643       // If there's a Popup, Hide it if it's contributing to the display in any way (EG. transitioning in or out).
644       // Otherwise quit.
645       if ( mVersionPopup && ( mVersionPopup.GetDisplayState() != Toolkit::Popup::HIDDEN ) )
646       {
647         mVersionPopup.SetDisplayState( Popup::HIDDEN );
648       }
649       else
650       {
651         mApplication.Quit();
652       }
653     }
654   }
655 }
656
657 void DaliTableView::SetupBackground( Actor bubbleContainer )
658 {
659   // Create distance field shape.
660   BufferImage distanceField;
661   Size imageSize( 512, 512 );
662   CreateShapeImage( CIRCLE, imageSize, distanceField );
663
664   // Add bubbles to the bubbleContainer.
665   // Note: The bubbleContainer is parented externally to this function.
666   AddBackgroundActors( bubbleContainer, NUM_BACKGROUND_IMAGES, distanceField );
667 }
668
669 void DaliTableView::InitialiseBackgroundActors( Actor actor )
670 {
671   // Delete current animations
672   mBackgroundAnimations.clear();
673
674   // Create new animations
675   const Vector3 size = actor.GetTargetSize();
676
677   for( unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i )
678   {
679     Actor child = actor.GetChildAt( i );
680
681     // Calculate a random position
682     Vector3 childPos( Random::Range( -size.x * 0.5f * BACKGROUND_SPREAD_SCALE, size.x * 0.5f * BACKGROUND_SPREAD_SCALE ),
683                       Random::Range( -size.y, size.y ),
684                       Random::Range( BUBBLE_MIN_Z, BUBBLE_MAX_Z ) );
685
686     child.SetPosition( childPos );
687
688     // Define bubble horizontal parallax and vertical wrapping
689     Constraint animConstraint = Constraint::New < Vector3 > ( child, Actor::Property::POSITION, AnimateBubbleConstraint( childPos, Random::Range( -0.85f, 0.25f ) ) );
690     animConstraint.AddSource( Source( mScrollView, ScrollView::Property::SCROLL_POSITION ) );
691     animConstraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) );
692     animConstraint.AddSource( Dali::LocalSource( Dali::Actor::Property::SIZE ) );
693     animConstraint.SetRemoveAction( Constraint::Discard );
694     animConstraint.Apply();
695
696     // Kickoff animation
697     Animation animation = Animation::New( Random::Range( 30.0f, 160.0f ) );
698     animation.AnimateBy( Property( child, Actor::Property::POSITION ), Vector3( 0.0f, -2000.0f, 0.0f ), AlphaFunction::LINEAR );
699     animation.SetLooping( true );
700     animation.Play();
701     mBackgroundAnimations.push_back( animation );
702   }
703 }
704
705 void DaliTableView::AddBackgroundActors( Actor layer, int count, BufferImage distanceField )
706 {
707   for( int i = 0; i < count; ++i )
708   {
709     float randSize = Random::Range( 10.0f, 400.0f );
710     ImageView dfActor = ImageView::New( distanceField );
711     dfActor.SetSize( Vector2( randSize, randSize ) );
712     dfActor.SetParentOrigin( ParentOrigin::CENTER );
713
714     Dali::Property::Map effect = Toolkit::CreateDistanceFieldEffect();
715     dfActor.SetProperty( Toolkit::ImageView::Property::IMAGE, effect );
716     dfActor.SetColor( BUBBLE_COLOR[ i%NUMBER_OF_BUBBLE_COLOR ] );
717     layer.Add( dfActor );
718   }
719
720   // Positioning will occur when the layer is relaid out
721   layer.OnRelayoutSignal().Connect( this, &DaliTableView::InitialiseBackgroundActors );
722 }
723
724 void DaliTableView::CreateShapeImage( ShapeType shapeType, const Size& size, BufferImage& distanceFieldOut )
725 {
726   // this bitmap will hold the alpha map for the distance field shader
727   distanceFieldOut = BufferImage::New( size.width, size.height, Pixel::A8 );
728
729   // Generate bit pattern
730   std::vector< unsigned char > imageDataA8;
731   imageDataA8.reserve( size.width * size.height ); // A8
732
733   switch( shapeType )
734   {
735     case CIRCLE:
736       GenerateCircle( size, imageDataA8 );
737       break;
738     case SQUARE:
739       GenerateSquare( size, imageDataA8 );
740       break;
741     default:
742       break;
743   }
744
745   PixelBuffer* buffer = distanceFieldOut.GetBuffer();
746   if( buffer )
747   {
748     GenerateDistanceFieldMap( &imageDataA8[ 0 ], size, buffer, size, 8.0f, size );
749     distanceFieldOut.Update();
750   }
751 }
752
753 void DaliTableView::GenerateSquare( const Size& size, std::vector< unsigned char >& distanceFieldOut )
754 {
755   for( int h = 0; h < size.height; ++h )
756   {
757     for( int w = 0; w < size.width; ++w )
758     {
759       distanceFieldOut.push_back( 0xFF );
760     }
761   }
762 }
763
764 void DaliTableView::GenerateCircle( const Size& size, std::vector< unsigned char >& distanceFieldOut )
765 {
766   const float radius = size.width * 0.5f * size.width * 0.5f;
767   Vector2 center( size.width / 2, size.height / 2 );
768
769   for( int h = 0; h < size.height; ++h )
770   {
771     for( int w = 0; w < size.width; ++w )
772     {
773       Vector2 pos( w, h );
774       Vector2 dist = pos - center;
775
776       if( dist.x * dist.x + dist.y * dist.y > radius )
777       {
778         distanceFieldOut.push_back( 0x00 );
779       }
780       else
781       {
782         distanceFieldOut.push_back( 0xFF );
783       }
784     }
785   }
786 }
787
788 ImageView DaliTableView::CreateLogo( std::string imagePath )
789 {
790   Image image = ResourceImage::New( imagePath );
791   ImageView logo = ImageView::New( image );
792
793   logo.SetAnchorPoint( AnchorPoint::CENTER );
794   logo.SetParentOrigin( ParentOrigin::CENTER );
795
796   return logo;
797 }
798
799 bool DaliTableView::PauseBackgroundAnimation()
800 {
801   PauseAnimation();
802
803   return false;
804 }
805
806 void DaliTableView::PauseAnimation()
807 {
808   if( mBackgroundAnimsPlaying )
809   {
810     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
811     {
812       Animation anim = *animIter;
813
814       anim.Stop();
815     }
816
817     mBackgroundAnimsPlaying = false;
818   }
819 }
820
821 void DaliTableView::PlayAnimation()
822 {
823   if ( !mBackgroundAnimsPlaying )
824   {
825     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
826     {
827       Animation anim = *animIter;
828
829       anim.Play();
830     }
831
832     mBackgroundAnimsPlaying = true;
833   }
834
835   mAnimationTimer.SetInterval( BACKGROUND_ANIMATION_DURATION );
836 }
837
838 Dali::Actor DaliTableView::OnKeyboardPreFocusChange( Dali::Actor current, Dali::Actor proposed, Dali::Toolkit::Control::KeyboardFocus::Direction direction )
839 {
840   Actor nextFocusActor = proposed;
841
842   if ( !current && !proposed  )
843   {
844     // Set the initial focus to the first tile in the current page should be focused.
845     nextFocusActor = mPages[mScrollView.GetCurrentPage()].GetChildAt(0);
846   }
847   else if( !proposed || (proposed && proposed == mScrollViewLayer) )
848   {
849     // ScrollView is being focused but nothing in the current page can be focused further
850     // in the given direction. We should work out which page to scroll to next.
851     int currentPage = mScrollView.GetCurrentPage();
852     int newPage = currentPage;
853     if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
854     {
855       newPage--;
856     }
857     else if( direction == Dali::Toolkit::Control::KeyboardFocus::RIGHT )
858     {
859       newPage++;
860     }
861
862     newPage = std::max(0, std::min(mTotalPages - 1, newPage));
863     if( newPage == currentPage )
864     {
865       if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
866       {
867         newPage = mTotalPages - 1;
868       } else if( direction == Dali::Toolkit::Control::KeyboardFocus::RIGHT )
869       {
870         newPage = 0;
871       }
872     }
873
874     // Scroll to the page in the given direction
875     mScrollView.ScrollTo(newPage);
876
877     if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
878     {
879       // Work out the cell position for the last tile
880       int remainingExamples = mExampleList.size() - newPage * EXAMPLES_PER_PAGE;
881       int rowPos = (remainingExamples >= EXAMPLES_PER_PAGE) ? ROWS_PER_PAGE - 1 : ( (remainingExamples % EXAMPLES_PER_PAGE + EXAMPLES_PER_ROW) / EXAMPLES_PER_ROW - 1 );
882       int colPos = remainingExamples >= EXAMPLES_PER_PAGE ? EXAMPLES_PER_ROW - 1 : ( remainingExamples % EXAMPLES_PER_PAGE - rowPos * EXAMPLES_PER_ROW - 1 );
883
884       // Move the focus to the last tile in the new page.
885       nextFocusActor = mPages[newPage].GetChildAt(rowPos * EXAMPLES_PER_ROW + colPos);
886     }
887     else
888     {
889       // Move the focus to the first tile in the new page.
890       nextFocusActor = mPages[newPage].GetChildAt(0);
891     }
892   }
893
894   return nextFocusActor;
895 }
896
897 void DaliTableView::OnFocusedActorActivated( Dali::Actor activatedActor )
898 {
899   if(activatedActor)
900   {
901     mPressedActor = activatedActor;
902
903     // Activate the current focused actor;
904     TouchEvent touchEventUp;
905     touchEventUp.points.push_back( TouchPoint ( 0, TouchPoint::Up, 0.0f, 0.0f ) );
906     OnTilePressed(mPressedActor, touchEventUp);
907   }
908 }
909
910 bool DaliTableView::OnTileHovered( Actor actor, const HoverEvent& event )
911 {
912   KeyboardFocusManager::Get().SetCurrentFocusActor( actor );
913   return true;
914 }
915
916 void DaliTableView::OnLogoTapped( Dali::Actor actor, const Dali::TapGesture& tap )
917 {
918   // Only show if currently fully hidden. If transitioning-out, the transition will not be interrupted.
919   if ( !mVersionPopup || ( mVersionPopup.GetDisplayState() == Toolkit::Popup::HIDDEN ) )
920   {
921     if ( !mVersionPopup )
922     {
923       std::ostringstream stream;
924       stream << "DALi Core: "    << CORE_MAJOR_VERSION << "." << CORE_MINOR_VERSION << "." << CORE_MICRO_VERSION << std::endl << "(" << CORE_BUILD_DATE << ")\n";
925       stream << "DALi Adaptor: " << ADAPTOR_MAJOR_VERSION << "." << ADAPTOR_MINOR_VERSION << "." << ADAPTOR_MICRO_VERSION << std::endl << "(" << ADAPTOR_BUILD_DATE << ")\n";
926       stream << "DALi Toolkit: " << TOOLKIT_MAJOR_VERSION << "." << TOOLKIT_MINOR_VERSION << "." << TOOLKIT_MICRO_VERSION << std::endl << "(" << TOOLKIT_BUILD_DATE << ")\n";
927
928       mVersionPopup = Dali::Toolkit::Popup::New();
929
930       Toolkit::TextLabel titleActor = Toolkit::TextLabel::New( "Version information" );
931       titleActor.SetName( "titleActor" );
932       titleActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
933
934       Toolkit::TextLabel contentActor = Toolkit::TextLabel::New( stream.str() );
935       contentActor.SetName( "contentActor" );
936       contentActor.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, true );
937       contentActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
938       contentActor.SetPadding( Padding( 0.0f, 0.0f, 20.0f, 0.0f ) );
939
940       mVersionPopup.SetTitle( titleActor );
941       mVersionPopup.SetContent( contentActor );
942
943       mVersionPopup.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
944       mVersionPopup.SetSizeModeFactor( Vector3( 0.75f, 1.0f, 1.0f ) );
945       mVersionPopup.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
946
947       mVersionPopup.OutsideTouchedSignal().Connect( this, &DaliTableView::HideVersionPopup );
948       Stage::GetCurrent().Add( mVersionPopup );
949     }
950
951     mVersionPopup.SetDisplayState( Popup::SHOWN );
952   }
953 }
954
955 void DaliTableView::HideVersionPopup()
956 {
957   // Only hide if currently fully shown. If transitioning-in, the transition will not be interrupted.
958   if ( mVersionPopup && ( mVersionPopup.GetDisplayState() == Toolkit::Popup::SHOWN ) )
959   {
960     mVersionPopup.SetDisplayState( Popup::HIDDEN );
961   }
962 }