Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-demo.git] / demo / dali-table-view.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "dali-table-view.h"
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23 #include <sstream>
24 #include <unistd.h>
25
26 // INTERNAL INCLUDES
27 #include "shared/view.h"
28
29 using namespace Dali;
30 using namespace Dali::Toolkit;
31
32 ///////////////////////////////////////////////////////////////////////////////
33
34 namespace
35 {
36
37 const std::string BUTTON_BACKWARD( "Backward" );
38 const std::string BUTTON_FORWARD( "Forward" );
39 const std::string BUTTON_QUIT( "Quit" );
40 const std::string BUTTON_OK( "Ok" );
41 const std::string BUTTON_CANCEL( "Cancel" );
42
43 const std::string DEFAULT_BACKGROUND_IMAGE_PATH( DALI_IMAGE_DIR "background-gradient.jpg" );
44 const std::string LOGO_PATH( DALI_IMAGE_DIR "dali-logo.png" );
45 const std::string DEFAULT_TOOLBAR_IMAGE_PATH( DALI_IMAGE_DIR "top-bar.png" );
46 const std::string BUTTON_BACKGROUND(DALI_IMAGE_DIR "button-background.png");
47 const std::string TILE_BACKGROUND(DALI_IMAGE_DIR "item-background.png");
48 const std::string TILE_BACKGROUND_ALPHA(DALI_IMAGE_DIR "item-background-alpha.png");
49
50 const char * const DEFAULT_TOOLBAR_TEXT( "TOUCH TO LAUNCH EXAMPLE" );
51
52 const float BUTTON_PRESS_ANIMATION_TIME = 0.25f;                ///< Time to perform button scale effect.
53 const float ROTATE_ANIMATION_TIME = 0.5f;                       ///< Time to perform rotate effect.
54 const int MAX_PAGES = 256;                                      ///< Maximum pages (arbitrary safety limit)
55 const int EXAMPLES_PER_ROW = 3;
56 const int ROWS_PER_PAGE = 3;
57 const int EXAMPLES_PER_PAGE = EXAMPLES_PER_ROW * ROWS_PER_PAGE;
58 const float LOGO_MARGIN_RATIO = 0.5f / 0.9f;
59 const float BOTTOM_PADDING_RATIO = 0.4f / 0.9f;
60 const Vector3 SCROLLVIEW_RELATIVE_SIZE(0.9f, 1.0f, 0.8f );     ///< ScrollView's relative size to its parent
61 const Vector3 TABLE_RELATIVE_SIZE(0.9f, 0.9f, 0.8f );          ///< TableView's relative size to the entire stage. The Y value means sum of the logo and table relative heights.
62 const float STENCIL_RELATIVE_SIZE = 1.0f;
63
64 const float EFFECT_SNAP_DURATION = 0.66f;                       ///< Scroll Snap Duration for Effects
65 const float EFFECT_FLICK_DURATION = 0.5f;                       ///< Scroll Flick Duration for Effects
66 const Vector3 ANGLE_CUBE_PAGE_ROTATE(Math::PI * 0.5f, Math::PI * 0.5f, 0.0f);
67
68 const int NUM_BACKGROUND_IMAGES = 18;
69 const float BACKGROUND_SWIPE_SCALE = 0.025f;
70 const float BACKGROUND_SPREAD_SCALE = 1.5f;
71 const float SCALE_MOD = 1000.0f * Math::PI * 2.0f;
72 const float SCALE_SPEED = 10.0f;
73 const float SCALE_SPEED_SIN = 0.1f;
74
75 const unsigned int BACKGROUND_ANIMATION_DURATION = 15000; // 15 secs
76
77 const float BACKGROUND_Z = -1.0f;
78 const float BACKGROUND_SIZE_SCALE = 1.0f;
79 const Vector4 BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 1.0f );
80
81 const float BUBBLE_MIN_Z = -1.0;
82 const float BUBBLE_MAX_Z = 0.0f;
83
84 // 3D Effect constants
85 const Vector2 ANGLE_SWING_3DEFFECT( Math::PI_2 * 0.75, Math::PI_2 * 0.75f ); ///< Angle Swing in radians
86 const Vector2 POSITION_SWING_3DEFFECT( 0.55f, 0.4f );             ///< Position Swing relative to stage size.
87 const Vector3 ANCHOR_3DEFFECT_STYLE0( -105.0f, 30.0f, -240.0f ); ///< Rotation Anchor position for 3D Effect (Style 0)
88 const Vector3 ANCHOR_3DEFFECT_STYLE1( 65.0f, -70.0f, -500.0f );  ///< Rotation Anchor position for 3D Effect (Style 1)
89
90 //const std::string             DEFAULT_TEXT_STYLE_FONT_FAMILY("HelveticaNeue");
91 //const std::string             DEFAULT_TEXT_STYLE_FONT_STYLE("Regular");
92 //const Dali::Vector4           DEFAULT_TEXT_STYLE_COLOR(0.7f, 0.7f, 0.7f, 1.0f);
93
94 //const std::string             TABLE_TEXT_STYLE_FONT_FAMILY("HelveticaNeue");
95 //const std::string             TABLE_TEXT_STYLE_FONT_STYLE("Regular");
96 //const Dali::PointSize         TABLE_TEXT_STYLE_POINT_SIZE( 8.0f );
97 //const Dali::TextStyle::Weight TABLE_TEXT_STYLE_WEIGHT(Dali::TextStyle::LIGHT);
98 //const Dali::Vector4           TABLE_TEXT_STYLE_COLOR(0.0f, 0.0f, 0.0f, 1.0f);
99
100 Vector3 ScalePointSize(const Vector3& vec)
101 {
102   return Vector3( DemoHelper::ScalePointSize( vec.x ), DemoHelper::ScalePointSize( vec.y ), DemoHelper::ScalePointSize( vec.z ) );
103 }
104
105 #define DP(x) DemoHelper::ScalePointSize(x)
106
107 /**
108  * Creates the background image
109  */
110 ImageActor CreateBackground( std::string imagePath )
111 {
112   Image image = ResourceImage::New( imagePath );
113   ImageActor background = ImageActor::New( image );
114
115   background.SetAnchorPoint( AnchorPoint::CENTER );
116   background.SetParentOrigin( ParentOrigin::CENTER );
117   background.SetZ( -1.0f );
118
119   return background;
120 }
121
122 // These values depend on the tile image
123 const float IMAGE_BORDER_LEFT = 11.0f;
124 const float IMAGE_BORDER_RIGHT = IMAGE_BORDER_LEFT;
125 const float IMAGE_BORDER_TOP = IMAGE_BORDER_LEFT;
126 const float IMAGE_BORDER_BOTTOM = IMAGE_BORDER_LEFT;
127
128 /**
129  * Constraint to return a position for a bubble based on the scroll value and vertical wrapping.
130  */
131 struct AnimateBubbleConstraint
132 {
133 public:
134   AnimateBubbleConstraint( const Vector3& initialPos, float scale, float size )
135       : mInitialX( initialPos.x ),
136         mScale( scale ),
137         mShapeSize( size )
138   {
139   }
140
141   Vector3 operator()( const Vector3& current, const PropertyInput& scrollProperty, const PropertyInput& parentSize )
142   {
143     Vector3 pos( current );
144
145     // Wrap bubbles verically.
146     if( pos.y + mShapeSize * 0.5f < -parentSize.GetVector3().y * 0.5f )
147     {
148       pos.y += parentSize.GetVector3().y + mShapeSize;
149     }
150
151     // Bubbles X position moves parallax to horizontal
152     // panning by a scale factor unique to each bubble.
153     pos.x = mInitialX + ( scrollProperty.GetVector3().x * mScale );
154     return pos;
155   }
156
157 private:
158   float mInitialX;
159   float mScale;
160   float mShapeSize;
161 };
162
163 bool CompareByTitle( const Example& lhs, const Example& rhs )
164 {
165   return lhs.title < rhs.title;
166 }
167
168 } // namespace
169
170 DaliTableView::DaliTableView( Application& application )
171     : mApplication( application ),
172         mScrolling( false ),
173         mBackgroundImagePath( DEFAULT_BACKGROUND_IMAGE_PATH ),
174         mSortAlphabetically( false ),
175         mBackgroundAnimsPlaying( false )
176 {
177   application.InitSignal().Connect( this, &DaliTableView::Initialize );
178 }
179
180 DaliTableView::~DaliTableView()
181 {
182 }
183
184 void DaliTableView::AddExample( Example example )
185 {
186   mExampleList.push_back( example );
187   mExampleMap[ example.name ] = example;
188 }
189
190 void DaliTableView::SetBackgroundPath( std::string imagePath )
191 {
192   mBackgroundImagePath = imagePath;
193 }
194
195 void DaliTableView::SortAlphabetically( bool sortAlphabetically )
196 {
197   mSortAlphabetically = sortAlphabetically;
198 }
199
200 void DaliTableView::Initialize( Application& application )
201 {
202   Stage::GetCurrent().KeyEventSignal().Connect( this, &DaliTableView::OnKeyEvent );
203
204   const Vector2 stageSize = Stage::GetCurrent().GetSize();
205
206   // Background
207   mBackground = CreateBackground( mBackgroundImagePath );
208   // set same size as parent actor
209   mBackground.SetSize( stageSize );
210   Stage::GetCurrent().Add( mBackground );
211
212   // Render entire content as overlays, as is all on same 2D plane.
213   mRootActor = TableView::New( 4, 1 );
214   mRootActor.SetAnchorPoint( AnchorPoint::CENTER );
215   mRootActor.SetParentOrigin( ParentOrigin::CENTER );
216   Stage::GetCurrent().Add( mRootActor );
217
218   // Toolbar at top
219   Dali::Toolkit::ToolBar toolbar;
220   Dali::Layer toolBarLayer = DemoHelper::CreateToolbar(toolbar,
221                                                        DEFAULT_TOOLBAR_IMAGE_PATH,
222                                                        DEFAULT_TOOLBAR_TEXT,
223                                                        DemoHelper::DEFAULT_VIEW_STYLE);
224
225   mRootActor.AddChild( toolBarLayer, TableView::CellPosition( 0, 0 ) );
226   const float toolbarHeight = DemoHelper::DEFAULT_VIEW_STYLE.mToolBarHeight;
227   mRootActor.SetFixedHeight( 0, toolbarHeight );
228
229   // Add logo
230   mLogo = CreateLogo( LOGO_PATH );
231   const float paddingHeight = ( ( 1.f-TABLE_RELATIVE_SIZE.y ) * stageSize.y );
232   const float logoMargin = paddingHeight * LOGO_MARGIN_RATIO;
233   const float logoHeight = mLogo.GetImage().GetHeight() + logoMargin;
234   mRootActor.SetFixedHeight( 1, logoHeight );
235
236   const float bottomMargin = paddingHeight * BOTTOM_PADDING_RATIO;
237   mButtonsPageRelativeSize = Vector3( TABLE_RELATIVE_SIZE.x, 1.f - ( toolbarHeight + logoHeight + bottomMargin) / stageSize.height, TABLE_RELATIVE_SIZE.z );
238   mRootActor.SetFixedHeight( 2, mButtonsPageRelativeSize.y * stageSize.height );
239
240   Alignment alignment = Alignment::New();
241   alignment.Add(mLogo);
242   mRootActor.AddChild( alignment, TableView::CellPosition( 1, 0 ) );
243
244   // scrollview occupying the majority of the screen
245   mScrollView = ScrollView::New();
246
247   mScrollView.SetAnchorPoint( AnchorPoint::CENTER );
248   mScrollView.SetParentOrigin( ParentOrigin::CENTER );
249   // Note: Currently, changing mScrollView to use SizeMode RELATIVE_TO_PARENT
250   // will cause scroll ends to appear in the wrong position.
251   mScrollView.ApplyConstraint( Dali::Constraint::New<Dali::Vector3>( Dali::Actor::Property::Size, Dali::ParentSource( Dali::Actor::Property::Size ), Dali::RelativeToConstraint( SCROLLVIEW_RELATIVE_SIZE ) ) );
252   mScrollView.SetAxisAutoLock( true );
253   mScrollView.ScrollCompletedSignal().Connect( this, &DaliTableView::OnScrollComplete );
254   mScrollView.ScrollStartedSignal().Connect( this, &DaliTableView::OnScrollStart );
255   mScrollView.TouchedSignal().Connect( this, &DaliTableView::OnScrollTouched );
256
257   mScrollViewLayer = Layer::New();
258   mScrollViewLayer.SetAnchorPoint( AnchorPoint::CENTER );
259   mScrollViewLayer.SetParentOrigin( ParentOrigin::CENTER );
260   mScrollViewLayer.SetDrawMode( DrawMode::OVERLAY );
261
262   // Populate background and bubbles - needs to be scrollViewLayer so scroll ends show
263   SetupBackground( mScrollView, mScrollViewLayer, stageSize );
264
265   mScrollViewLayer.Add( mScrollView );
266   mRootActor.AddChild( mScrollViewLayer, TableView::CellPosition( 2, 0 ) );
267
268   // Add scroll view effect and setup constraints on pages
269   ApplyScrollViewEffect();
270
271   // Add pages and tiles
272   Populate();
273
274   // Remove constraints for inner cube effect
275   ApplyCubeEffectToActors();
276
277   // Set initial orientation
278   unsigned int degrees = application.GetOrientation().GetDegrees();
279   Rotate( degrees );
280
281   Dali::Window winHandle = application.GetWindow();
282   winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT );
283   winHandle.RemoveAvailableOrientation( Dali::Window::LANDSCAPE );
284   winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT_INVERSE );
285   winHandle.RemoveAvailableOrientation( Dali::Window::LANDSCAPE_INVERSE );
286
287   Dali::Orientation orientation = winHandle.GetOrientation();
288   orientation.ChangedSignal().Connect( this, &DaliTableView::OrientationChanged );
289
290   winHandle.ShowIndicator( Dali::Window::INVISIBLE );
291
292   //
293   mAnimationTimer = Timer::New( BACKGROUND_ANIMATION_DURATION );
294   mAnimationTimer.TickSignal().Connect( this, &DaliTableView::PauseBackgroundAnimation );
295   mAnimationTimer.Start();
296   mBackgroundAnimsPlaying = true;
297
298   KeyboardFocusManager::Get().PreFocusChangeSignal().Connect( this, &DaliTableView::OnKeyboardPreFocusChange );
299   KeyboardFocusManager::Get().FocusedActorActivatedSignal().Connect( this, &DaliTableView::OnFocusedActorActivated );
300 }
301
302 void DaliTableView::ApplyCubeEffectToActors()
303 {
304   for( ActorIter pageIter = mPages.begin(); pageIter != mPages.end(); ++pageIter )
305   {
306     Actor page = *pageIter;
307
308     unsigned int numChildren = page.GetChildCount();
309     Actor pageActor = page;
310     for( unsigned int i=0; i<numChildren; ++i)
311     {
312       // Remove old effect's manual constraints.
313       Actor child = pageActor.GetChildAt(i);
314       if( child )
315       {
316         ApplyCubeEffectToActor( child );
317       }
318     }
319   }
320 }
321 void DaliTableView::Populate()
322 {
323   const Vector2 stageSize = Stage::GetCurrent().GetSize();
324
325   mTotalPages = ( mExampleList.size() + EXAMPLES_PER_PAGE - 1 ) / EXAMPLES_PER_PAGE;
326
327   // Populate ScrollView.
328   if( mExampleList.size() > 0 )
329   {
330     if( mSortAlphabetically )
331     {
332       sort( mExampleList.begin(), mExampleList.end(), CompareByTitle );
333     }
334
335     unsigned int exampleCount = 0;
336     ExampleListConstIter iter = mExampleList.begin();
337
338     for( int t = 0; t < mTotalPages; t++ )
339     {
340       // Create Table. (contains up to 9 Examples)
341       Actor page = Actor::New();
342
343       // Add tableView to container.
344       mScrollView.Add( page );
345
346       page.SetAnchorPoint( AnchorPoint::CENTER );
347       page.SetParentOrigin( ParentOrigin::CENTER );
348       page.SetSizeMode( SIZE_EQUAL_TO_PARENT );
349
350       // add cells to table
351       const float margin = 4.0f;
352
353       // Calculate the number of images going across (columns) within a page, according to the screen resolution and dpi.
354       const Size tileSize((stageSize.x * mButtonsPageRelativeSize.x / EXAMPLES_PER_ROW) - margin, (stageSize.y * mButtonsPageRelativeSize.y / ROWS_PER_PAGE) - margin );
355
356       for(int row = 0; row < ROWS_PER_PAGE; row++)
357       {
358         for(int column = 0; column < EXAMPLES_PER_ROW; column++)
359         {
360           const Example& example = ( *iter );
361
362           Actor tile = CreateTile( example.name, example.title, tileSize, true );
363           FocusManager focusManager = FocusManager::Get();
364           focusManager.SetFocusOrder( tile, ++exampleCount );
365           focusManager.SetAccessibilityAttribute( tile, Dali::Toolkit::FocusManager::ACCESSIBILITY_LABEL,
366                                                   example.title );
367           focusManager.SetAccessibilityAttribute( tile, Dali::Toolkit::FocusManager::ACCESSIBILITY_TRAIT, "Tile" );
368           focusManager.SetAccessibilityAttribute( tile, Dali::Toolkit::FocusManager::ACCESSIBILITY_HINT,
369                                                   "You can run this example" );
370
371           Vector3 position( margin * 0.5f + (tileSize.x + margin) * column - stageSize.width * mButtonsPageRelativeSize.x * 0.5f,
372                            margin * 0.5f + (tileSize.y + margin) * row - stageSize.height * mButtonsPageRelativeSize.y * 0.5f,
373                             0.0f);
374           tile.SetPosition( position + Vector3( tileSize.x, tileSize.y, 0.0f ) * 0.5f );
375           tile.SetSize( tileSize );
376           page.Add( tile );
377
378           iter++;
379
380           if( iter == mExampleList.end() )
381           {
382             break;
383           }
384         }
385
386         if( iter == mExampleList.end() )
387         {
388           break;
389         }
390       }
391
392       // Set tableview position
393       Vector3 pagePos( stageSize.x * mButtonsPageRelativeSize.x * t, 0.0f, 0.0f );
394       page.SetPosition( pagePos );
395
396       mPages.push_back( page );
397
398       if( iter == mExampleList.end() )
399       {
400         break;
401       }
402     }
403   }
404
405   // Update Ruler info.
406   mScrollRulerX = new FixedRuler( stageSize.width * mButtonsPageRelativeSize.x );
407   mScrollRulerY = new DefaultRuler();
408   mScrollRulerX->SetDomain( RulerDomain( 0.0f, mTotalPages * stageSize.width * mButtonsPageRelativeSize.x, true ) );
409   mScrollRulerY->Disable();
410   mScrollView.SetRulerX( mScrollRulerX );
411   mScrollView.SetRulerY( mScrollRulerY );
412 }
413
414 void DaliTableView::OrientationChanged( Orientation orientation )
415 {
416   // TODO: Implement if orientation change required
417 }
418
419 void DaliTableView::Rotate( unsigned int degrees )
420 {
421   // Resize the root actor
422   Vector2 stageSize = Stage::GetCurrent().GetSize();
423   Vector3 targetSize( stageSize.x, stageSize.y, 1.0f );
424
425   if( degrees == 90 || degrees == 270 )
426   {
427     targetSize = Vector3( stageSize.y, stageSize.x, 1.0f );
428   }
429
430   if( mRotateAnimation )
431   {
432     mRotateAnimation.Stop();
433     mRotateAnimation.Clear();
434   }
435
436   mRotateAnimation = Animation::New( ROTATE_ANIMATION_TIME );
437   mRotateAnimation.RotateTo( mRootActor, Degree( 360 - degrees ), Vector3::ZAXIS, AlphaFunctions::EaseOut );
438   mRotateAnimation.Resize( mRootActor, targetSize, AlphaFunctions::EaseOut );
439   mRotateAnimation.Play();
440 }
441
442 Actor DaliTableView::CreateTile( const std::string& name, const std::string& title, const Size& parentSize, bool addBackground )
443 {
444   Actor tile = Actor::New();
445   tile.SetName( name );
446   tile.SetAnchorPoint( AnchorPoint::CENTER );
447   tile.SetParentOrigin( ParentOrigin::CENTER );
448
449   // create background image
450   if( addBackground )
451   {
452     Image bg = ResourceImage::New( TILE_BACKGROUND );
453     ImageActor image = ImageActor::New( bg );
454     image.SetAnchorPoint( AnchorPoint::CENTER );
455     image.SetParentOrigin( ParentOrigin::CENTER );
456     // make the image 100% of tile
457     image.SetSizeMode( SIZE_EQUAL_TO_PARENT );
458     // move image back to get text appear in front
459     image.SetZ( -1 );
460     image.SetStyle( ImageActor::STYLE_NINE_PATCH );
461     image.SetNinePatchBorder( Vector4( IMAGE_BORDER_LEFT, IMAGE_BORDER_TOP, IMAGE_BORDER_RIGHT, IMAGE_BORDER_BOTTOM ) );
462     tile.Add( image );
463
464     // Add stencil
465     ImageActor stencil = NewStencilImage();
466     stencil.SetSizeMode( SIZE_EQUAL_TO_PARENT );
467     image.Add( stencil );
468   }
469
470   TextLabel label = TextLabel::New();
471   label.SetParentOrigin( ParentOrigin::TOP_LEFT );
472   label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
473   label.SetProperty( TextLabel::PROPERTY_MULTI_LINE, true );
474   label.SetProperty( TextLabel::PROPERTY_TEXT, title );
475   label.SetColor( Color::BLACK );
476   tile.Add( label );
477
478   // FIXME - This is a kludge because size negotiation is not finished
479   label.SetSize( parentSize );
480
481   // Set the tile to be keyboard focusable
482   tile.SetKeyboardFocusable(true);
483
484   // connect to the touch events
485   tile.TouchedSignal().Connect( this, &DaliTableView::OnTilePressed );
486   tile.HoveredSignal().Connect( this, &DaliTableView::OnTileHovered );
487
488   return tile;
489 }
490
491 ImageActor DaliTableView::NewStencilImage()
492 {
493   Image alpha = ResourceImage::New( TILE_BACKGROUND_ALPHA );
494
495   ImageActor stencilActor = ImageActor::New( alpha );
496   stencilActor.SetStyle( ImageActor::STYLE_NINE_PATCH );
497   stencilActor.SetNinePatchBorder( Vector4( IMAGE_BORDER_LEFT, IMAGE_BORDER_TOP, IMAGE_BORDER_RIGHT, IMAGE_BORDER_BOTTOM ) );
498
499   stencilActor.SetParentOrigin( ParentOrigin::CENTER );
500   stencilActor.SetAnchorPoint( AnchorPoint::CENTER );
501   stencilActor.SetDrawMode( DrawMode::STENCIL );
502
503   Dali::ShaderEffect shaderEffect = AlphaDiscardEffect::New();
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     std::string name = actor.GetName();
526     ExampleMapConstIter iter = mExampleMap.find( name );
527
528     FocusManager focusManager = FocusManager::Get();
529
530     if( iter != mExampleMap.end() )
531     {
532       // ignore Example button presses when scrolling or button animating.
533       if( ( !mScrolling ) && ( !mPressedAnimation ) )
534       {
535         // do nothing, until pressed animation finished.
536         consumed = true;
537       }
538     }
539
540     if( consumed )
541     {
542       mPressedAnimation = Animation::New( BUTTON_PRESS_ANIMATION_TIME );
543       mPressedAnimation.SetEndAction( Animation::Discard );
544
545       // scale the content actor within the Tile, as to not affect the placement within the Table.
546       Actor content = actor.GetChildAt(0);
547       mPressedAnimation.ScaleTo( content, Vector3( 0.9f, 0.9f, 1.0f ), AlphaFunctions::EaseInOut, 0.0f,
548                                  BUTTON_PRESS_ANIMATION_TIME * 0.5f );
549       mPressedAnimation.ScaleTo( content, Vector3::ONE, AlphaFunctions::EaseInOut, BUTTON_PRESS_ANIMATION_TIME * 0.5f,
550                                  BUTTON_PRESS_ANIMATION_TIME * 0.5f );
551       mPressedAnimation.Play();
552       mPressedAnimation.FinishedSignal().Connect( this, &DaliTableView::OnPressedAnimationFinished );
553     }
554   }
555   return consumed;
556 }
557
558 void DaliTableView::OnPressedAnimationFinished( Dali::Animation& source )
559 {
560   mPressedAnimation.Reset();
561   if( mPressedActor )
562   {
563     std::string name = mPressedActor.GetName();
564     ExampleMapConstIter iter = mExampleMap.find( name );
565
566     if( iter == mExampleMap.end() )
567     {
568       if( name == BUTTON_QUIT )
569       {
570         // Move focus to the OK button
571         FocusManager focusManager = FocusManager::Get();
572
573         // Enable the group mode and wrap mode
574         focusManager.SetGroupMode( true );
575         focusManager.SetWrapMode( true );
576       }
577     }
578     else
579     {
580       const Example& example( iter->second );
581
582       std::stringstream stream;
583       stream << DALI_EXAMPLE_BIN << example.name.c_str();
584       pid_t pid = fork();
585       if( pid == 0)
586       {
587         execlp( stream.str().c_str(), example.name.c_str(), NULL );
588         DALI_ASSERT_ALWAYS(false && "exec failed!");
589       }
590     }
591     mPressedActor.Reset();
592   }
593 }
594
595 void DaliTableView::OnScrollStart( const Dali::Vector3& position )
596 {
597   mScrolling = true;
598
599   PlayAnimation();
600 }
601
602 void DaliTableView::OnScrollComplete( const Dali::Vector3& position )
603 {
604   mScrolling = false;
605
606   // move focus to 1st item of new page
607   FocusManager focusManager = FocusManager::Get();
608   focusManager.SetCurrentFocusActor(mPages[mScrollView.GetCurrentPage()].GetChildAt(0) );
609
610   ApplyCubeEffectToActors();
611 }
612
613 bool DaliTableView::OnScrollTouched( Actor actor, const TouchEvent& event )
614 {
615   const TouchPoint& point = event.GetPoint( 0 );
616   if( TouchPoint::Down == point.state )
617   {
618     mPressedActor = actor;
619   }
620
621   return false;
622 }
623
624 void DaliTableView::ApplyScrollViewEffect()
625 {
626   // Remove old effect if exists.
627
628   if( mScrollViewEffect )
629   {
630     mScrollView.RemoveEffect( mScrollViewEffect );
631   }
632
633   // Just one effect for now
634   SetupInnerPageCubeEffect();
635
636   mScrollView.ApplyEffect( mScrollViewEffect );
637 }
638
639 void DaliTableView::SetupInnerPageCubeEffect()
640 {
641   mScrollViewEffect = ScrollViewCubeEffect::New();
642   mScrollView.SetScrollSnapDuration( EFFECT_SNAP_DURATION );
643   mScrollView.SetScrollFlickDuration( EFFECT_FLICK_DURATION );
644   mScrollView.RemoveConstraintsFromChildren();
645 }
646
647 void DaliTableView::ApplyCubeEffectToActor( Actor actor )
648 {
649   actor.RemoveConstraints();
650
651   ScrollViewCubeEffect cubeEffect = ScrollViewCubeEffect::DownCast(mScrollViewEffect);
652   cubeEffect.ApplyToActor( actor,
653                            ScalePointSize( ( rand() & 1 ) ? ANCHOR_3DEFFECT_STYLE0 : ANCHOR_3DEFFECT_STYLE1 ),
654                            ANGLE_SWING_3DEFFECT,
655                            POSITION_SWING_3DEFFECT * Vector2(Stage::GetCurrent().GetSize()));
656 }
657
658 void DaliTableView::OnKeyEvent( const KeyEvent& event )
659 {
660   if( event.state == KeyEvent::Down )
661   {
662     if ( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
663     {
664       mApplication.Quit();
665     }
666   }
667 }
668
669 void DaliTableView::SetupBackground( Actor bubbleContainer, Actor backgroundLayer, const Vector2& size )
670 {
671   // Create distance field shape.
672   BufferImage distanceField;
673   Size imageSize( 512, 512 );
674   CreateShapeImage( CIRCLE, imageSize, distanceField );
675
676   // Create solid background colour.
677   ImageActor backgroundColourActor = Dali::Toolkit::CreateSolidColorActor( BACKGROUND_COLOR );
678   backgroundColourActor.SetAnchorPoint( AnchorPoint::CENTER );
679   backgroundColourActor.SetParentOrigin( ParentOrigin::CENTER );
680   backgroundColourActor.SetSize( size * BACKGROUND_SIZE_SCALE );
681   backgroundColourActor.SetZ( BACKGROUND_Z );
682   backgroundColourActor.SetPositionInheritanceMode( DONT_INHERIT_POSITION );
683   backgroundLayer.Add( backgroundColourActor );
684
685   // Add bubbles to the bubbleContainer.
686   // Note: The bubbleContainer is parented externally to this function.
687   AddBackgroundActors( bubbleContainer, NUM_BACKGROUND_IMAGES, distanceField, size );
688 }
689
690 void DaliTableView::AddBackgroundActors( Actor layer, int count, BufferImage distanceField, const Dali::Vector2& size )
691 {
692   for( int i = 0; i < count; ++i )
693   {
694     float randSize = Random::Range( 10.0f, 400.0f );
695     float hue = Random::Range( 0.3f, 1.0f );
696     Vector4 randColour( hue, hue*0.5, 0.0f, Random::Range( 0.3f, 0.6f ));
697
698     ImageActor dfActor = ImageActor::New( distanceField );
699     mBackgroundActors.push_back( dfActor );
700     dfActor.SetSize( Vector2( randSize, randSize ) );
701     dfActor.SetParentOrigin( ParentOrigin::CENTER );
702
703     Toolkit::DistanceFieldEffect effect = Toolkit::DistanceFieldEffect::New();
704     dfActor.SetShaderEffect( effect );
705     dfActor.SetColor( randColour );
706     effect.SetOutlineParams( Vector2( 0.55f, 0.00f ) );
707     effect.SetSmoothingEdge( 0.5f );
708     layer.Add( dfActor );
709
710     // Setup animation
711     Vector3 actorPos(
712         Random::Range( -size.x * 0.5f * BACKGROUND_SPREAD_SCALE, size.x * 0.5f * BACKGROUND_SPREAD_SCALE ),
713         Random::Range( -size.y * 0.5f - randSize, size.y * 0.5f + randSize ),
714         Random::Range( BUBBLE_MIN_Z, BUBBLE_MAX_Z ) );
715     dfActor.SetPosition( actorPos );
716
717     // Define bubble horizontal parallax and vertical wrapping
718     Constraint animConstraint = Constraint::New < Vector3 > ( Actor::Property::Position,
719       Source( mScrollView, mScrollView.GetPropertyIndex( ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
720       Dali::ParentSource( Dali::Actor::Property::Size ),
721       AnimateBubbleConstraint( actorPos, Random::Range( -0.85f, 0.25f ), randSize ) );
722     dfActor.ApplyConstraint( animConstraint );
723
724     // Kickoff animation
725     Animation animation = Animation::New( Random::Range( 40.0f, 200.0f ) );
726     KeyFrames keyframes = KeyFrames::New();
727     keyframes.Add( 0.0f, actorPos );
728     Vector3 toPos( actorPos );
729     toPos.y -= ( size.y + randSize );
730     keyframes.Add( 1.0f, toPos );
731     animation.AnimateBetween( Property( dfActor, Actor::Property::Position ), keyframes );
732     animation.SetLooping( true );
733     animation.Play();
734     mBackgroundAnimations.push_back( animation );
735   }
736 }
737
738 void DaliTableView::CreateShapeImage( ShapeType shapeType, const Size& size, BufferImage& distanceFieldOut )
739 {
740   // this bitmap will hold the alpha map for the distance field shader
741   distanceFieldOut = BufferImage::New( size.width, size.height, Pixel::A8 );
742
743   // Generate bit pattern
744   std::vector< unsigned char > imageDataA8;
745   imageDataA8.reserve( size.width * size.height ); // A8
746
747   switch( shapeType )
748   {
749     case CIRCLE:
750       GenerateCircle( size, imageDataA8 );
751       break;
752     case SQUARE:
753       GenerateSquare( size, imageDataA8 );
754       break;
755     default:
756       break;
757   }
758
759   PixelBuffer* buffer = distanceFieldOut.GetBuffer();
760   if( buffer )
761   {
762     GenerateDistanceFieldMap( &imageDataA8[ 0 ], size, buffer, size, 8.0f, size );
763     distanceFieldOut.Update();
764   }
765 }
766
767 void DaliTableView::GenerateSquare( const Size& size, std::vector< unsigned char >& distanceFieldOut )
768 {
769   for( int h = 0; h < size.height; ++h )
770   {
771     for( int w = 0; w < size.width; ++w )
772     {
773       distanceFieldOut.push_back( 0xFF );
774     }
775   }
776 }
777
778 void DaliTableView::GenerateCircle( const Size& size, std::vector< unsigned char >& distanceFieldOut )
779 {
780   const float radius = size.width * 0.5f * size.width * 0.5f;
781   Vector2 center( size.width / 2, size.height / 2 );
782
783   for( int h = 0; h < size.height; ++h )
784   {
785     for( int w = 0; w < size.width; ++w )
786     {
787       Vector2 pos( w, h );
788       Vector2 dist = pos - center;
789
790       if( dist.x * dist.x + dist.y * dist.y > radius )
791       {
792         distanceFieldOut.push_back( 0x00 );
793       }
794       else
795       {
796         distanceFieldOut.push_back( 0xFF );
797       }
798     }
799   }
800 }
801
802 ImageActor DaliTableView::CreateLogo( std::string imagePath )
803 {
804   Image image = ResourceImage::New( imagePath );
805   ImageActor logo = ImageActor::New( image );
806
807   logo.SetAnchorPoint( AnchorPoint::CENTER );
808   logo.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
809
810   return logo;
811 }
812
813 bool DaliTableView::PauseBackgroundAnimation()
814 {
815   PauseAnimation();
816
817   return false;
818 }
819
820 void DaliTableView::PauseAnimation()
821 {
822   if( mBackgroundAnimsPlaying )
823   {
824     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
825     {
826       Animation anim = *animIter;
827
828       anim.Pause();
829     }
830
831     mBackgroundAnimsPlaying = false;
832   }
833 }
834
835 void DaliTableView::PlayAnimation()
836 {
837   if ( !mBackgroundAnimsPlaying )
838   {
839     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
840     {
841       Animation anim = *animIter;
842
843       anim.Play();
844     }
845
846     mBackgroundAnimsPlaying = true;
847   }
848
849   mAnimationTimer.SetInterval( BACKGROUND_ANIMATION_DURATION );
850 }
851
852 Dali::Actor DaliTableView::OnKeyboardPreFocusChange( Dali::Actor current, Dali::Actor proposed, Dali::Toolkit::Control::KeyboardFocusNavigationDirection direction )
853 {
854   Actor nextFocusActor = proposed;
855
856   if ( !current && !proposed  )
857   {
858     // Set the initial focus to the first tile in the current page should be focused.
859     nextFocusActor = mPages[mScrollView.GetCurrentPage()].GetChildAt(0);
860   }
861   else if( !proposed || (proposed && proposed == mScrollViewLayer) )
862   {
863     // ScrollView is being focused but nothing in the current page can be focused further
864     // in the given direction. We should work out which page to scroll to next.
865     int currentPage = mScrollView.GetCurrentPage();
866     int newPage = currentPage;
867     if( direction == Dali::Toolkit::Control::Left )
868     {
869       newPage--;
870     }
871     else if( direction == Dali::Toolkit::Control::Right )
872     {
873       newPage++;
874     }
875
876     newPage = std::max(0, std::min(static_cast<int>(mScrollRulerX->GetTotalPages() - 1), newPage));
877     if( newPage == currentPage )
878     {
879       if( direction == Dali::Toolkit::Control::Left )
880       {
881         newPage = mScrollRulerX->GetTotalPages() - 1;
882       } else if( direction == Dali::Toolkit::Control::Right )
883       {
884         newPage = 0;
885       }
886     }
887
888     // Scroll to the page in the given direction
889     mScrollView.ScrollTo(newPage);
890
891     if( direction == Dali::Toolkit::Control::Left )
892     {
893       // Work out the cell position for the last tile
894       int remainingExamples = mExampleList.size() - newPage * EXAMPLES_PER_PAGE;
895       int rowPos = (remainingExamples >= EXAMPLES_PER_PAGE) ? ROWS_PER_PAGE - 1 : ( (remainingExamples % EXAMPLES_PER_PAGE + EXAMPLES_PER_ROW) / EXAMPLES_PER_ROW - 1 );
896       int colPos = remainingExamples >= EXAMPLES_PER_PAGE ? EXAMPLES_PER_ROW - 1 : ( remainingExamples % EXAMPLES_PER_PAGE - rowPos * EXAMPLES_PER_ROW - 1 );
897
898       // Move the focus to the last tile in the new page.
899       nextFocusActor = mPages[newPage].GetChildAt(colPos * EXAMPLES_PER_ROW + rowPos);
900     }
901     else
902     {
903       // Move the focus to the first tile in the new page.
904       nextFocusActor = mPages[newPage].GetChildAt(0);
905     }
906   }
907
908   return nextFocusActor;
909 }
910
911 void DaliTableView::OnFocusedActorActivated( Dali::Actor activatedActor )
912 {
913   if(activatedActor)
914   {
915     mPressedActor = activatedActor;
916
917     // Activate the current focused actor;
918     TouchEvent touchEventUp;
919     touchEventUp.points.push_back( TouchPoint ( 0, TouchPoint::Up, 0.0f, 0.0f ) );
920     OnTilePressed(mPressedActor, touchEventUp);
921   }
922 }
923
924 bool DaliTableView::OnTileHovered( Actor actor, const HoverEvent& event )
925 {
926   KeyboardFocusManager::Get().SetCurrentFocusActor( actor );
927   return true;
928 }
929
930