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