[Tizen][ATSPI] Accessibility initial implementation
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / popup / popup-impl.cpp
1 /*
2  * Copyright (c) 2017 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-toolkit/internal/controls/popup/popup-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 #include <dali/devel-api/adaptor-framework/physical-keyboard.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/adaptor-framework/key.h>
27 #include <dali/public-api/animation/constraints.h>
28 #include <dali/public-api/common/stage.h>
29 #include <dali/public-api/events/key-event.h>
30 #include <dali/public-api/events/touch-data.h>
31 #include <dali/public-api/object/type-registry.h>
32 #include <dali/devel-api/scripting/scripting.h>
33 #include <dali/devel-api/actors/actor-devel.h>
34 #include <dali/public-api/size-negotiation/relayout-container.h>
35
36 // INTERNAL INCLUDES
37 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
38 #include <dali-toolkit/public-api/controls/control-impl.h>
39 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
40 #include <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
41 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
42 #include <dali-toolkit/public-api/visuals/visual-properties.h>
43 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
44
45 using namespace Dali;
46
47 namespace Dali
48 {
49
50 namespace Toolkit
51 {
52
53 namespace Internal
54 {
55
56 namespace
57 {
58
59 /**
60  * Creation function for main Popup type.
61  * @return Handle to the new popup object.
62  */
63 BaseHandle Create()
64 {
65   return Toolkit::Popup::New();
66 }
67
68 // Toast style defaults.
69 const int          DEFAULT_TOAST_AUTO_HIDE_DELAY = 3000;                                    ///< Toast will auto-hide after 3000ms (3 seconds)
70 const float        DEFAULT_TOAST_TRANSITION_TIME = 0.65f;                                   ///< Default time the toast Popup will take to show and hide.
71 const Vector3      DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN( 0.5f, 0.94f, 0.5f );                 ///< This is similar to BOTTOM_CENTER, but vertically higher up, as a ratio of parent height.
72 const Vector3      DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO( 0.75f, 0.75f, 0.75f );               ///< Amount of the stage's width that the toast popup will take up.
73
74 /**
75  * Creation function for named type "popupToast".
76  * @return Handle to the new toast popup object.
77  */
78 BaseHandle CreateToast()
79 {
80   Toolkit::Popup popup = Toolkit::Popup::New();
81
82   // Setup for Toast Popup type.
83   popup.SetSizeModeFactor( DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO );
84   popup.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
85   popup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
86   popup.SetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE, Toolkit::Popup::NON_CONTEXTUAL );
87   popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, DEFAULT_TOAST_TRANSITION_TIME );
88   popup.SetProperty( Toolkit::Popup::Property::TAIL_VISIBILITY, false );
89
90   // Disable the dimmed backing.
91   popup.SetProperty( Toolkit::Popup::Property::BACKING_ENABLED, false );
92
93   // The toast popup should fade in (not zoom).
94   popup.SetProperty( Toolkit::Popup::Property::ANIMATION_MODE, Toolkit::Popup::FADE );
95
96   // The toast popup should auto-hide.
97   popup.SetProperty( Toolkit::Popup::Property::AUTO_HIDE_DELAY, DEFAULT_TOAST_AUTO_HIDE_DELAY );
98
99   // Align to the bottom of the screen.
100   popup.SetParentOrigin( DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN );
101   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
102
103   // Let events pass through the toast popup.
104   popup.SetProperty( Toolkit::Popup::Property::TOUCH_TRANSPARENT, true );
105
106   return popup;
107 }
108
109 // Setup properties, signals and actions using the type-registry.
110 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Popup, Toolkit::Control, Create )
111
112 // Main content related properties.
113 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "title",                             MAP,              TITLE                   )
114 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "content",                           MAP,              CONTENT                 )
115 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "footer",                            MAP,              FOOTER                  )
116 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "displayState",                      STRING,           DISPLAY_STATE           )
117 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "touchTransparent",                  BOOLEAN,          TOUCH_TRANSPARENT       )
118
119 // Contextual related properties.
120 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailVisibility",                    BOOLEAN,          TAIL_VISIBILITY         )
121 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailPosition",                      VECTOR3,          TAIL_POSITION           )
122 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "contextualMode",                    STRING,           CONTEXTUAL_MODE         )
123
124 // Animation related properties.
125 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "animationDuration",                 FLOAT,            ANIMATION_DURATION      )
126 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "animationMode",                     STRING,           ANIMATION_MODE          )
127 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "entryAnimation",                    MAP,              ENTRY_ANIMATION         )
128 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "exitAnimation",                     MAP,              EXIT_ANIMATION          )
129 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "autoHideDelay",                     INTEGER,          AUTO_HIDE_DELAY         )
130
131 // Style related properties.
132 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "backingEnabled",                    BOOLEAN,          BACKING_ENABLED         )
133 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "backingColor",                      VECTOR4,          BACKING_COLOR           )
134 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "popupBackgroundImage",              STRING,           POPUP_BACKGROUND_IMAGE  )
135 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "popupBackgroundBorder",             RECTANGLE,        POPUP_BACKGROUND_BORDER )
136 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailUpImage",                       STRING,           TAIL_UP_IMAGE           )
137 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailDownImage",                     STRING,           TAIL_DOWN_IMAGE         )
138 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailLeftImage",                     STRING,           TAIL_LEFT_IMAGE         )
139 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailRightImage",                    STRING,           TAIL_RIGHT_IMAGE        )
140
141 // Signals.
142 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "touchedOutside",                                      SIGNAL_TOUCHED_OUTSIDE  )
143 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "showing",                                             SIGNAL_SHOWING          )
144 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "shown",                                               SIGNAL_SHOWN            )
145 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "hiding",                                              SIGNAL_HIDING           )
146 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "hidden",                                              SIGNAL_HIDDEN           )
147
148 DALI_TYPE_REGISTRATION_END()
149
150 // Named type registration.
151
152 // Toast Popup: Non-modal popup that displays information at the bottom of the screen.
153 TypeRegistration typeRegistrationToast( "PopupToast",  typeid( Toolkit::Popup ), CreateToast );
154
155 // Enumeration to / from string conversion tables
156
157 const Scripting::StringEnum DisplayStateTable[] = {
158   { "SHOWING", Toolkit::Popup::SHOWING },
159   { "SHOWN",   Toolkit::Popup::SHOWN   },
160   { "HIDING",  Toolkit::Popup::HIDING  },
161   { "HIDDEN",  Toolkit::Popup::HIDDEN  },
162 }; const unsigned int DisplayStateTableCount = sizeof( DisplayStateTable ) / sizeof( DisplayStateTable[0] );
163
164 const Scripting::StringEnum AnimationModeTable[] = {
165   { "NONE",    Toolkit::Popup::NONE    },
166   { "ZOOM",    Toolkit::Popup::ZOOM    },
167   { "FADE",    Toolkit::Popup::FADE    },
168   { "CUSTOM",  Toolkit::Popup::CUSTOM  },
169 }; const unsigned int AnimationModeTableCount = sizeof( AnimationModeTable ) / sizeof( AnimationModeTable[0] );
170
171 const Scripting::StringEnum ContextualModeTable[] = {
172   { "NON_CONTEXTUAL", Toolkit::Popup::NON_CONTEXTUAL },
173   { "ABOVE",          Toolkit::Popup::ABOVE          },
174   { "RIGHT",          Toolkit::Popup::RIGHT          },
175   { "BELOW",          Toolkit::Popup::BELOW          },
176   { "LEFT",           Toolkit::Popup::LEFT           },
177 }; const unsigned int ContextualModeTableCount = sizeof( ContextualModeTable ) / sizeof( ContextualModeTable[0] );
178
179 // Popup defaults.
180 const Vector3 DEFAULT_POPUP_PARENT_RELATIVE_SIZE( 0.75f, 1.0f, 1.0f );                      ///< Default size percentage of parent.
181 const float   DEFAULT_POPUP_ANIMATION_DURATION =  0.6f;                                     ///< Duration of hide/show animations.
182 const float   POPUP_OUT_MARGIN_WIDTH =            16.f;                                     ///< Space between the screen edge and the popup edge in the horizontal dimension.
183 const float   POPUP_OUT_MARGIN_HEIGHT =           36.f;                                     ///< Space between the screen edge and the popup edge in the vertical dimension.
184 const Vector3 DEFAULT_TAIL_POSITION( 0.5f, 1.0f, 0.0f );                                    ///< Position the tail will be displayed when enabled without setting the position.
185
186 // Contextual defaults.
187 const Vector2 DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN( 10.0f, 10.0f );                          ///< How close the Popup will be to it's contextual parent.
188 const Vector2 DEFAULT_CONTEXTUAL_STAGE_BORDER( 15.0f, 15.0f );                              ///< How close the Popup can be to the stage edges.
189
190 // Popup style defaults.
191 const char*   DEFAULT_BACKGROUND_IMAGE_PATH =     DALI_IMAGE_DIR "00_popup_bg.9.png";       ///< Background image.
192 const char*   DEFAULT_TAIL_UP_IMAGE_PATH =        DALI_IMAGE_DIR "popup_tail_up.png";       ///< Tail up image.
193 const char*   DEFAULT_TAIL_DOWN_IMAGE_PATH =      DALI_IMAGE_DIR "popup_tail_down.png";     ///< Tail down image.
194 const char*   DEFAULT_TAIL_LEFT_IMAGE_PATH =      DALI_IMAGE_DIR "popup_tail_left.png";     ///< Tail left image.
195 const char*   DEFAULT_TAIL_RIGHT_IMAGE_PATH =     DALI_IMAGE_DIR "popup_tail_right.png";    ///< Tail right image.
196
197 const Vector4 DEFAULT_BACKING_COLOR( 0.0f, 0.0f, 0.0f, 0.5f );                              ///< Color of the dimmed backing.
198 const Rect<int> DEFAULT_BACKGROUND_BORDER( 17, 17, 13, 13 );                                ///< Default border of the background.
199 const Rect<float>  DEFAULT_TITLE_PADDING( 20.0f, 20.0f, 20.0f, 20.0f );                     ///< Title padding used on popups with content and/or controls (from Tizen GUI UX).
200 const Rect<float>  DEFAULT_TITLE_ONLY_PADDING( 8.0f, 8.0f, 8.0f, 8.0f );                    ///< Title padding used on popups with a title only (like toast popups).
201 const Vector3 FOOTER_SIZE( 620.0f, 96.0f,0.0f );                                            ///< Default size of the bottom control area.
202 const float   DEFAULT_RELATIVE_PARENT_WIDTH =     0.75f;                                    ///< If width is not fixed, relative size to parent is used by default.
203
204 } // Unnamed namespace
205
206 /*
207  * Implementation.
208  */
209
210 Dali::Toolkit::Popup Popup::New()
211 {
212   // Create the implementation
213   PopupPtr popup( new Popup() );
214
215   // Pass ownership to CustomActor via derived handle.
216   Dali::Toolkit::Popup handle( *popup );
217
218   // Second-phase initialisation of the implementation.
219   // This can only be done after the CustomActor connection has been made.
220   popup->Initialize();
221
222   return handle;
223 }
224
225 Popup::Popup()
226 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
227   mTouchedOutsideSignal(),
228   mShowingSignal(),
229   mShownSignal(),
230   mHidingSignal(),
231   mHiddenSignal(),
232   mLayer(),
233   mPopupLayout(),
234   mBacking(),
235   mPreviousFocusedActor(),
236   mTailImage(),
237   mPopupContainer(),
238   mAnimation(),
239   mAlterAddedChild( false ),
240   mLayoutDirty( true ),
241   mAutoHideTimer(),
242   mTouchTransparent( false ),
243   mTitle(),
244   mContent(),
245   mFooter(),
246   mDisplayState( Toolkit::Popup::HIDDEN ), // Hidden until shown with SetDisplayState()
247   mTailVisible( false ),
248   mTailPosition( DEFAULT_TAIL_POSITION ),
249   mContextualMode( Toolkit::Popup::NON_CONTEXTUAL ),
250   mAnimationDuration( DEFAULT_POPUP_ANIMATION_DURATION ),
251   mAnimationMode( Toolkit::Popup::FADE ),
252   mEntryAnimationData(),
253   mExitAnimationData(),
254   mAutoHideDelay( 0 ),
255   mBackingEnabled( true ),
256   mBackingColor( DEFAULT_BACKING_COLOR ),
257   mPopupBackgroundImage(),
258   mBackgroundBorder( DEFAULT_BACKGROUND_BORDER ),
259   mMargin(),
260   mTailUpImage( DEFAULT_TAIL_UP_IMAGE_PATH ),
261   mTailDownImage( DEFAULT_TAIL_DOWN_IMAGE_PATH ),
262   mTailLeftImage( DEFAULT_TAIL_LEFT_IMAGE_PATH ),
263   mTailRightImage( DEFAULT_TAIL_RIGHT_IMAGE_PATH )
264 {
265   SetKeyboardNavigationSupport( true );
266   SetAccessibilityConstructor( []( Dali::Actor actor ) {
267     return std::unique_ptr< Dali::Accessibility::Accessible >(
268         new AccessibleImpl( actor, Dali::Accessibility::Role::Dialog, true ) );
269   } );
270 }
271
272 void Popup::OnInitialize()
273 {
274   Actor self = Self();
275   self.SetName( "popup" );
276
277   // Apply some default resizing rules.
278   self.SetParentOrigin( ParentOrigin::CENTER );
279   self.SetAnchorPoint( AnchorPoint::CENTER );
280
281   self.SetSizeModeFactor( DEFAULT_POPUP_PARENT_RELATIVE_SIZE );
282   self.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
283   self.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
284
285   // Create a new layer so all Popup components can appear above all other actors.
286   mLayer = Layer::New();
287   mLayer.SetName( "popupLayer" );
288
289   mLayer.SetParentOrigin( ParentOrigin::CENTER );
290   mLayer.SetAnchorPoint( AnchorPoint::CENTER );
291   mLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
292
293   // Important to set as invisible as otherwise, if the popup is parented,
294   // but not shown yet it will appear statically on the screen.
295   mLayer.SetVisible( false );
296
297   // Add the layer to the hierarchy.
298   self.Add( mLayer );
299
300   // Add Backing (Dimmed effect).
301   mBacking = CreateBacking();
302   mLayer.Add( mBacking );
303
304   mPopupContainer = Actor::New();
305   mPopupContainer.SetName( "popupContainer" );
306   mPopupContainer.SetParentOrigin( ParentOrigin::CENTER );
307   mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER );
308   mPopupContainer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
309   mLayer.Add( mPopupContainer );
310
311   // Create the Popup layout to contain all main content.
312   mPopupLayout = Toolkit::TableView::New( 3, 1 );
313
314   // Adds the default background image.
315   SetPopupBackgroundImage( Toolkit::ImageView::New( DEFAULT_BACKGROUND_IMAGE_PATH ) );
316
317   mPopupLayout.SetName( "popupLayoutTable" );
318   mPopupLayout.SetParentOrigin( ParentOrigin::CENTER );
319   mPopupLayout.SetAnchorPoint( AnchorPoint::CENTER );
320
321   mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
322   mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
323   mPopupLayout.SetSize( Stage::GetCurrent().GetSize().x * DEFAULT_RELATIVE_PARENT_WIDTH, 0.0f );
324
325   mPopupLayout.SetFitHeight( 0 ); // Set row to fit.
326   mPopupLayout.SetFitHeight( 1 ); // Set row to fit.
327
328   mPopupLayout.TouchSignal().Connect( this, &Popup::OnDialogTouched );
329
330   mPopupContainer.Add( mPopupLayout );
331
332   // Any content after this point which is added to Self() will be re-parented to mContent.
333   mAlterAddedChild = true;
334
335   SetAsKeyboardFocusGroup( true );
336 }
337
338 Popup::~Popup()
339 {
340   mEntryAnimationData.Clear();
341   mExitAnimationData.Clear();
342 }
343
344 void Popup::LayoutAnimation()
345 {
346   // Perform setup based on the currently selected animation.
347   switch( mAnimationMode )
348   {
349     case Toolkit::Popup::ZOOM:
350     {
351       // Zoom animations start fully zoomed out.
352       mPopupContainer.SetScale( Vector3::ZERO );
353       break;
354     }
355
356     case Toolkit::Popup::FADE:
357     {
358       // Fade animations start transparent.
359       mPopupContainer.SetOpacity( 0.0f );
360       break;
361     }
362
363     case Toolkit::Popup::CUSTOM:
364     {
365       // Initialise the custom animation by playing to the end of it's exit animation instantly.
366       // EG. If it was zooming in, then we zoom out fully instantly so the zoom in works.
367       StartTransitionAnimation( false, true );
368       break;
369     }
370
371     case Toolkit::Popup::NONE:
372     {
373       break;
374     }
375   }
376 }
377
378 void Popup::StartTransitionAnimation( bool transitionIn, bool instantaneous /* false */ )
379 {
380   // Stop and recreate animation.
381   if ( mAnimation )
382   {
383     mAnimation.Stop();
384     mAnimation.Clear();
385     mAnimation.Reset();
386   }
387   float duration = GetAnimationDuration();
388
389   // Setup variables ready to start the animations.
390   // If we are performing the animation instantaneously, we do not want to emit a signal.
391   if( !instantaneous )
392   {
393     if( transitionIn )
394     {
395       // Setup variables and signal that we are starting the transition.
396       // Note: We signal even if the transition is instant so signal order is consistent.
397       mShowingSignal.Emit();
398     }
399     else
400     {
401       mHidingSignal.Emit();
402     }
403   }
404
405   // Perform chosen animation for the Popup.
406   switch( mAnimationMode )
407   {
408     case Toolkit::Popup::NONE:
409     {
410       mAnimation = Animation::New( 0.0f );
411       break;
412     }
413
414     case Toolkit::Popup::ZOOM:
415     {
416       mAnimation = Animation::New( duration );
417       if( duration > Math::MACHINE_EPSILON_0 )
418       {
419         if( transitionIn )
420         {
421           mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT, TimePeriod( duration * 0.25f, duration * 0.75f ) );
422         }
423         else
424         {
425           // Zoom out animation is twice the speed. Modify the duration variable so the backing animation speed is modified also.
426           duration /= 2.0f;
427           mAnimation.SetDuration( duration );
428           mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ZERO, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration ) );
429         }
430       }
431       else
432       {
433         mPopupContainer.SetScale( transitionIn ? Vector3::ONE : Vector3::ZERO );
434       }
435       break;
436     }
437
438     case Toolkit::Popup::FADE:
439     {
440       mAnimation = Animation::New( duration );
441       if( duration > Math::MACHINE_EPSILON_0 )
442       {
443         if( transitionIn )
444         {
445           mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) );
446         }
447         else
448         {
449           mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) );
450         }
451       }
452       else
453       {
454         mPopupContainer.SetOpacity( transitionIn ? 1.0f : 0.0f );
455       }
456       break;
457     }
458
459     case Toolkit::Popup::CUSTOM:
460     {
461       // Use a user specified animation for in and out.
462       // Read the correct animation depending on entry or exit.
463       // Attempt to use animation data defined from script data.
464       Dali::AnimationData* animationData = transitionIn ? &mEntryAnimationData : &mExitAnimationData;
465
466       // Create a new animation from the pre-defined data in the AnimationData class.
467       // If there is no data, mAnimation is invalidated.
468       mAnimation = animationData->CreateAnimation( mPopupContainer, duration );
469
470       // If we don't have a valid animation, provide a blank one so play() can still function generically.
471       if( !mAnimation )
472       {
473         // No animation was configured (even though custom mode was specified). Create a dummy animation to avoid an exception.
474         mAnimation = Animation::New( 0.0f );
475       }
476
477       break;
478     }
479   }
480
481   // Animate the backing, if enabled.
482   // This is set up last so that different animation modes can have an effect on the backing animation speed.
483   if( mBackingEnabled )
484   {
485     // Use the alpha from the user-specified color.
486     float targetAlpha = mBackingColor.a;
487     if( duration > Math::MACHINE_EPSILON_0 )
488     {
489       if( transitionIn )
490       {
491         mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), targetAlpha, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) );
492       }
493       else
494       {
495         mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) );
496       }
497     }
498     else
499     {
500       mBacking.SetProperty( Actor::Property::COLOR_ALPHA, transitionIn ? targetAlpha : 0.0f );
501     }
502   }
503
504   // If we are performing the animation instantaneously, jump to the position directly and do not signal.
505   if( instantaneous )
506   {
507     mAnimation.SetCurrentProgress( 1.0f );
508     mAnimation.Play();
509   }
510   else if( duration > Math::MACHINE_EPSILON_0 )
511   {
512     // Run the animation.
513     mAnimation.FinishedSignal().Connect( this, &Popup::OnDisplayChangeAnimationFinished );
514     mAnimation.Play();
515   }
516   else
517   {
518     // We did not use an animation to achive the transition.
519     // Trigger the state change directly.
520     DisplayStateChangeComplete();
521   }
522 }
523
524 void Popup::OnDisplayChangeAnimationFinished( Animation& source )
525 {
526   DisplayStateChangeComplete();
527 }
528
529 void Popup::DisplayStateChangeComplete()
530 {
531   // Remove contents from stage if completely hidden.
532   if( mDisplayState == Toolkit::Popup::HIDING )
533   {
534     mDisplayState = Toolkit::Popup::HIDDEN;
535
536     mLayer.SetVisible( false );
537     mPopupLayout.SetSensitive( false );
538
539     // Guard against destruction during signal emission.
540     Toolkit::Popup handle( GetOwner() );
541     mHiddenSignal.Emit();
542   }
543   else if( mDisplayState == Toolkit::Popup::SHOWING )
544   {
545     mDisplayState = Toolkit::Popup::SHOWN;
546     Toolkit::Popup handle( GetOwner() );
547     mShownSignal.Emit();
548
549     // Start a timer to auto-hide if enabled.
550     if( mAutoHideDelay > 0u )
551     {
552       mAutoHideTimer = Timer::New( mAutoHideDelay );
553       mAutoHideTimer.TickSignal().Connect( this, &Popup::OnAutoHideTimeReached );
554       mAutoHideTimer.Start();
555     }
556   }
557 }
558
559 bool Popup::OnAutoHideTimeReached()
560 {
561   // Display timer has expired, auto hide the popup exactly as if the user had clicked outside.
562   SetDisplayState( Toolkit::Popup::HIDDEN );
563
564   if( mAutoHideTimer )
565   {
566     mAutoHideTimer.Stop();
567     mAutoHideTimer.TickSignal().Disconnect( this, &Popup::OnAutoHideTimeReached );
568     mAutoHideTimer.Reset();
569   }
570   return true;
571 }
572
573 void Popup::SetPopupBackgroundImage( Actor image )
574 {
575   // Removes any previous background.
576   if( mPopupBackgroundImage )
577   {
578     mPopupBackgroundImage.Unparent();
579     if( mTailImage )
580     {
581       mTailImage.Unparent();
582     }
583   }
584
585   // Adds new background to the dialog.
586   mPopupBackgroundImage = image;
587   mPopupBackgroundImage.SetName( "popupBackgroundImage" );
588   mPopupBackgroundImage.SetAnchorPoint( AnchorPoint::CENTER );
589   mPopupBackgroundImage.SetParentOrigin( ParentOrigin::CENTER );
590
591   // OnDialogTouched only consumes the event. It prevents the touch event to be caught by the backing.
592   mPopupBackgroundImage.TouchSignal().Connect( this, &Popup::OnDialogTouched );
593
594   // Set the popup border to be slightly larger than the layout contents.
595   UpdateBackgroundPositionAndSize();
596
597   const bool prevAlter = mAlterAddedChild;
598   mAlterAddedChild = false;
599   mPopupContainer.Add( mPopupBackgroundImage );
600   mPopupBackgroundImage.LowerToBottom();
601   mAlterAddedChild = prevAlter;
602
603   if( mTailImage )
604   {
605     mPopupBackgroundImage.Add( mTailImage );
606   }
607
608   mLayoutDirty = true;
609 }
610
611 Actor Popup::GetPopupBackgroundImage() const
612 {
613   return mPopupBackgroundImage;
614 }
615
616 void Popup::SetTitle( Actor titleActor )
617 {
618   // Replaces the current title actor.
619   if( !mPopupLayout )
620   {
621     return;
622   }
623
624   if( mTitle )
625   {
626     mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 0, 0) );
627   }
628   mTitle = titleActor;
629
630   if( mTitle )
631   {
632     // Set up padding to give sensible default behaviour
633     // (an application developer can later override this if they wish).
634     mTitle.SetPadding( DEFAULT_TITLE_PADDING );
635
636     mPopupLayout.AddChild( mTitle, Toolkit::TableView::CellPosition( 0, 0 ) );
637   }
638
639   mLayoutDirty = true;
640   RelayoutRequest();
641 }
642
643 Actor Popup::GetTitle() const
644 {
645   return mTitle;
646 }
647
648 void Popup::SetContent( Actor content )
649 {
650   // Remove previous content actor.
651   if( mPopupLayout )
652   {
653     mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 1, 0 ) );
654   }
655    // Keep a handle to the new content.
656   mContent = content;
657
658   if( mContent )
659   {
660     mContent.SetName( "popupContent" );
661
662     mPopupLayout.AddChild( mContent, Toolkit::TableView::CellPosition( 1, 0 ) );
663   }
664
665   mLayoutDirty = true;
666   RelayoutRequest();
667 }
668
669 Actor Popup::GetContent() const
670 {
671   return mContent;
672 }
673
674 void Popup::SetFooter( Actor footer )
675 {
676   // Remove previous content actor.
677   if( mPopupLayout )
678   {
679     mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 2, 0 ) );
680   }
681
682   // Keep a handle to the new content.
683   mFooter = footer;
684
685   if( mFooter )
686   {
687     mFooter.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
688
689     // The control container has a fixed height.
690     mPopupLayout.SetFitHeight( 2u );
691     mPopupLayout.AddChild( footer, Toolkit::TableView::CellPosition( 2, 0 ) );
692   }
693
694   mLayoutDirty = true;
695   RelayoutRequest();
696 }
697
698 Actor Popup::GetFooter() const
699 {
700   return mFooter;
701 }
702
703 void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState )
704 {
705   // Convert the 4-way state to a bool, true for show, false for hide.
706   bool display = ( displayState == Toolkit::Popup::SHOWING ) || ( displayState == Toolkit::Popup::SHOWN );
707
708   // Ignore if we are already at the target display state.
709   if( display == ( ( mDisplayState == Toolkit::Popup::SHOWING ) || ( mDisplayState == Toolkit::Popup::SHOWN ) ) )
710   {
711     return;
712   }
713
714   // Convert the bool state to the actual display state to use.
715   mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
716
717   if ( display )
718   {
719     // Update the state to indicate the current intent.
720     mDisplayState = Toolkit::Popup::SHOWING;
721
722     // We want the popup to have key input focus when it is displayed
723     SetKeyInputFocus();
724
725     // We are displaying so bring the popup layer to the front, and set it visible so it is rendered.
726     mLayer.RaiseToTop();
727     mLayer.SetVisible( true );
728
729     // Set up the layout if this is the first display or the layout has become dirty.
730     if( mLayoutDirty )
731     {
732       // Bake-in any style and layout options to create the Popup layout.
733       LayoutPopup();
734     }
735
736     // Allow the popup to catch events.
737     mPopupLayout.SetSensitive( true );
738
739     // Handle the keyboard focus when popup is shown.
740     Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
741     if( keyboardFocusManager )
742     {
743       mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor();
744
745       if( Self().IsKeyboardFocusable() )
746       {
747         // Setup the actgor to start focus from.
748         Actor focusActor;
749         if( mContent && mContent.IsKeyboardFocusable() )
750         {
751           // If the content is focusable, move the focus to the content.
752           focusActor = mContent;
753         }
754         else if( mFooter && mFooter.IsKeyboardFocusable() )
755         {
756           // If the footer is focusable, move the focus to the footer.
757           focusActor = mFooter;
758         }
759         else
760         {
761           DALI_LOG_WARNING( "There is no focusable in popup\n" );
762         }
763
764         if( focusActor )
765         {
766           keyboardFocusManager.SetCurrentFocusActor( focusActor );
767         }
768       }
769     }
770   }
771   else // Not visible.
772   {
773     mDisplayState = Toolkit::Popup::HIDING;
774     ClearKeyInputFocus();
775
776     // Restore the keyboard focus when popup is hidden.
777     if( mPreviousFocusedActor && mPreviousFocusedActor.IsKeyboardFocusable() )
778     {
779       Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
780       if( keyboardFocusManager )
781       {
782         keyboardFocusManager.SetCurrentFocusActor( mPreviousFocusedActor );
783       }
784     }
785   }
786
787   // Perform animation.
788   StartTransitionAnimation( display );
789 }
790
791 Toolkit::Popup::DisplayState Popup::GetDisplayState() const
792 {
793   return mDisplayState;
794 }
795
796 void Popup::LayoutPopup()
797 {
798   mLayoutDirty = false;
799
800   /* When animating in, we want to respect the origin applied to Self().
801    * For example, if zooming, not only will the final result be anchored to the
802    * selected point, but the zoom will originate from this point also.
803    *
804    * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT :
805    *
806    *       --------                --------
807    *       |X|                     |XXX|
808    *       |``        Animates     |XXX|
809    *       |             to:       |XXX|
810    *       |                       |````
811    *       |                       |
812    */
813   mPopupContainer.SetParentOrigin( Self().GetCurrentParentOrigin() );
814   mPopupContainer.SetAnchorPoint( Self().GetCurrentAnchorPoint() );
815
816   // If there is only a title, use less padding.
817   if( mTitle )
818   {
819     if( !mContent && !mFooter )
820     {
821       mTitle.SetPadding( DEFAULT_TITLE_ONLY_PADDING );
822     }
823     else
824     {
825       mTitle.SetPadding( DEFAULT_TITLE_PADDING );
826     }
827   }
828
829   // Allow derived classes to perform any layout they may need to do.
830   OnLayoutSetup();
831
832   // Update background visibility.
833   mPopupContainer.SetVisible( !( !mFooter && mPopupLayout.GetChildCount() == 0 ) );
834
835   // Create / destroy / position the tail as needed.
836   LayoutTail();
837
838   // Setup any layout and initialisation required for the selected animation.
839   LayoutAnimation();
840
841   RelayoutRequest();
842 }
843
844 void Popup::LayoutTail()
845 {
846   // Removes the tail actor.
847   if( mTailImage && mTailImage.GetParent() )
848   {
849     mTailImage.GetParent().Remove( mTailImage );
850     mTailImage.Reset();
851   }
852
853   if( !mTailVisible )
854   {
855     return;
856   }
857
858   const Vector3& parentOrigin = GetTailPosition();
859   Vector3 position;
860   std::string image;
861   Vector3 anchorPoint;
862
863   // depending on position of tail around ParentOrigin, a different tail image is used...
864   if( parentOrigin.y < Math::MACHINE_EPSILON_1 )
865   {
866     image = mTailUpImage;
867     anchorPoint = AnchorPoint::BOTTOM_CENTER;
868     position.y = mBackgroundBorder.top;
869   }
870   else if( parentOrigin.y > ( 1.0f - Math::MACHINE_EPSILON_1 ) )
871   {
872     image = mTailDownImage;
873     anchorPoint = AnchorPoint::TOP_CENTER;
874     position.y = - mBackgroundBorder.bottom;
875   }
876   else if( parentOrigin.x < Math::MACHINE_EPSILON_1 )
877   {
878     image = mTailLeftImage;
879     anchorPoint = AnchorPoint::CENTER_RIGHT;
880     position.x = mBackgroundBorder.left;
881   }
882   else if( parentOrigin.x > ( 1.0f - Math::MACHINE_EPSILON_1 ) )
883   {
884     image = mTailRightImage;
885     anchorPoint = AnchorPoint::CENTER_LEFT;
886     position.x = - mBackgroundBorder.right;
887   }
888
889   if( !image.empty() )
890   {
891     // Adds the tail actor.
892     mTailImage = Toolkit::ImageView::New( image );
893     mTailImage.SetName( "tailImage" );
894     mTailImage.SetParentOrigin( parentOrigin );
895     mTailImage.SetAnchorPoint( anchorPoint );
896     mTailImage.SetPosition( position );
897
898     if( mPopupBackgroundImage )
899     {
900       mPopupBackgroundImage.Add( mTailImage );
901     }
902   }
903 }
904
905 void Popup::SetContextualMode( Toolkit::Popup::ContextualMode mode )
906 {
907   mContextualMode = mode;
908   mLayoutDirty = true;
909 }
910
911 Toolkit::Popup::ContextualMode Popup::GetContextualMode() const
912 {
913   return mContextualMode;
914 }
915
916 Toolkit::Control Popup::CreateBacking()
917 {
918   Toolkit::Control backing = Control::New();
919   backing.SetProperty( Toolkit::Control::Property::BACKGROUND,
920                        Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR )
921                                       .Add( Toolkit::ColorVisual::Property::MIX_COLOR, Vector4( mBackingColor.r, mBackingColor.g, mBackingColor.b, 1.0f ) ) );
922   backing.SetName( "popupBacking" );
923
924   // Must always be positioned top-left of stage, regardless of parent.
925   backing.SetInheritPosition(false);
926
927   // Always the full size of the stage.
928   backing.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
929   backing.SetSize( Stage::GetCurrent().GetSize() );
930
931   // Catch events.
932   backing.SetSensitive( true );
933
934   // Default to being transparent.
935   backing.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f );
936   backing.TouchSignal().Connect( this, &Popup::OnBackingTouched );
937   backing.WheelEventSignal().Connect( this, &Popup::OnBackingWheelEvent );
938   return backing;
939 }
940
941 Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
942 {
943   return mTouchedOutsideSignal;
944 }
945
946 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
947 {
948   return mShowingSignal;
949 }
950
951 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
952 {
953   return mShownSignal;
954 }
955
956 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
957 {
958   return mHidingSignal;
959 }
960
961 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
962 {
963   return mHiddenSignal;
964 }
965
966 void Popup::SetTailVisibility( bool visible )
967 {
968   mTailVisible = visible;
969   mLayoutDirty = true;
970 }
971
972 const bool Popup::IsTailVisible() const
973 {
974   return mTailVisible;
975 }
976
977 void Popup::SetTailPosition( Vector3 position )
978 {
979   mTailPosition = position;
980   mLayoutDirty = true;
981 }
982
983 const Vector3& Popup::GetTailPosition() const
984 {
985   return mTailPosition;
986 }
987
988 void Popup::SetAnimationDuration( float duration )
989 {
990   mAnimationDuration = duration;
991   mLayoutDirty = true;
992 }
993
994 float Popup::GetAnimationDuration() const
995 {
996   return mAnimationDuration;
997 }
998
999 void Popup::SetAnimationMode( Toolkit::Popup::AnimationMode animationMode )
1000 {
1001   mAnimationMode = animationMode;
1002   mLayoutDirty = true;
1003 }
1004
1005 Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const
1006 {
1007   return mAnimationMode;
1008 }
1009
1010 void Popup::SetEntryAnimationData( const Property::Map& map )
1011 {
1012   mEntryAnimationData.Clear();
1013   Scripting::NewAnimation( map, mEntryAnimationData );
1014 }
1015
1016 void Popup::SetExitAnimationData( const Property::Map& map )
1017 {
1018   mExitAnimationData.Clear();
1019   Scripting::NewAnimation( map, mExitAnimationData );
1020 }
1021
1022 void Popup::UpdateBackgroundPositionAndSize()
1023 {
1024   if( mPopupBackgroundImage )
1025   {
1026     mPopupBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
1027     mPopupBackgroundImage.SetSizeModeFactor( Vector3( mBackgroundBorder.left + mBackgroundBorder.right, mBackgroundBorder.top + mBackgroundBorder.bottom, 0.0f ) );
1028
1029     // Adjust the position of the background so the transparent areas are set appropriately
1030     mPopupBackgroundImage.SetPosition( ( mBackgroundBorder.right - mBackgroundBorder.left ) * 0.5f, ( mBackgroundBorder.bottom - mBackgroundBorder.top ) * 0.5f );
1031   }
1032 }
1033
1034 void Popup::SetAutoHideDelay( int delay )
1035 {
1036   mAutoHideDelay = delay;
1037 }
1038
1039 int Popup::GetAutoHideDelay() const
1040 {
1041   return mAutoHideDelay;
1042 }
1043
1044 void Popup::SetBackingEnabled( bool enabled )
1045 {
1046   mBackingEnabled = enabled;
1047   mLayoutDirty = true;
1048 }
1049
1050 const bool Popup::IsBackingEnabled() const
1051 {
1052   return mBackingEnabled;
1053 }
1054
1055 void Popup::SetBackingColor( Vector4 color )
1056 {
1057   mBackingColor = color;
1058   mBacking.SetBackgroundColor( Vector4( color.r, color.g, color.b, 1.0f ) );
1059   mLayoutDirty = true;
1060 }
1061
1062 const Vector4& Popup::GetBackingColor() const
1063 {
1064   return mBackingColor;
1065 }
1066
1067 void Popup::SetTailUpImage( std::string image )
1068 {
1069   mTailUpImage = image;
1070   mLayoutDirty = true;
1071   LayoutTail();
1072 }
1073
1074 const std::string& Popup::GetTailUpImage() const
1075 {
1076   return mTailUpImage;
1077 }
1078
1079 void Popup::SetTailDownImage( std::string image )
1080 {
1081   mTailDownImage = image;
1082   mLayoutDirty = true;
1083   LayoutTail();
1084 }
1085
1086 const std::string& Popup::GetTailDownImage() const
1087 {
1088   return mTailDownImage;
1089 }
1090
1091 void Popup::SetTailLeftImage( std::string image )
1092 {
1093   mTailLeftImage = image;
1094   mLayoutDirty = true;
1095   LayoutTail();
1096 }
1097
1098 const std::string& Popup::GetTailLeftImage() const
1099 {
1100   return mTailLeftImage;
1101 }
1102
1103 void Popup::SetTailRightImage( std::string image )
1104 {
1105   mTailRightImage = image;
1106   mLayoutDirty = true;
1107   LayoutTail();
1108 }
1109
1110 const std::string& Popup::GetTailRightImage() const
1111 {
1112   return mTailRightImage;
1113 }
1114
1115 void Popup::SetTouchTransparent( bool enabled )
1116 {
1117   mTouchTransparent = enabled;
1118 }
1119
1120 const bool Popup::IsTouchTransparent() const
1121 {
1122   return mTouchTransparent;
1123 }
1124
1125 void Popup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1126 {
1127   Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1128
1129   if ( popup )
1130   {
1131     Popup& popupImpl( GetImpl( popup ) );
1132
1133     switch ( propertyIndex )
1134     {
1135       case Toolkit::Popup::Property::TITLE:
1136       {
1137         Property::Map valueMap;
1138         if( value.Get( valueMap ) )
1139         {
1140           popupImpl.SetTitle( Scripting::NewActor( valueMap ) );
1141         }
1142         break;
1143       }
1144       case Toolkit::Popup::Property::CONTENT:
1145       {
1146         Property::Map valueMap;
1147         if( value.Get( valueMap ) )
1148         {
1149           popupImpl.SetContent( Scripting::NewActor( valueMap ) );
1150         }
1151         break;
1152       }
1153       case Toolkit::Popup::Property::FOOTER:
1154       {
1155         Property::Map valueMap;
1156         if( value.Get( valueMap ) )
1157         {
1158           popupImpl.SetFooter( Scripting::NewActor( valueMap ) );
1159         }
1160         break;
1161       }
1162       case Toolkit::Popup::Property::DISPLAY_STATE:
1163       {
1164         std::string valueString;
1165         if( value.Get( valueString ) )
1166         {
1167           Toolkit::Popup::DisplayState displayState( Toolkit::Popup::HIDDEN );
1168           if( Scripting::GetEnumeration< Toolkit::Popup::DisplayState >( valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState ) )
1169           {
1170             popupImpl.SetDisplayState( displayState );
1171           }
1172         }
1173         break;
1174       }
1175       case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1176       {
1177         bool valueBool;
1178         if( value.Get( valueBool ) )
1179         {
1180           popupImpl.SetTouchTransparent( valueBool );
1181         }
1182         break;
1183       }
1184       case Toolkit::Popup::Property::TAIL_VISIBILITY:
1185       {
1186         bool valueBool;
1187         if( value.Get( valueBool ) )
1188         {
1189           popupImpl.SetTailVisibility( valueBool );
1190         }
1191         break;
1192       }
1193       case Toolkit::Popup::Property::TAIL_POSITION:
1194       {
1195         Vector3 valueVector3;
1196         if( value.Get( valueVector3 ) )
1197         {
1198           popupImpl.SetTailPosition( valueVector3 );
1199         }
1200         break;
1201       }
1202       case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1203       {
1204         std::string valueString;
1205         if( value.Get( valueString ) )
1206         {
1207           Toolkit::Popup::ContextualMode contextualMode( Toolkit::Popup::BELOW );
1208           if( Scripting::GetEnumeration< Toolkit::Popup::ContextualMode >( valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode ) )
1209           {
1210             popupImpl.SetContextualMode( contextualMode );
1211           }
1212         }
1213         break;
1214       }
1215       case Toolkit::Popup::Property::ANIMATION_DURATION:
1216       {
1217         float valueFloat;
1218         if( value.Get( valueFloat ) )
1219         {
1220           popupImpl.SetAnimationDuration( valueFloat );
1221         }
1222         break;
1223       }
1224       case Toolkit::Popup::Property::ANIMATION_MODE:
1225       {
1226         std::string valueString;
1227         if( value.Get( valueString ) )
1228         {
1229           Toolkit::Popup::AnimationMode animationMode( Toolkit::Popup::FADE );
1230           if( Scripting::GetEnumeration< Toolkit::Popup::AnimationMode >( valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode ) )
1231           {
1232             popupImpl.SetAnimationMode( animationMode );
1233           }
1234         }
1235         break;
1236       }
1237       case Toolkit::Popup::Property::ENTRY_ANIMATION:
1238       {
1239         Property::Map valueMap;
1240         if( value.Get( valueMap ) )
1241         {
1242           popupImpl.SetEntryAnimationData( valueMap );
1243         }
1244         break;
1245       }
1246       case Toolkit::Popup::Property::EXIT_ANIMATION:
1247       {
1248         Property::Map valueMap;
1249         if( value.Get( valueMap ) )
1250         {
1251           popupImpl.SetExitAnimationData( valueMap );
1252         }
1253         break;
1254       }
1255       case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1256       {
1257         int valueInt;
1258         if( value.Get( valueInt ) )
1259         {
1260           popupImpl.SetAutoHideDelay( valueInt );
1261         }
1262         break;
1263       }
1264       case Toolkit::Popup::Property::BACKING_ENABLED:
1265       {
1266         bool valueBool;
1267         if( value.Get( valueBool ) )
1268         {
1269           popupImpl.SetBackingEnabled( valueBool );
1270         }
1271         break;
1272       }
1273       case Toolkit::Popup::Property::BACKING_COLOR:
1274       {
1275         Vector4 valueVector4;
1276         if( value.Get( valueVector4 ) )
1277         {
1278           popupImpl.SetBackingColor( valueVector4 );
1279         }
1280         break;
1281       }
1282       case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1283       {
1284         std::string valueString;
1285         if( value.Get( valueString ) )
1286         {
1287           Toolkit::ImageView actor = Toolkit::ImageView::New( valueString );
1288           popupImpl.SetPopupBackgroundImage( actor );
1289         }
1290         break;
1291       }
1292       case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1293       {
1294         bool valueUpdated = false;
1295
1296         Vector4 valueVector4;
1297         if( value.Get( popupImpl.mBackgroundBorder ) )
1298         {
1299           valueUpdated = true;
1300         }
1301         else if( value.Get( valueVector4 ) )
1302         {
1303           popupImpl.mBackgroundBorder.left   = valueVector4.x;
1304           popupImpl.mBackgroundBorder.right  = valueVector4.y;
1305           popupImpl.mBackgroundBorder.bottom = valueVector4.z;
1306           popupImpl.mBackgroundBorder.top    = valueVector4.w;
1307           valueUpdated = true;
1308         }
1309
1310         if( valueUpdated )
1311         {
1312           popupImpl.LayoutTail(); // Update the tail if required
1313           popupImpl.UpdateBackgroundPositionAndSize(); // Update the background's size and position
1314         }
1315         break;
1316       }
1317       case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1318       {
1319         std::string valueString;
1320         if( value.Get( valueString ) )
1321         {
1322           popupImpl.SetTailUpImage( valueString );
1323         }
1324         break;
1325       }
1326       case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1327       {
1328         std::string valueString;
1329         if( value.Get( valueString ) )
1330         {
1331           popupImpl.SetTailDownImage( valueString );
1332         }
1333         break;
1334       }
1335       case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1336       {
1337         std::string valueString;
1338         if( value.Get( valueString ) )
1339         {
1340           popupImpl.SetTailLeftImage( valueString );
1341         }
1342         break;
1343       }
1344       case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1345       {
1346         std::string valueString;
1347         if( value.Get( valueString ) )
1348         {
1349           popupImpl.SetTailRightImage( valueString );
1350         }
1351         break;
1352       }
1353     }
1354   }
1355 }
1356
1357 Property::Value Popup::GetProperty( BaseObject* object, Property::Index propertyIndex )
1358 {
1359   Property::Value value;
1360
1361   Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1362
1363   if ( popup )
1364   {
1365     Popup& popupImpl( GetImpl( popup ) );
1366
1367     switch ( propertyIndex )
1368     {
1369       case Toolkit::Popup::Property::TITLE:
1370       {
1371         Property::Map map;
1372         Scripting::CreatePropertyMap( popupImpl.GetTitle(), map );
1373         value = map;
1374         break;
1375       }
1376       case Toolkit::Popup::Property::CONTENT:
1377       {
1378         Property::Map map;
1379         Scripting::CreatePropertyMap( popupImpl.GetContent(), map );
1380         value = map;
1381         break;
1382       }
1383       case Toolkit::Popup::Property::FOOTER:
1384       {
1385         Property::Map map;
1386         Scripting::CreatePropertyMap( popupImpl.GetFooter(), map );
1387         value = map;
1388         break;
1389       }
1390       case Toolkit::Popup::Property::DISPLAY_STATE:
1391       {
1392         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::DisplayState >( popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount );
1393         break;
1394       }
1395       case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1396       {
1397         value = popupImpl.IsTouchTransparent();
1398         break;
1399       }
1400       case Toolkit::Popup::Property::TAIL_VISIBILITY:
1401       {
1402         value = popupImpl.IsTailVisible();
1403         break;
1404       }
1405       case Toolkit::Popup::Property::TAIL_POSITION:
1406       {
1407         value = popupImpl.GetTailPosition();
1408         break;
1409       }
1410       case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1411       {
1412         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::ContextualMode >( popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount );
1413         break;
1414       }
1415       case Toolkit::Popup::Property::ANIMATION_DURATION:
1416       {
1417         value = popupImpl.GetAnimationDuration();
1418         break;
1419       }
1420       case Toolkit::Popup::Property::ANIMATION_MODE:
1421       {
1422         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::AnimationMode >( popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount );
1423         break;
1424       }
1425       case Toolkit::Popup::Property::ENTRY_ANIMATION:
1426       {
1427         // Note: Cannot retrieve property map from animation.
1428         Property::Map map;
1429         value = map;
1430         break;
1431       }
1432       case Toolkit::Popup::Property::EXIT_ANIMATION:
1433       {
1434         // Note: Cannot retrieve property map from animation.
1435         Property::Map map;
1436         value = map;
1437         break;
1438       }
1439       case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1440       {
1441         value = popupImpl.GetAutoHideDelay();
1442         break;
1443       }
1444       case Toolkit::Popup::Property::BACKING_ENABLED:
1445       {
1446         value = popupImpl.IsBackingEnabled();
1447         break;
1448       }
1449       case Toolkit::Popup::Property::BACKING_COLOR:
1450       {
1451         value = popupImpl.GetBackingColor();
1452         break;
1453       }
1454       case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1455       {
1456         Toolkit::ImageView imageView = Toolkit::ImageView::DownCast( popupImpl.GetPopupBackgroundImage() );
1457         if( imageView )
1458         {
1459           value = imageView.GetProperty( Toolkit::ImageView::Property::IMAGE );
1460         }
1461         break;
1462       }
1463       case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1464       {
1465         value = popupImpl.mBackgroundBorder;
1466         break;
1467       }
1468       case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1469       {
1470         value = popupImpl.GetTailUpImage();
1471         break;
1472       }
1473       case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1474       {
1475         value = popupImpl.GetTailDownImage();
1476         break;
1477       }
1478       case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1479       {
1480         value = popupImpl.GetTailLeftImage();
1481         break;
1482       }
1483       case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1484       {
1485         value = popupImpl.GetTailRightImage();
1486         break;
1487       }
1488     }
1489   }
1490
1491   return value;
1492 }
1493
1494 bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1495 {
1496   Dali::BaseHandle handle( object );
1497
1498   bool connected( true );
1499   Toolkit::Popup popup = Toolkit::Popup::DownCast( handle );
1500
1501   if( 0 == strcmp( signalName.c_str(), SIGNAL_TOUCHED_OUTSIDE ) )
1502   {
1503     popup.OutsideTouchedSignal().Connect( tracker, functor );
1504   }
1505   else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWING ) )
1506   {
1507     popup.ShowingSignal().Connect( tracker, functor );
1508   }
1509   else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWN ) )
1510   {
1511     popup.ShownSignal().Connect( tracker, functor );
1512   }
1513   else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDING ) )
1514   {
1515     popup.HidingSignal().Connect( tracker, functor );
1516   }
1517   else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDDEN ) )
1518   {
1519     popup.HiddenSignal().Connect( tracker, functor );
1520   }
1521   else
1522   {
1523     // signalName does not match any signal
1524     connected = false;
1525   }
1526
1527   return connected;
1528 }
1529
1530 bool Popup::OnBackingTouched( Actor actor, const TouchData& touch )
1531 {
1532   // Allow events to pass through if touch transparency is enabled.
1533   if( mTouchTransparent )
1534   {
1535     return false;
1536   }
1537
1538   if( touch.GetPointCount() > 0 )
1539   {
1540     if( touch.GetState( 0 ) == PointState::DOWN )
1541     {
1542       // Guard against destruction during signal emission.
1543       Toolkit::Popup handle( GetOwner() );
1544
1545       mTouchedOutsideSignal.Emit();
1546     }
1547   }
1548
1549   // Block anything behind backing becoming touched.
1550   mLayer.SetTouchConsumed( true );
1551   return true;
1552 }
1553
1554 bool Popup::OnBackingWheelEvent( Actor actor, const WheelEvent& event )
1555 {
1556   // Allow events to pass through if touch transparency is enabled.
1557   if( mTouchTransparent )
1558   {
1559     return false;
1560   }
1561
1562   // Consume wheel event in dimmed backing actor.
1563   mLayer.SetTouchConsumed( true );
1564   return true;
1565 }
1566
1567 bool Popup::OnDialogTouched( Actor actor, const TouchData& touch )
1568 {
1569   // Allow events to pass through if touch transparency is enabled.
1570   if( mTouchTransparent )
1571   {
1572     return false;
1573   }
1574
1575   // Consume event (stops backing actor receiving touch events)
1576   mLayer.SetTouchConsumed( true );
1577   return true;
1578 }
1579
1580 void Popup::OnStageConnection( int depth )
1581 {
1582   mLayoutDirty = true;
1583   RelayoutRequest();
1584
1585   Control::OnStageConnection( depth );
1586 }
1587
1588 void Popup::OnChildAdd( Actor& child )
1589 {
1590   // Re-parent any children added by user to the body layer.
1591   if( mAlterAddedChild )
1592   {
1593     SetContent( child );
1594   }
1595   else
1596   {
1597     mLayoutDirty = true;
1598     RelayoutRequest();
1599   }
1600
1601   Control::OnChildAdd( child );
1602 }
1603
1604 void Popup::LayoutContext( const Vector2& size )
1605 {
1606   // Do nothing if not in a contextual mode (or there is no parent context).
1607   Actor self = Self();
1608   Actor parent = self.GetParent();
1609   if( ( mContextualMode == Toolkit::Popup::NON_CONTEXTUAL ) || !parent )
1610   {
1611     return;
1612   }
1613
1614   mPopupContainer.SetParentOrigin( ParentOrigin::CENTER );
1615   // We always anchor to the CENTER, rather than a different anchor point for each contextual
1616   // mode to allow code-reuse of the bound checking code (for maintainability).
1617   mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER );
1618
1619   // Setup with some pre-calculations for speed.
1620   Vector3 halfStageSize( Stage().GetCurrent().GetSize() / 2.0f );
1621   Vector3 parentPosition( parent.GetCurrentPosition() );
1622   Vector2 halfSize( size / 2.0f );
1623   Vector2 halfParentSize( parent.GetRelayoutSize( Dimension::WIDTH ) / 2.0f, parent.GetRelayoutSize( Dimension::HEIGHT ) / 2.0f );
1624   Vector3 newPosition( Vector3::ZERO );
1625
1626   // Perform different positioning based on the specified contextual layout mode.
1627   switch( mContextualMode )
1628   {
1629     case Toolkit::Popup::BELOW:
1630     {
1631       newPosition.x += halfSize.x - halfParentSize.x;
1632       newPosition.y += halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1633       break;
1634     }
1635     case Toolkit::Popup::ABOVE:
1636     {
1637       newPosition.x += halfSize.x - halfParentSize.x;
1638       newPosition.y -= halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1639       break;
1640     }
1641     case Toolkit::Popup::RIGHT:
1642     {
1643       newPosition.x += halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1644       newPosition.y += halfSize.y - halfParentSize.y;
1645       break;
1646     }
1647     case Toolkit::Popup::LEFT:
1648     {
1649       newPosition.x -= halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1650       newPosition.y += halfSize.y - halfParentSize.y;
1651       break;
1652     }
1653     case Toolkit::Popup::NON_CONTEXTUAL:
1654     {
1655       // Code won't reach here (caught earlier).
1656       break;
1657     }
1658   }
1659
1660   // On-screen position checking.
1661   // Check new position is not too far right. If so, correct it.
1662   // Note: Check for right rather than left first, so if popup is too wide, the left check overrides
1663   // the right check and we at least see the left portion of the popup (as this is more useful).
1664   if( newPosition.x >= ( halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x ) )
1665   {
1666     newPosition.x = halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x;
1667   }
1668   // Check new position is not too far left. If so, correct it.
1669   if( newPosition.x < halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x )
1670   {
1671     newPosition.x = halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x;// - parentSize.x;
1672   }
1673   // Check new position is not too far down. If so, correct it.
1674   if( newPosition.y >= ( halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y ) )
1675   {
1676     newPosition.y = halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1677   }
1678   // Check new position is not too far up. If so, correct it.
1679   if( newPosition.y < halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y )
1680   {
1681     newPosition.y = halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1682   }
1683
1684   // Set the final position.
1685   mPopupContainer.SetPosition( newPosition );
1686 }
1687
1688 void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container )
1689 {
1690   Vector2 useSize( size );
1691
1692   // Use the Popup layouts size, unless requested to use a fixed size.
1693   // In which case take the size set for the Popup itself.
1694   ResizePolicy::Type widthPolicy = Self().GetResizePolicy( Dimension::WIDTH );
1695   ResizePolicy::Type heightPolicy = Self().GetResizePolicy( Dimension::HEIGHT );
1696
1697   // Width calculations:
1698   if( widthPolicy == ResizePolicy::USE_NATURAL_SIZE || widthPolicy == ResizePolicy::FIT_TO_CHILDREN )
1699   {
1700     // If we using a child-based policy, take the size from the popup layout.
1701     mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
1702     useSize.width = mPopupLayout.GetRelayoutSize( Dimension::WIDTH );
1703
1704     mPopupLayout.SetFitWidth( 0u );
1705   }
1706   else
1707   {
1708     // If we using a parent-based policy, take the size from the popup object itself (self).
1709     mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
1710
1711     mPopupLayout.SetFixedWidth( 0u, useSize.width );
1712   }
1713
1714   // Height calculations:
1715   // Title: Let the title be as high as it needs to be.
1716   mPopupLayout.SetFitHeight( 0u );
1717
1718   // Footer: Convert the footer's resize policy to a TableView row policy.
1719   if( mFooter )
1720   {
1721     ResizePolicy::Type footerHeightPolicy = mFooter.GetResizePolicy( Dimension::HEIGHT );
1722     if( ( footerHeightPolicy == ResizePolicy::USE_NATURAL_SIZE ) ||
1723         ( footerHeightPolicy == ResizePolicy::FIT_TO_CHILDREN ) )
1724     {
1725       mPopupLayout.SetFitHeight( 2u );
1726     }
1727     else if( footerHeightPolicy == ResizePolicy::FIXED )
1728     {
1729       mPopupLayout.SetFixedHeight( 2u, mFooter.GetRelayoutSize( Dimension::HEIGHT) );
1730     }
1731     else
1732     {
1733       mPopupLayout.SetRelativeHeight( 2u, 1.0f );
1734     }
1735   }
1736   else
1737   {
1738     mPopupLayout.SetFixedHeight( 2u, 0.0f );
1739   }
1740
1741   // Popup contents: Adjust the tableview's policies based on the popup's policies.
1742   if( heightPolicy == ResizePolicy::USE_NATURAL_SIZE || heightPolicy == ResizePolicy::FIT_TO_CHILDREN )
1743   {
1744     mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
1745
1746     // Let both the contents expand as necessary.
1747     mPopupLayout.SetFitHeight( 1u );
1748     useSize.height = mPopupLayout.GetRelayoutSize( Dimension::HEIGHT );
1749   }
1750   else
1751   {
1752     mPopupLayout.SetResizePolicy( heightPolicy, Dimension::HEIGHT );
1753
1754     // Let the content expand to fill the remaining space.
1755     mPopupLayout.SetRelativeHeight( 1u, 1.0f );
1756     mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
1757   }
1758
1759   // Relayout the popup-layout to give it it's new size this frame.
1760   container.Add( mPopupLayout, useSize );
1761
1762   if( mContent )
1763   {
1764     container.Add( mContent, Vector2( mContent.GetRelayoutSize( Dimension::WIDTH ), mContent.GetRelayoutSize( Dimension::HEIGHT ) ) );
1765   }
1766
1767   // Perform contextual layout setup if required.
1768   // This is done each time in case the parent moves.
1769   // This will have no effect if no contextual mode is selected.
1770   LayoutContext( useSize );
1771 }
1772
1773 void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
1774 {
1775   // To get the popup to emulate fit-to-children, we need to actually set use-natural-size.
1776   if( ( dimension & Dimension::HEIGHT ) && ( policy == ResizePolicy::FIT_TO_CHILDREN ) )
1777   {
1778     Self().SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
1779   }
1780
1781   mLayoutDirty = true;
1782   return;
1783 }
1784
1785 Vector3 Popup::GetNaturalSize()
1786 {
1787   return mPopupLayout.GetNaturalSize();
1788 }
1789
1790 float Popup::GetHeightForWidth( float width )
1791 {
1792   return mPopupLayout.GetHeightForWidth( width );
1793 }
1794
1795 float Popup::GetWidthForHeight( float height )
1796 {
1797   return mPopupLayout.GetWidthForHeight( height );
1798 }
1799
1800 bool Popup::OnKeyEvent( const KeyEvent& event )
1801 {
1802   // Allow events to pass through if touch transparency is enabled.
1803   if( mTouchTransparent )
1804   {
1805     return false;
1806   }
1807
1808   bool consumed = false;
1809
1810   if( event.state == KeyEvent::Down )
1811   {
1812     if (event.keyCode == Dali::DALI_KEY_ESCAPE || event.keyCode == Dali::DALI_KEY_BACK)
1813     {
1814       SetDisplayState( Toolkit::Popup::HIDDEN );
1815       consumed = true;
1816     }
1817   }
1818
1819   return consumed;
1820 }
1821
1822 void Popup::AddFocusableChildrenRecursive( Actor parent, std::vector< Actor >& focusableActors )
1823 {
1824   if( parent )
1825   {
1826     Toolkit::Control control = Toolkit::Control::DownCast( parent );
1827     bool layoutControl = control && GetImplementation( control ).IsKeyboardNavigationSupported();
1828
1829     if( parent.IsKeyboardFocusable() || layoutControl )
1830     {
1831       focusableActors.push_back( parent );
1832
1833       if( !layoutControl )
1834       {
1835         for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
1836         {
1837           Actor child( parent.GetChildAt( i ) );
1838           AddFocusableChildrenRecursive( child, focusableActors );
1839         }
1840       }
1841     }
1842   }
1843 }
1844
1845 void Popup::AddFocusableChildren( Actor parent, std::vector< Actor >& focusableActors )
1846 {
1847   if( parent )
1848   {
1849     Toolkit::Control control = Toolkit::Control::DownCast( parent );
1850     if( !GetImplementation( control ).IsKeyboardNavigationSupported() )
1851     {
1852       for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
1853       {
1854         Actor child( parent.GetChildAt( i ) );
1855         AddFocusableChildrenRecursive( child, focusableActors );
1856       }
1857     }
1858     else
1859     {
1860       focusableActors.push_back( parent );
1861     }
1862   }
1863 }
1864
1865 Actor Popup::GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled )
1866 {
1867   std::string currentStr;
1868   if( currentFocusedActor )
1869   {
1870     currentStr = currentFocusedActor.GetName();
1871   }
1872
1873   Actor nextFocusableActor( currentFocusedActor );
1874   Actor currentFocusGroup;
1875   if( currentFocusedActor )
1876   {
1877     currentFocusGroup = KeyboardFocusManager::Get().GetFocusGroup( currentFocusedActor );
1878   }
1879
1880   // TODO: Needs to be optimised
1881   // The following statement checks that if we have a current focused actor, then the current focus group is not the popup content or footer.
1882   // This is to detect if the focus is currently outside the popup, and if so, move it inside.
1883   if( !currentFocusedActor ||
1884     ( currentFocusedActor && ( ( !mContent || ( currentFocusGroup != mContent ) ) && ( !mFooter || ( currentFocusGroup != mFooter ) ) ) ) )
1885   {
1886     // The current focused actor is not within popup.
1887     if( mContent && mContent.IsKeyboardFocusable() )
1888     {
1889       // If the content is focusable, move the focus to the content.
1890       nextFocusableActor = mContent;
1891     }
1892     else if( mFooter && mFooter.IsKeyboardFocusable() )
1893     {
1894       // If the footer is focusable, move the focus to the footer.
1895       nextFocusableActor = mFooter;
1896     }
1897   }
1898   else
1899   {
1900     // Rebuild the focus chain because controls or content can be added or removed dynamically
1901     std::vector< Actor > focusableActors;
1902
1903     AddFocusableChildren( mContent, focusableActors );
1904     AddFocusableChildren( mFooter, focusableActors );
1905
1906     std::vector< Actor >::iterator endIterator = focusableActors.end();
1907     std::vector< Actor >::iterator currentIterator = focusableActors.begin();
1908     for( std::vector< Actor >::iterator iterator = focusableActors.begin(); iterator != endIterator; ++iterator )
1909     {
1910       if( currentFocusedActor == *iterator )
1911       {
1912         currentIterator = iterator;
1913       }
1914     }
1915
1916     if( currentIterator != endIterator )
1917     {
1918       switch( direction )
1919       {
1920         case Toolkit::Control::KeyboardFocus::LEFT:
1921         {
1922           if( currentIterator == focusableActors.begin() )
1923           {
1924             nextFocusableActor = *( endIterator - 1 );
1925           }
1926           else
1927           {
1928             nextFocusableActor = *( currentIterator - 1 );
1929           }
1930           break;
1931         }
1932         case Toolkit::Control::KeyboardFocus::RIGHT:
1933         {
1934           if( currentIterator == endIterator - 1 )
1935           {
1936             nextFocusableActor = *( focusableActors.begin() );
1937           }
1938           else
1939           {
1940             nextFocusableActor = *( currentIterator + 1 );
1941           }
1942           break;
1943         }
1944
1945         case Toolkit::Control::KeyboardFocus::UP:
1946         {
1947           nextFocusableActor = *(  focusableActors.begin() );
1948           break;
1949         }
1950
1951         case Toolkit::Control::KeyboardFocus::DOWN:
1952         {
1953           nextFocusableActor = *( endIterator - 1 );
1954           break;
1955         }
1956
1957         default:
1958         {
1959           break;
1960         }
1961       }
1962
1963       if( !nextFocusableActor )
1964       {
1965         DALI_LOG_WARNING( "Can not decide next focusable actor\n" );
1966       }
1967     }
1968   }
1969
1970   return nextFocusableActor;
1971 }
1972
1973
1974 } // namespace Internal
1975
1976 } // namespace Toolkit
1977
1978 } // namespace Dali