Merge branch 'devel/master (1.2.0)' into tizen
[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.TouchSignal().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.TouchSignal().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   stencil.SetParentOrigin( ParentOrigin::CENTER );
489   stencil.SetAnchorPoint( AnchorPoint::CENTER );
490   stencil.SetDrawMode( DrawMode::STENCIL );
491
492   Property::Map shaderEffect = CreateAlphaDiscardEffect();
493   stencil.SetProperty( Toolkit::ImageView::Property::IMAGE, shaderEffect );
494
495   return stencil;
496 }
497
498 bool DaliTableView::OnTilePressed( Actor actor, const TouchData& event )
499 {
500   return DoTilePress( actor, event.GetState( 0 ) );
501 }
502
503 bool DaliTableView::DoTilePress( Actor actor, PointState::Type pointState )
504 {
505   bool consumed = false;
506
507   if( PointState::DOWN == pointState )
508   {
509     mPressedActor = actor;
510     consumed = true;
511   }
512
513   // A button press is only valid if the Down & Up events
514   // both occurred within the button.
515   if( ( PointState::UP == pointState ) &&
516       ( mPressedActor == actor ) )
517   {
518     // ignore Example button presses when scrolling or button animating.
519     if( ( !mScrolling ) && ( !mPressedAnimation ) )
520     {
521       std::string name = actor.GetName();
522       const ExampleListIter end = mExampleList.end();
523       for( ExampleListIter iter = mExampleList.begin(); iter != end; ++iter )
524       {
525         if( (*iter).name == name )
526         {
527           // do nothing, until pressed animation finished.
528           consumed = true;
529           break;
530         }
531       }
532     }
533
534     if( consumed )
535     {
536       mPressedAnimation = Animation::New( BUTTON_PRESS_ANIMATION_TIME );
537       mPressedAnimation.SetEndAction( Animation::Discard );
538
539       // scale the content actor within the Tile, as to not affect the placement within the Table.
540       Actor content = actor.GetChildAt(0);
541       mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3( 0.9f, 0.9f, 1.0f ), AlphaFunction::EASE_IN_OUT,
542                                  TimePeriod( 0.0f, BUTTON_PRESS_ANIMATION_TIME * 0.5f ) );
543       mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT,
544                                  TimePeriod( BUTTON_PRESS_ANIMATION_TIME * 0.5f, BUTTON_PRESS_ANIMATION_TIME * 0.5f ) );
545       mPressedAnimation.Play();
546       mPressedAnimation.FinishedSignal().Connect( this, &DaliTableView::OnPressedAnimationFinished );
547     }
548   }
549   return consumed;
550 }
551
552 void DaliTableView::OnPressedAnimationFinished( Dali::Animation& source )
553 {
554   mPressedAnimation.Reset();
555   if( mPressedActor )
556   {
557     std::string name = mPressedActor.GetName();
558
559     std::stringstream stream;
560     stream << DEMO_EXAMPLE_BIN << name.c_str();
561     pid_t pid = fork();
562     if( pid == 0)
563     {
564       execlp( stream.str().c_str(), name.c_str(), NULL );
565       DALI_ASSERT_ALWAYS(false && "exec failed!");
566     }
567     mPressedActor.Reset();
568   }
569 }
570
571 void DaliTableView::OnScrollStart( const Dali::Vector2& position )
572 {
573   mScrolling = true;
574
575   PlayAnimation();
576 }
577
578 void DaliTableView::OnScrollComplete( const Dali::Vector2& position )
579 {
580   mScrolling = false;
581
582   // move focus to 1st item of new page
583   AccessibilityManager accessibilityManager = AccessibilityManager::Get();
584   accessibilityManager.SetCurrentFocusActor(mPages[mScrollView.GetCurrentPage()].GetChildAt(0) );
585 }
586
587 bool DaliTableView::OnScrollTouched( Actor actor, const TouchData& event )
588 {
589   if( PointState::DOWN == event.GetState( 0 ) )
590   {
591     mPressedActor = actor;
592   }
593
594   return false;
595 }
596
597 void DaliTableView::ApplyScrollViewEffect()
598 {
599   // Remove old effect if exists.
600
601   if( mScrollViewEffect )
602   {
603     mScrollView.RemoveEffect( mScrollViewEffect );
604   }
605
606   // Just one effect for now
607   SetupInnerPageCubeEffect();
608
609   mScrollView.ApplyEffect( mScrollViewEffect );
610 }
611
612 void DaliTableView::SetupInnerPageCubeEffect()
613 {
614   const Vector2 stageSize = Stage::GetCurrent().GetSize();
615
616   Dali::Path path = Dali::Path::New();
617   Dali::Property::Array points;
618   points.Resize(3);
619   points[0] = Vector3( stageSize.x*0.5, 0.0f,  stageSize.x*0.5f);
620   points[1] = Vector3( 0.0f, 0.0f, 0.0f );
621   points[2] = Vector3( -stageSize.x*0.5f, 0.0f, stageSize.x*0.5f);
622   path.SetProperty( Path::Property::POINTS, points );
623
624   Dali::Property::Array controlPoints;
625   controlPoints.Resize(4);
626   controlPoints[0] = Vector3( stageSize.x*0.5f, 0.0f, stageSize.x*0.3f );
627   controlPoints[1] = Vector3( stageSize.x*0.3f, 0.0f, 0.0f );
628   controlPoints[2] = Vector3(-stageSize.x*0.3f, 0.0f, 0.0f );
629   controlPoints[3] = Vector3(-stageSize.x*0.5f, 0.0f,  stageSize.x*0.3f );
630   path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
631
632
633   mScrollViewEffect = ScrollViewPagePathEffect::New(path,
634                                                     Vector3(-1.0f,0.0f,0.0f),
635                                                     Toolkit::ScrollView::Property::SCROLL_FINAL_X,
636                                                     Vector3(stageSize.x*TABLE_RELATIVE_SIZE.x,stageSize.y*TABLE_RELATIVE_SIZE.y,0.0f),mTotalPages);
637 }
638
639 void DaliTableView::OnKeyEvent( const KeyEvent& event )
640 {
641   if( event.state == KeyEvent::Down )
642   {
643     if ( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
644     {
645       // If there's a Popup, Hide it if it's contributing to the display in any way (EG. transitioning in or out).
646       // Otherwise quit.
647       if ( mVersionPopup && ( mVersionPopup.GetDisplayState() != Toolkit::Popup::HIDDEN ) )
648       {
649         mVersionPopup.SetDisplayState( Popup::HIDDEN );
650       }
651       else
652       {
653         mApplication.Quit();
654       }
655     }
656   }
657 }
658
659 void DaliTableView::SetupBackground( Actor bubbleContainer )
660 {
661   // Create distance field shape.
662   BufferImage distanceField;
663   Size imageSize( 512, 512 );
664   CreateShapeImage( CIRCLE, imageSize, distanceField );
665
666   // Add bubbles to the bubbleContainer.
667   // Note: The bubbleContainer is parented externally to this function.
668   AddBackgroundActors( bubbleContainer, NUM_BACKGROUND_IMAGES, distanceField );
669 }
670
671 void DaliTableView::InitialiseBackgroundActors( Actor actor )
672 {
673   // Delete current animations
674   mBackgroundAnimations.clear();
675
676   // Create new animations
677   const Vector3 size = actor.GetTargetSize();
678
679   for( unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i )
680   {
681     Actor child = actor.GetChildAt( i );
682
683     // Calculate a random position
684     Vector3 childPos( Random::Range( -size.x * 0.5f * BACKGROUND_SPREAD_SCALE, size.x * 0.5f * BACKGROUND_SPREAD_SCALE ),
685                       Random::Range( -size.y, size.y ),
686                       Random::Range( BUBBLE_MIN_Z, BUBBLE_MAX_Z ) );
687
688     child.SetPosition( childPos );
689
690     // Define bubble horizontal parallax and vertical wrapping
691     Constraint animConstraint = Constraint::New < Vector3 > ( child, Actor::Property::POSITION, AnimateBubbleConstraint( childPos, Random::Range( -0.85f, 0.25f ) ) );
692     animConstraint.AddSource( Source( mScrollView, ScrollView::Property::SCROLL_POSITION ) );
693     animConstraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) );
694     animConstraint.AddSource( Dali::LocalSource( Dali::Actor::Property::SIZE ) );
695     animConstraint.SetRemoveAction( Constraint::Discard );
696     animConstraint.Apply();
697
698     // Kickoff animation
699     Animation animation = Animation::New( Random::Range( 30.0f, 160.0f ) );
700     animation.AnimateBy( Property( child, Actor::Property::POSITION ), Vector3( 0.0f, -2000.0f, 0.0f ), AlphaFunction::LINEAR );
701     animation.SetLooping( true );
702     animation.Play();
703     mBackgroundAnimations.push_back( animation );
704   }
705 }
706
707 void DaliTableView::AddBackgroundActors( Actor layer, int count, BufferImage distanceField )
708 {
709   for( int i = 0; i < count; ++i )
710   {
711     float randSize = Random::Range( 10.0f, 400.0f );
712     ImageView dfActor = ImageView::New( distanceField );
713     dfActor.SetSize( Vector2( randSize, randSize ) );
714     dfActor.SetParentOrigin( ParentOrigin::CENTER );
715
716     Dali::Property::Map effect = Toolkit::CreateDistanceFieldEffect();
717     dfActor.SetProperty( Toolkit::ImageView::Property::IMAGE, effect );
718     dfActor.SetColor( BUBBLE_COLOR[ i%NUMBER_OF_BUBBLE_COLOR ] );
719
720     layer.Add( dfActor );
721   }
722
723   // Positioning will occur when the layer is relaid out
724   layer.OnRelayoutSignal().Connect( this, &DaliTableView::InitialiseBackgroundActors );
725 }
726
727 void DaliTableView::CreateShapeImage( ShapeType shapeType, const Size& size, BufferImage& distanceFieldOut )
728 {
729   // this bitmap will hold the alpha map for the distance field shader
730   distanceFieldOut = BufferImage::New( size.width, size.height, Pixel::A8 );
731
732   // Generate bit pattern
733   std::vector< unsigned char > imageDataA8;
734   imageDataA8.reserve( size.width * size.height ); // A8
735
736   switch( shapeType )
737   {
738     case CIRCLE:
739       GenerateCircle( size, imageDataA8 );
740       break;
741     case SQUARE:
742       GenerateSquare( size, imageDataA8 );
743       break;
744     default:
745       break;
746   }
747
748   PixelBuffer* buffer = distanceFieldOut.GetBuffer();
749   if( buffer )
750   {
751     GenerateDistanceFieldMap( &imageDataA8[ 0 ], size, buffer, size, 8.0f, size );
752     distanceFieldOut.Update();
753   }
754 }
755
756 void DaliTableView::GenerateSquare( const Size& size, std::vector< unsigned char >& distanceFieldOut )
757 {
758   for( int h = 0; h < size.height; ++h )
759   {
760     for( int w = 0; w < size.width; ++w )
761     {
762       distanceFieldOut.push_back( 0xFF );
763     }
764   }
765 }
766
767 void DaliTableView::GenerateCircle( const Size& size, std::vector< unsigned char >& distanceFieldOut )
768 {
769   const float radius = size.width * 0.5f * size.width * 0.5f;
770   Vector2 center( size.width / 2, size.height / 2 );
771
772   for( int h = 0; h < size.height; ++h )
773   {
774     for( int w = 0; w < size.width; ++w )
775     {
776       Vector2 pos( w, h );
777       Vector2 dist = pos - center;
778
779       if( dist.x * dist.x + dist.y * dist.y > radius )
780       {
781         distanceFieldOut.push_back( 0x00 );
782       }
783       else
784       {
785         distanceFieldOut.push_back( 0xFF );
786       }
787     }
788   }
789 }
790
791 ImageView DaliTableView::CreateLogo( std::string imagePath )
792 {
793   ImageView logo = ImageView::New( imagePath );
794
795   logo.SetAnchorPoint( AnchorPoint::CENTER );
796   logo.SetParentOrigin( ParentOrigin::CENTER );
797
798   return logo;
799 }
800
801 bool DaliTableView::PauseBackgroundAnimation()
802 {
803   PauseAnimation();
804
805   return false;
806 }
807
808 void DaliTableView::PauseAnimation()
809 {
810   if( mBackgroundAnimsPlaying )
811   {
812     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
813     {
814       Animation anim = *animIter;
815
816       anim.Stop();
817     }
818
819     mBackgroundAnimsPlaying = false;
820   }
821 }
822
823 void DaliTableView::PlayAnimation()
824 {
825   if ( !mBackgroundAnimsPlaying )
826   {
827     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
828     {
829       Animation anim = *animIter;
830
831       anim.Play();
832     }
833
834     mBackgroundAnimsPlaying = true;
835   }
836
837   mAnimationTimer.SetInterval( BACKGROUND_ANIMATION_DURATION );
838 }
839
840 Dali::Actor DaliTableView::OnKeyboardPreFocusChange( Dali::Actor current, Dali::Actor proposed, Dali::Toolkit::Control::KeyboardFocus::Direction direction )
841 {
842   Actor nextFocusActor = proposed;
843
844   if ( !current && !proposed  )
845   {
846     // Set the initial focus to the first tile in the current page should be focused.
847     nextFocusActor = mPages[mScrollView.GetCurrentPage()].GetChildAt(0);
848   }
849   else if( !proposed || (proposed && proposed == mScrollViewLayer) )
850   {
851     // ScrollView is being focused but nothing in the current page can be focused further
852     // in the given direction. We should work out which page to scroll to next.
853     int currentPage = mScrollView.GetCurrentPage();
854     int newPage = currentPage;
855     if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
856     {
857       newPage--;
858     }
859     else if( direction == Dali::Toolkit::Control::KeyboardFocus::RIGHT )
860     {
861       newPage++;
862     }
863
864     newPage = std::max(0, std::min(mTotalPages - 1, newPage));
865     if( newPage == currentPage )
866     {
867       if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
868       {
869         newPage = mTotalPages - 1;
870       } else if( direction == Dali::Toolkit::Control::KeyboardFocus::RIGHT )
871       {
872         newPage = 0;
873       }
874     }
875
876     // Scroll to the page in the given direction
877     mScrollView.ScrollTo(newPage);
878
879     if( direction == Dali::Toolkit::Control::KeyboardFocus::LEFT )
880     {
881       // Work out the cell position for the last tile
882       int remainingExamples = mExampleList.size() - newPage * EXAMPLES_PER_PAGE;
883       int rowPos = (remainingExamples >= EXAMPLES_PER_PAGE) ? ROWS_PER_PAGE - 1 : ( (remainingExamples % EXAMPLES_PER_PAGE + EXAMPLES_PER_ROW) / EXAMPLES_PER_ROW - 1 );
884       int colPos = remainingExamples >= EXAMPLES_PER_PAGE ? EXAMPLES_PER_ROW - 1 : ( remainingExamples % EXAMPLES_PER_PAGE - rowPos * EXAMPLES_PER_ROW - 1 );
885
886       // Move the focus to the last tile in the new page.
887       nextFocusActor = mPages[newPage].GetChildAt(rowPos * EXAMPLES_PER_ROW + colPos);
888     }
889     else
890     {
891       // Move the focus to the first tile in the new page.
892       nextFocusActor = mPages[newPage].GetChildAt(0);
893     }
894   }
895
896   return nextFocusActor;
897 }
898
899 void DaliTableView::OnFocusedActorActivated( Dali::Actor activatedActor )
900 {
901   if(activatedActor)
902   {
903     mPressedActor = activatedActor;
904
905     // Activate the current focused actor;
906     DoTilePress( mPressedActor, PointState::UP );
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 }