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