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