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