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