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