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