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