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