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