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