48c06ea5d1fb9bed44592ad2a27452aba898e2f0
[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 int BOTTOM_PADDING_HEIGHT = 40;
57 const int LOGO_MARGIN = 50;
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, 1.0f, 0.8f );          ///< TableView's relative size to the entire stage. The Y value will be calculated.
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 = 20;
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::PointSize         DEFAULT_TEXT_STYLE_POINT_SIZE( 8.0f );
91 const Dali::TextStyle::Weight DEFAULT_TEXT_STYLE_WEIGHT(Dali::TextStyle::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 TextStyle GetTableTextStyle()
108 {
109   TextStyle textStyle;
110   textStyle.SetFontName(TABLE_TEXT_STYLE_FONT_FAMILY);
111   textStyle.SetFontStyle(TABLE_TEXT_STYLE_FONT_STYLE);
112   textStyle.SetFontPointSize( Dali::PointSize(DemoHelper::ScalePointSize(TABLE_TEXT_STYLE_POINT_SIZE)));
113   textStyle.SetWeight(TABLE_TEXT_STYLE_WEIGHT);
114   textStyle.SetTextColor(TABLE_TEXT_STYLE_COLOR);
115   return textStyle;
116 }
117
118 /**
119  * Creates the background image
120  */
121 ImageActor CreateBackground( std::string imagePath )
122 {
123   Image image = Image::New( imagePath );
124   ImageActor background = ImageActor::New( image );
125
126   background.SetAnchorPoint( AnchorPoint::CENTER );
127   background.SetParentOrigin( ParentOrigin::CENTER );
128   background.SetZ( -1.0f );
129
130   return background;
131 }
132
133 // These values depend on the tile image
134 const float IMAGE_BORDER_LEFT = 11.0f;
135 const float IMAGE_BORDER_RIGHT = IMAGE_BORDER_LEFT;
136 const float IMAGE_BORDER_TOP = IMAGE_BORDER_LEFT;
137 const float IMAGE_BORDER_BOTTOM = IMAGE_BORDER_LEFT;
138
139 /**
140  * TableViewVisibilityConstraint
141  */
142 struct TableViewVisibilityConstraint
143 {
144   bool operator()( const bool& current,
145               const PropertyInput& pagePositionProperty,
146               const PropertyInput& pageSizeProperty )
147   {
148     // Only the tableview in the current page should be visible.
149     const Vector3& pagePosition = pagePositionProperty.GetVector3();
150     const Vector3& pageSize = pageSizeProperty.GetVector3();
151     return fabsf( pagePosition.x ) < pageSize.x;
152   }
153 };
154
155 /**
156  * Constraint to wrap an actor in y that is moving vertically
157  */
158 Vector3 ShapeMovementConstraint( const Vector3& current,
159                          const PropertyInput& shapeSizeProperty,
160                          const PropertyInput& parentSizeProperty )
161 {
162   const Vector3& shapeSize = shapeSizeProperty.GetVector3();
163   const Vector3& parentSize = parentSizeProperty.GetVector3();
164
165   Vector3 pos( current );
166   if( pos.y + shapeSize.y * 0.5f < -parentSize.y * 0.5f )
167   {
168     pos.y += parentSize.y + shapeSize.y;
169   }
170
171   return pos;
172 }
173
174 /**
175  * Constraint to return a position for the background based on the scroll value
176  */
177 struct AnimScrollConstraint
178 {
179 public:
180
181   AnimScrollConstraint( const Vector3& initialPos, float scale )
182       : mInitialPos( initialPos ),
183         mScale( scale )
184   {
185
186   }
187
188   Vector3 operator()( const Vector3& current, const PropertyInput& scrollProperty )
189   {
190     float scrollPos = scrollProperty.GetVector3().x;
191
192     return mInitialPos + Vector3( -scrollPos * mScale, 0.0f, 0.0f );
193   }
194
195 private:
196   Vector3 mInitialPos;
197   float mScale;
198 };
199
200 /**
201  * Constraint to return a tracked world position added to the constant local position
202  */
203 struct TranslateLocalConstraint
204 {
205 public:
206
207   TranslateLocalConstraint( const Vector3& localPos )
208       : mLocalPos( localPos )
209   {
210   }
211
212   Vector3 operator()( const Vector3& current, const PropertyInput& pagePosProperty )
213   {
214     Vector3 worldPos = pagePosProperty.GetVector3();
215
216     return ( worldPos + mLocalPos );
217   }
218
219 private:
220   Vector3 mLocalPos;
221 };
222
223
224 bool CompareByTitle( const Example& lhs, const Example& rhs )
225 {
226   return lhs.title < rhs.title;
227 }
228
229 } // namespace
230
231 DaliTableView::DaliTableView( Application& application )
232     : mApplication( application ),
233         mScrolling( false ),
234         mBackgroundImagePath( DEFAULT_BACKGROUND_IMAGE_PATH ),
235         mSortAlphabetically( false ),
236         mBackgroundAnimsPlaying( false )
237 {
238   application.InitSignal().Connect( this, &DaliTableView::Initialize );
239 }
240
241 DaliTableView::~DaliTableView()
242 {
243 }
244
245 void DaliTableView::AddExample( Example example )
246 {
247   mExampleList.push_back( example );
248   mExampleMap[ example.name ] = example;
249 }
250
251 void DaliTableView::SetBackgroundPath( std::string imagePath )
252 {
253   mBackgroundImagePath = imagePath;
254 }
255
256 void DaliTableView::SortAlphabetically( bool sortAlphabetically )
257 {
258   mSortAlphabetically = sortAlphabetically;
259 }
260
261 void DaliTableView::Initialize( Application& application )
262 {
263   Stage::GetCurrent().KeyEventSignal().Connect( this, &DaliTableView::OnKeyEvent );
264
265   const Vector2 stageSize = Stage::GetCurrent().GetSize();
266
267   // Background
268   mBackground = CreateBackground( mBackgroundImagePath );
269   // set same size as parent actor
270   mBackground.SetSize( stageSize );
271   Stage::GetCurrent().Add( mBackground );
272
273   // Render entire content as overlays, as is all on same 2D plane.
274   mRootActor = TableView::New( 4, 1 );
275   mRootActor.SetAnchorPoint( AnchorPoint::CENTER );
276   mRootActor.SetParentOrigin( ParentOrigin::CENTER );
277   Stage::GetCurrent().Add( mRootActor );
278
279   // Toolbar at top
280   Dali::Toolkit::ToolBar toolbar;
281   Dali::Layer toolBarLayer = DemoHelper::CreateToolbar(toolbar,
282                                                        DEFAULT_TOOLBAR_IMAGE_PATH,
283                                                        DEFAULT_TOOLBAR_TEXT,
284                                                        DemoHelper::DEFAULT_VIEW_STYLE,
285                                                        DemoHelper::GetDefaultTextStyle());
286
287   mRootActor.AddChild( toolBarLayer, TableView::CellPosition( 0, 0 ) );
288   const float toolbarHeight = DemoHelper::DEFAULT_VIEW_STYLE.mToolBarHeight;
289   mRootActor.SetFixedHeight( 0, toolbarHeight );
290
291   // Add logo
292   mLogo = CreateLogo( LOGO_PATH );
293   const float logoHeight = mLogo.GetImage().GetHeight() + DP(LOGO_MARGIN);
294   mRootActor.SetFixedHeight( 1, logoHeight );
295
296   mButtonsPageRelativeSize = Vector3( TABLE_RELATIVE_SIZE.x, ( stageSize.height - toolbarHeight - logoHeight - DP( BOTTOM_PADDING_HEIGHT ) ) / stageSize.height, TABLE_RELATIVE_SIZE.z );
297
298   mRootActor.SetFixedHeight( 2, mButtonsPageRelativeSize.y * stageSize.height );
299
300   Alignment alignment = Alignment::New();
301   alignment.Add(mLogo);
302   mRootActor.AddChild( alignment, TableView::CellPosition( 1, 0 ) );
303
304   // scrollview occupying the majority of the screen
305   mScrollView = ScrollView::New();
306
307   mScrollView.SetAnchorPoint( AnchorPoint::CENTER );
308   mScrollView.SetParentOrigin( ParentOrigin::CENTER );
309   mScrollView.ApplyConstraint( Dali::Constraint::New<Dali::Vector3>( Dali::Actor::SIZE, Dali::ParentSource( Dali::Actor::SIZE ),
310                                                                      Dali::RelativeToConstraint( SCROLLVIEW_RELATIVE_SIZE ) ) );
311   mScrollView.SetAxisAutoLock( true );
312   mScrollView.ScrollCompletedSignal().Connect( this, &DaliTableView::OnScrollComplete );
313   mScrollView.ScrollStartedSignal().Connect( this, &DaliTableView::OnScrollStart );
314   mScrollView.TouchedSignal().Connect( this, &DaliTableView::OnScrollTouched );
315
316   mScrollViewLayer = Layer::New();
317   mScrollViewLayer.SetAnchorPoint( AnchorPoint::CENTER );
318   mScrollViewLayer.SetParentOrigin( ParentOrigin::CENTER );
319   mScrollViewLayer.SetDrawMode( DrawMode::OVERLAY );
320
321   // Populate background and bubbles - needs to be scrollViewLayer so scroll ends show
322   SetupBackground( mScrollView, mScrollViewLayer, stageSize );
323
324   mScrollViewLayer.Add( mScrollView );
325   mRootActor.AddChild( mScrollViewLayer, TableView::CellPosition( 2, 0 ) );
326
327   // Add scroll view effect and setup constraints on pages
328   ApplyScrollViewEffect();
329
330   // Add pages and tiles
331   Populate();
332
333   // Remove constraints for inner cube effect
334   ApplyCubeEffectToActors();
335
336   // Set initial orientation
337   unsigned int degrees = application.GetOrientation().GetDegrees();
338   Rotate( degrees );
339
340   Dali::Window winHandle = application.GetWindow();
341   winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT );
342   winHandle.RemoveAvailableOrientation( Dali::Window::LANDSCAPE );
343   winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT_INVERSE );
344   winHandle.RemoveAvailableOrientation( Dali::Window::LANDSCAPE_INVERSE );
345
346   Dali::Orientation orientation = winHandle.GetOrientation();
347   orientation.ChangedSignal().Connect( this, &DaliTableView::OrientationChanged );
348
349   winHandle.ShowIndicator( Dali::Window::INVISIBLE );
350
351   //
352   mAnimationTimer = Timer::New( BACKGROUND_ANIMATION_DURATION );
353   mAnimationTimer.TickSignal().Connect( this, &DaliTableView::PauseBackgroundAnimation );
354   mAnimationTimer.Start();
355   mBackgroundAnimsPlaying = true;
356
357   KeyboardFocusManager::Get().PreFocusChangeSignal().Connect( this, &DaliTableView::OnKeyboardPreFocusChange );
358   KeyboardFocusManager::Get().FocusedActorActivatedSignal().Connect( this, &DaliTableView::OnFocusedActorActivated );
359 }
360
361 void DaliTableView::ApplyCubeEffectToActors()
362 {
363   for( ActorIter pageIter = mPages.begin(); pageIter != mPages.end(); ++pageIter )
364   {
365     Actor page = *pageIter;
366
367     unsigned int numChildren = page.GetChildCount();
368     Actor pageActor = page;
369     for( unsigned int i=0; i<numChildren; ++i)
370     {
371       // Remove old effect's manual constraints.
372       Actor child = pageActor.GetChildAt(i);
373       if( child )
374       {
375         ApplyCubeEffectToActor( child );
376       }
377     }
378   }
379 }
380 void DaliTableView::Populate()
381 {
382   const Vector2 stageSize = Stage::GetCurrent().GetSize();
383
384   mTotalPages = ( mExampleList.size() + EXAMPLES_PER_PAGE - 1 ) / EXAMPLES_PER_PAGE;
385
386   // Populate ScrollView.
387   if( mExampleList.size() > 0 )
388   {
389     if( mSortAlphabetically )
390     {
391       sort( mExampleList.begin(), mExampleList.end(), CompareByTitle );
392     }
393
394     unsigned int exampleCount = 0;
395     ExampleListConstIter iter = mExampleList.begin();
396
397     for( int t = 0; t < mTotalPages; t++ )
398     {
399       // Create Table. (contains up to 9 Examples)
400       Actor page = Actor::New();
401
402       // Add tableView to container.
403       mScrollView.Add( page );
404
405       page.SetAnchorPoint( AnchorPoint::CENTER );
406       page.SetParentOrigin( ParentOrigin::CENTER );
407       page.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
408
409       // add cells to table
410       const float margin = 4.0f;
411
412       // Calculate the number of images going across (columns) within a page, according to the screen resolution and dpi.
413       const Size tileSize((stageSize.x * mButtonsPageRelativeSize.x / EXAMPLES_PER_ROW) - margin, (stageSize.y * mButtonsPageRelativeSize.y / ROWS_PER_PAGE) - margin );
414
415       for(int row = 0; row < ROWS_PER_PAGE; row++)
416       {
417         for(int column = 0; column < EXAMPLES_PER_ROW; column++)
418         {
419           const Example& example = ( *iter );
420
421           Actor tile = CreateTile( example.name, example.title, tileSize, true );
422           FocusManager focusManager = FocusManager::Get();
423           focusManager.SetFocusOrder( tile, ++exampleCount );
424           focusManager.SetAccessibilityAttribute( tile, Dali::Toolkit::FocusManager::ACCESSIBILITY_LABEL,
425                                                   example.title );
426           focusManager.SetAccessibilityAttribute( tile, Dali::Toolkit::FocusManager::ACCESSIBILITY_TRAIT, "Tile" );
427           focusManager.SetAccessibilityAttribute( tile, Dali::Toolkit::FocusManager::ACCESSIBILITY_HINT,
428                                                   "You can run this example" );
429
430           Vector3 position( margin * 0.5f + (tileSize.x + margin) * column - stageSize.width * mButtonsPageRelativeSize.x * 0.5f,
431                            margin * 0.5f + (tileSize.y + margin) * row - stageSize.height * mButtonsPageRelativeSize.y * 0.5f,
432                             0.0f);
433           tile.SetPosition( position + Vector3( tileSize.x, tileSize.y, 0.0f ) * 0.5f );
434           tile.SetSize( tileSize );
435           page.Add( tile );
436
437           iter++;
438
439           if( iter == mExampleList.end() )
440           {
441             break;
442           }
443         }
444
445         if( iter == mExampleList.end() )
446         {
447           break;
448         }
449       }
450
451       // Set tableview position
452       Vector3 pagePos( stageSize.x * mButtonsPageRelativeSize.x * t, 0.0f, 0.0f );
453       page.SetPosition( pagePos );
454
455       mPages.push_back( page );
456
457       if( iter == mExampleList.end() )
458       {
459         break;
460       }
461     }
462   }
463
464   // Update Ruler info.
465   mScrollRulerX = new FixedRuler( stageSize.width * mButtonsPageRelativeSize.x );
466   mScrollRulerY = new DefaultRuler();
467   mScrollRulerX->SetDomain( RulerDomain( 0.0f, mTotalPages * stageSize.width * mButtonsPageRelativeSize.x, true ) );
468   mScrollRulerY->Disable();
469   mScrollView.SetRulerX( mScrollRulerX );
470   mScrollView.SetRulerY( mScrollRulerY );
471 }
472
473 void DaliTableView::OrientationChanged( Orientation orientation )
474 {
475   // TODO: Implement if orientation change required
476 }
477
478 void DaliTableView::Rotate( unsigned int degrees )
479 {
480   // Resize the root actor
481   Vector2 stageSize = Stage::GetCurrent().GetSize();
482   Vector3 targetSize( stageSize.x, stageSize.y, 1.0f );
483
484   if( degrees == 90 || degrees == 270 )
485   {
486     targetSize = Vector3( stageSize.y, stageSize.x, 1.0f );
487   }
488
489   if( mRotateAnimation )
490   {
491     mRotateAnimation.Stop();
492     mRotateAnimation.Clear();
493   }
494
495   mRotateAnimation = Animation::New( ROTATE_ANIMATION_TIME );
496   mRotateAnimation.RotateTo( mRootActor, Degree( 360 - degrees ), Vector3::ZAXIS, AlphaFunctions::EaseOut );
497   mRotateAnimation.Resize( mRootActor, targetSize, AlphaFunctions::EaseOut );
498   mRotateAnimation.Play();
499 }
500
501 Actor DaliTableView::CreateTile( const std::string& name, const std::string& title, const Size& parentSize, bool addBackground )
502 {
503   Actor tile = Actor::New();
504   tile.SetName( name );
505   tile.SetAnchorPoint( AnchorPoint::CENTER );
506   tile.SetParentOrigin( ParentOrigin::CENTER );
507
508   Actor content = Actor::New();
509   content.SetAnchorPoint( AnchorPoint::CENTER );
510   content.SetParentOrigin( ParentOrigin::CENTER );
511   content.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
512   tile.Add(content);
513
514   // create background image
515   if( addBackground )
516   {
517     Image bg = Image::New( TILE_BACKGROUND );
518     ImageActor image = ImageActor::New( bg );
519     image.SetAnchorPoint( AnchorPoint::CENTER );
520     image.SetParentOrigin( ParentOrigin::CENTER );
521     // make the image 100% of tile
522     image.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
523     // move image back to get text appear in front
524     image.SetZ( -1 );
525     image.SetStyle( ImageActor::STYLE_NINE_PATCH );
526     image.SetNinePatchBorder( Vector4( IMAGE_BORDER_LEFT, IMAGE_BORDER_TOP, IMAGE_BORDER_RIGHT, IMAGE_BORDER_BOTTOM ) );
527
528     content.Add( image );
529
530     // Add stencil
531     ImageActor stencil = NewStencilImage();
532     stencil.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
533     image.Add( stencil );
534   }
535
536   TextView text = TextView::New( title );
537   text.SetAnchorPoint( AnchorPoint::CENTER );
538   text.SetParentOrigin( ParentOrigin::CENTER );
539   text.SetWidthExceedPolicy( Toolkit::TextView::ShrinkToFit );
540   text.SetMultilinePolicy( Toolkit::TextView::SplitByWord );
541   text.SetLineJustification( Toolkit::TextView::Center );
542   text.SetTextAlignment( Toolkit::Alignment::Type( Alignment::HorizontalCenter | Alignment::VerticalCenter ) );
543   text.SetColor( Color::WHITE );
544   text.SetZ( 1 );
545   // make the text 90% of tile
546   text.SetSize( 0.9f * parentSize.width, 0.9f * parentSize.height );
547   text.SetStyleToCurrentText( GetTableTextStyle() );
548   text.SetSnapshotModeEnabled( false );
549   content.Add( text );
550
551   // Set the tile to be keyboard focusable
552   tile.SetKeyboardFocusable(true);
553
554   // connect to the touch events
555   tile.TouchedSignal().Connect( this, &DaliTableView::OnTilePressed );
556   tile.HoveredSignal().Connect( this, &DaliTableView::OnTileHovered );
557
558   return tile;
559 }
560
561 ImageActor DaliTableView::NewStencilImage()
562 {
563   Image alpha = Image::New( TILE_BACKGROUND_ALPHA );
564
565   ImageActor stencilActor = ImageActor::New( alpha );
566   stencilActor.SetStyle( ImageActor::STYLE_NINE_PATCH );
567   stencilActor.SetNinePatchBorder( Vector4( IMAGE_BORDER_LEFT, IMAGE_BORDER_TOP, IMAGE_BORDER_RIGHT, IMAGE_BORDER_BOTTOM ) );
568
569   stencilActor.SetParentOrigin( ParentOrigin::CENTER );
570   stencilActor.SetAnchorPoint( AnchorPoint::CENTER );
571   stencilActor.SetDrawMode( DrawMode::STENCIL );
572
573   Dali::ShaderEffect shaderEffect = AlphaDiscardEffect::New();
574   stencilActor.SetShaderEffect( shaderEffect );
575
576   return stencilActor;
577 }
578
579 bool DaliTableView::OnTilePressed( Actor actor, const TouchEvent& event )
580 {
581   bool consumed = false;
582
583   const TouchPoint& point = event.GetPoint( 0 );
584   if( TouchPoint::Down == point.state )
585   {
586     mPressedActor = actor;
587     consumed = true;
588   }
589
590   // A button press is only valid if the Down & Up events
591   // both occurred within the button.
592   if( ( TouchPoint::Up == point.state ) &&
593       ( mPressedActor == actor ) )
594   {
595     std::string name = actor.GetName();
596     ExampleMapConstIter iter = mExampleMap.find( name );
597
598     FocusManager focusManager = FocusManager::Get();
599
600     if( iter != mExampleMap.end() )
601     {
602       // ignore Example button presses when scrolling or button animating.
603       if( ( !mScrolling ) && ( !mPressedAnimation ) )
604       {
605         // do nothing, until pressed animation finished.
606         consumed = true;
607       }
608     }
609
610     if( consumed )
611     {
612       mPressedAnimation = Animation::New( BUTTON_PRESS_ANIMATION_TIME );
613       mPressedAnimation.SetEndAction( Animation::Discard );
614
615       // scale the content actor within the Tile, as to not affect the placement within the Table.
616       Actor content = actor.GetChildAt(0);
617       mPressedAnimation.ScaleTo( content, Vector3( 0.9f, 0.9f, 1.0f ), AlphaFunctions::EaseInOut, 0.0f,
618                                  BUTTON_PRESS_ANIMATION_TIME * 0.5f );
619       mPressedAnimation.ScaleTo( content, Vector3::ONE, AlphaFunctions::EaseInOut, BUTTON_PRESS_ANIMATION_TIME * 0.5f,
620                                  BUTTON_PRESS_ANIMATION_TIME * 0.5f );
621       mPressedAnimation.Play();
622       mPressedAnimation.FinishedSignal().Connect( this, &DaliTableView::OnPressedAnimationFinished );
623     }
624   }
625   return consumed;
626 }
627
628 void DaliTableView::OnPressedAnimationFinished( Dali::Animation& source )
629 {
630   mPressedAnimation.Reset();
631   if( mPressedActor )
632   {
633     std::string name = mPressedActor.GetName();
634     ExampleMapConstIter iter = mExampleMap.find( name );
635
636     if( iter == mExampleMap.end() )
637     {
638       if( name == BUTTON_QUIT )
639       {
640         // Move focus to the OK button
641         FocusManager focusManager = FocusManager::Get();
642
643         // Enable the group mode and wrap mode
644         focusManager.SetGroupMode( true );
645         focusManager.SetWrapMode( true );
646       }
647     }
648     else
649     {
650       const Example& example( iter->second );
651
652       std::stringstream stream;
653       stream << DALI_EXAMPLE_BIN << example.name.c_str();
654       pid_t pid = fork();
655       if( pid == 0)
656       {
657         execlp( stream.str().c_str(), example.name.c_str(), NULL );
658         DALI_ASSERT_ALWAYS(false && "exec failed!");
659       }
660     }
661     mPressedActor.Reset();
662   }
663 }
664
665 void DaliTableView::OnScrollStart( const Dali::Vector3& position )
666 {
667   mScrolling = true;
668
669   PlayAnimation();
670 }
671
672 void DaliTableView::OnScrollComplete( const Dali::Vector3& position )
673 {
674   mScrolling = false;
675
676   // move focus to 1st item of new page
677   FocusManager focusManager = FocusManager::Get();
678   focusManager.SetCurrentFocusActor(mPages[mScrollView.GetCurrentPage()].GetChildAt(0) );
679
680   ApplyCubeEffectToActors();
681 }
682
683 bool DaliTableView::OnScrollTouched( Actor actor, const TouchEvent& event )
684 {
685   const TouchPoint& point = event.GetPoint( 0 );
686   if( TouchPoint::Down == point.state )
687   {
688     mPressedActor = actor;
689   }
690
691   return false;
692 }
693
694 void DaliTableView::ApplyScrollViewEffect()
695 {
696   // Remove old effect if exists.
697
698   if( mScrollViewEffect )
699   {
700     mScrollView.RemoveEffect( mScrollViewEffect );
701   }
702
703   // Just one effect for now
704   SetupInnerPageCubeEffect();
705
706   mScrollView.ApplyEffect( mScrollViewEffect );
707 }
708
709 void DaliTableView::SetupInnerPageCubeEffect()
710 {
711   mScrollViewEffect = ScrollViewCubeEffect::New();
712   mScrollView.SetScrollSnapDuration( EFFECT_SNAP_DURATION );
713   mScrollView.SetScrollFlickDuration( EFFECT_FLICK_DURATION );
714   mScrollView.RemoveConstraintsFromChildren();
715 }
716
717 void DaliTableView::ApplyCubeEffectToActor( Actor actor )
718 {
719   actor.RemoveConstraints();
720
721   ScrollViewCubeEffect cubeEffect = ScrollViewCubeEffect::DownCast(mScrollViewEffect);
722   cubeEffect.ApplyToActor( actor,
723                            ScalePointSize( ( rand() & 1 ) ? ANCHOR_3DEFFECT_STYLE0 : ANCHOR_3DEFFECT_STYLE1 ),
724                            ANGLE_SWING_3DEFFECT,
725                            POSITION_SWING_3DEFFECT * Vector2(Stage::GetCurrent().GetSize()));
726 }
727
728 void DaliTableView::OnKeyEvent( const KeyEvent& event )
729 {
730   if( event.state == KeyEvent::Down )
731   {
732     if ( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
733     {
734       mApplication.Quit();
735     }
736   }
737 }
738
739 Actor CreateBackgroundActor( const Vector2& size )
740 {
741   Actor layer = Actor::New();
742   layer.SetAnchorPoint( AnchorPoint::CENTER );
743   layer.SetParentOrigin( ParentOrigin::CENTER );
744   layer.SetSize( size );
745   return layer;
746 }
747
748 void DaliTableView::SetupBackground( Actor bubbleLayer, Actor backgroundLayer, const Vector2& size )
749 {
750   // Create distance field shape
751   BitmapImage distanceField;
752   Size imageSize( 512, 512 );
753   CreateShapeImage( CIRCLE, imageSize, distanceField );
754
755   // Create layers
756   Actor backgroundAnimLayer0 = CreateBackgroundActor( size );
757   Actor backgroundAnimLayer1 = CreateBackgroundActor( size );
758   Actor backgroundAnimLayer2 = CreateBackgroundActor( size );
759
760   // Add constraints
761   Constraint animConstraint0 = Constraint::New < Vector3 > ( Actor::POSITION,
762       Source( mScrollView, mScrollView.GetPropertyIndex( ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
763       AnimScrollConstraint( backgroundAnimLayer0.GetCurrentPosition(), 0.75f ) );
764   backgroundAnimLayer0.ApplyConstraint( animConstraint0 );
765
766   Constraint animConstraint1 = Constraint::New < Vector3 > ( Actor::POSITION,
767       Source( mScrollView, mScrollView.GetPropertyIndex( ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
768       AnimScrollConstraint( backgroundAnimLayer1.GetCurrentPosition(), 0.5f ) );
769   backgroundAnimLayer1.ApplyConstraint( animConstraint1 );
770
771   Constraint animConstraint2 = Constraint::New < Vector3 > ( Actor::POSITION,
772       Source( mScrollView, mScrollView.GetPropertyIndex( ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
773       AnimScrollConstraint( backgroundAnimLayer2.GetCurrentPosition(), 0.25f ) );
774   backgroundAnimLayer2.ApplyConstraint( animConstraint2 );
775
776   // Background
777   ImageActor layer = Dali::Toolkit::CreateSolidColorActor( BACKGROUND_COLOR );
778   layer.SetAnchorPoint( AnchorPoint::CENTER );
779   layer.SetParentOrigin( ParentOrigin::CENTER );
780   layer.SetSize( size * BACKGROUND_SIZE_SCALE );
781   layer.SetZ( BACKGROUND_Z );
782   layer.SetPositionInheritanceMode( DONT_INHERIT_POSITION );
783   backgroundLayer.Add( layer );
784
785   // Parent the layers
786   bubbleLayer.Add( backgroundAnimLayer0 );
787   bubbleLayer.Add( backgroundAnimLayer1 );
788   bubbleLayer.Add( backgroundAnimLayer2 );
789
790   // Add all the children
791   AddBackgroundActors( backgroundAnimLayer0, NUM_BACKGROUND_IMAGES / 3, distanceField, size );
792   AddBackgroundActors( backgroundAnimLayer1, NUM_BACKGROUND_IMAGES / 3, distanceField, size );
793   AddBackgroundActors( backgroundAnimLayer2, NUM_BACKGROUND_IMAGES / 3, distanceField, size );
794 }
795
796 void DaliTableView::AddBackgroundActors( Actor layer, int count, BitmapImage distanceField, const Dali::Vector2& size )
797 {
798   for( int i = 0; i < count; ++i )
799   {
800     float randSize = Random::Range( 10.0f, 400.0f );
801     float hue = Random::Range( 0.3f, 1.0f );
802     Vector4 randColour( hue, hue*0.5, 0.0f, Random::Range( 0.3f, 0.6f ));
803
804     ImageActor dfActor = ImageActor::New( distanceField );
805     mBackgroundActors.push_back( dfActor );
806     dfActor.SetSize( Vector2( randSize, randSize ) );
807     dfActor.SetParentOrigin( ParentOrigin::CENTER );
808
809     Toolkit::DistanceFieldEffect effect = Toolkit::DistanceFieldEffect::New();
810     dfActor.SetShaderEffect( effect );
811     dfActor.SetColor( randColour );
812     effect.SetOutlineParams( Vector2( 0.55f, 0.00f ) );
813     effect.SetSmoothingEdge( 0.5f );
814     layer.Add( dfActor );
815
816     // Setup animation
817     Vector3 actorPos(
818         Random::Range( -size.x * 0.5f * BACKGROUND_SPREAD_SCALE, size.x * 0.5f * BACKGROUND_SPREAD_SCALE ),
819         Random::Range( -size.y * 0.5f - randSize, size.y * 0.5f + randSize ),
820         Random::Range( BUBBLE_MIN_Z, BUBBLE_MAX_Z ) );
821     dfActor.SetPosition( actorPos );
822
823     Constraint movementConstraint = Constraint::New < Vector3 > ( Actor::POSITION,
824         LocalSource( Actor::SIZE ),
825         ParentSource( Actor::SIZE ),
826         ShapeMovementConstraint );
827     dfActor.ApplyConstraint( movementConstraint );
828
829     // Kickoff animation
830     Animation animation = Animation::New( Random::Range( 40.0f, 200.0f ) );
831     KeyFrames keyframes = KeyFrames::New();
832     keyframes.Add( 0.0f, actorPos );
833     Vector3 toPos( actorPos );
834     toPos.y -= ( size.y + randSize );
835     keyframes.Add( 1.0f, toPos );
836     animation.AnimateBetween( Property( dfActor, Actor::POSITION ), keyframes );
837     animation.SetLooping( true );
838     animation.Play();
839     mBackgroundAnimations.push_back( animation );
840   }
841 }
842
843 void DaliTableView::CreateShapeImage( ShapeType shapeType, const Size& size, BitmapImage& distanceFieldOut )
844 {
845   // this bitmap will hold the alpha map for the distance field shader
846   distanceFieldOut = BitmapImage::New( size.width, size.height, Pixel::A8 );
847
848   // Generate bit pattern
849   std::vector< unsigned char > imageDataA8;
850   imageDataA8.reserve( size.width * size.height ); // A8
851
852   switch( shapeType )
853   {
854     case CIRCLE:
855       GenerateCircle( size, imageDataA8 );
856       break;
857     case SQUARE:
858       GenerateSquare( size, imageDataA8 );
859       break;
860     default:
861       break;
862   }
863
864   PixelBuffer* buffer = distanceFieldOut.GetBuffer();
865   if( buffer )
866   {
867     GenerateDistanceFieldMap( &imageDataA8[ 0 ], size, buffer, size, 8.0f, size );
868     distanceFieldOut.Update();
869   }
870 }
871
872 void DaliTableView::GenerateSquare( const Size& size, std::vector< unsigned char >& distanceFieldOut )
873 {
874   for( int h = 0; h < size.height; ++h )
875   {
876     for( int w = 0; w < size.width; ++w )
877     {
878       distanceFieldOut.push_back( 0xFF );
879     }
880   }
881 }
882
883 void DaliTableView::GenerateCircle( const Size& size, std::vector< unsigned char >& distanceFieldOut )
884 {
885   const float radius = size.width * 0.5f * size.width * 0.5f;
886   Vector2 center( size.width / 2, size.height / 2 );
887
888   for( int h = 0; h < size.height; ++h )
889   {
890     for( int w = 0; w < size.width; ++w )
891     {
892       Vector2 pos( w, h );
893       Vector2 dist = pos - center;
894
895       if( dist.x * dist.x + dist.y * dist.y > radius )
896       {
897         distanceFieldOut.push_back( 0x00 );
898       }
899       else
900       {
901         distanceFieldOut.push_back( 0xFF );
902       }
903     }
904   }
905 }
906
907 ImageActor DaliTableView::CreateLogo( std::string imagePath )
908 {
909   Image image = Image::New( imagePath );
910   ImageActor logo = ImageActor::New( image );
911
912   logo.SetAnchorPoint( AnchorPoint::CENTER );
913   logo.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
914
915   return logo;
916 }
917
918 bool DaliTableView::PauseBackgroundAnimation()
919 {
920   PauseAnimation();
921
922   return false;
923 }
924
925 void DaliTableView::PauseAnimation()
926 {
927   if( mBackgroundAnimsPlaying )
928   {
929     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
930     {
931       Animation anim = *animIter;
932
933       anim.Pause();
934     }
935
936     mBackgroundAnimsPlaying = false;
937   }
938 }
939
940 void DaliTableView::PlayAnimation()
941 {
942   if ( !mBackgroundAnimsPlaying )
943   {
944     for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter )
945     {
946       Animation anim = *animIter;
947
948       anim.Play();
949     }
950
951     mBackgroundAnimsPlaying = true;
952   }
953
954   mAnimationTimer.SetInterval( BACKGROUND_ANIMATION_DURATION );
955 }
956
957 Dali::Actor DaliTableView::OnKeyboardPreFocusChange( Dali::Actor current, Dali::Actor proposed, Dali::Toolkit::Control::KeyboardFocusNavigationDirection direction )
958 {
959   Actor nextFocusActor = proposed;
960
961   if ( !current && !proposed  )
962   {
963     // Set the initial focus to the first tile in the current page should be focused.
964     nextFocusActor = mPages[mScrollView.GetCurrentPage()].GetChildAt(0);
965   }
966   else if( !proposed || (proposed && proposed == mScrollViewLayer) )
967   {
968     // ScrollView is being focused but nothing in the current page can be focused further
969     // in the given direction. We should work out which page to scroll to next.
970     int currentPage = mScrollView.GetCurrentPage();
971     int newPage = currentPage;
972     if( direction == Dali::Toolkit::Control::Left )
973     {
974       newPage--;
975     }
976     else if( direction == Dali::Toolkit::Control::Right )
977     {
978       newPage++;
979     }
980
981     newPage = std::max(0, std::min(static_cast<int>(mScrollRulerX->GetTotalPages() - 1), newPage));
982     if( newPage == currentPage )
983     {
984       if( direction == Dali::Toolkit::Control::Left )
985       {
986         newPage = mScrollRulerX->GetTotalPages() - 1;
987       } else if( direction == Dali::Toolkit::Control::Right )
988       {
989         newPage = 0;
990       }
991     }
992
993     // Scroll to the page in the given direction
994     mScrollView.ScrollTo(newPage);
995
996     if( direction == Dali::Toolkit::Control::Left )
997     {
998       // Work out the cell position for the last tile
999       int remainingExamples = mExampleList.size() - newPage * EXAMPLES_PER_PAGE;
1000       int rowPos = (remainingExamples >= EXAMPLES_PER_PAGE) ? ROWS_PER_PAGE - 1 : ( (remainingExamples % EXAMPLES_PER_PAGE + EXAMPLES_PER_ROW) / EXAMPLES_PER_ROW - 1 );
1001       int colPos = remainingExamples >= EXAMPLES_PER_PAGE ? EXAMPLES_PER_ROW - 1 : ( remainingExamples % EXAMPLES_PER_PAGE - rowPos * EXAMPLES_PER_ROW - 1 );
1002
1003       // Move the focus to the last tile in the new page.
1004       nextFocusActor = mPages[newPage].GetChildAt(colPos * EXAMPLES_PER_ROW + rowPos);
1005     }
1006     else
1007     {
1008       // Move the focus to the first tile in the new page.
1009       nextFocusActor = mPages[newPage].GetChildAt(0);
1010     }
1011   }
1012
1013   return nextFocusActor;
1014 }
1015
1016 void DaliTableView::OnFocusedActorActivated( Dali::Actor activatedActor )
1017 {
1018   if(activatedActor)
1019   {
1020     mPressedActor = activatedActor;
1021
1022     // Activate the current focused actor;
1023     TouchEvent touchEventUp;
1024     touchEventUp.points.push_back( TouchPoint ( 0, TouchPoint::Up, 0.0f, 0.0f ) );
1025     OnTilePressed(mPressedActor, touchEventUp);
1026   }
1027 }
1028
1029 bool DaliTableView::OnTileHovered( Actor actor, const HoverEvent& event )
1030 {
1031   KeyboardFocusManager::Get().SetCurrentFocusActor( actor );
1032   return true;
1033 }
1034
1035