Merge "Set focusable to true when touched in default." into devel/master
[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   // Convert the bool state to the actual display state to use.
730   mDisplayState    = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
731   auto* accessible = Dali::Accessibility::Accessible::Get(Self());
732
733   if(display)
734   {
735     // Update the state to indicate the current intent.
736     mDisplayState = Toolkit::Popup::SHOWING;
737     Dali::Accessibility::Bridge::GetCurrentBridge()->RegisterDefaultLabel(accessible);
738     accessible->EmitShowing(true);
739
740     // We want the popup to have key input focus when it is displayed
741     SetKeyInputFocus();
742
743     // We are displaying so bring the popup layer to the front, and set it visible so it is rendered.
744     mLayer.RaiseToTop();
745     mLayer.SetProperty(Actor::Property::VISIBLE, true);
746
747     // Set up the layout if this is the first display or the layout has become dirty.
748     if(mLayoutDirty)
749     {
750       // Bake-in any style and layout options to create the Popup layout.
751       LayoutPopup();
752     }
753
754     // Allow the popup to catch events.
755     mPopupLayout.SetProperty(Actor::Property::SENSITIVE, true);
756
757     // Handle the keyboard focus when popup is shown.
758     Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
759     if(keyboardFocusManager)
760     {
761       mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor();
762
763       if(Self().GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
764       {
765         // Setup the actgor to start focus from.
766         Actor focusActor;
767         if(mContent && mContent.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
768         {
769           // If the content is focusable, move the focus to the content.
770           focusActor = mContent;
771         }
772         else if(mFooter && mFooter.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
773         {
774           // If the footer is focusable, move the focus to the footer.
775           focusActor = mFooter;
776         }
777         else
778         {
779           DALI_LOG_WARNING("There is no focusable in popup\n");
780         }
781
782         if(focusActor)
783         {
784           keyboardFocusManager.SetCurrentFocusActor(focusActor);
785         }
786       }
787     }
788   }
789   else // Not visible.
790   {
791     mDisplayState = Toolkit::Popup::HIDING;
792     Dali::Accessibility::Bridge::GetCurrentBridge()->UnregisterDefaultLabel(accessible);
793     ClearKeyInputFocus();
794     accessible->EmitShowing(false);
795     // Restore the keyboard focus when popup is hidden.
796     if(mPreviousFocusedActor && mPreviousFocusedActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
797     {
798       Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
799       if(keyboardFocusManager)
800       {
801         keyboardFocusManager.SetCurrentFocusActor(mPreviousFocusedActor);
802       }
803     }
804   }
805
806   // Perform animation.
807   StartTransitionAnimation(display);
808 }
809
810 Toolkit::Popup::DisplayState Popup::GetDisplayState() const
811 {
812   return mDisplayState;
813 }
814
815 void Popup::LayoutPopup()
816 {
817   mLayoutDirty = false;
818
819   /* When animating in, we want to respect the origin applied to Self().
820    * For example, if zooming, not only will the final result be anchored to the
821    * selected point, but the zoom will originate from this point also.
822    *
823    * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT :
824    *
825    *       --------                --------
826    *       |X|                     |XXX|
827    *       |``        Animates     |XXX|
828    *       |             to:       |XXX|
829    *       |                       |````
830    *       |                       |
831    */
832   mPopupContainer.SetProperty(Actor::Property::PARENT_ORIGIN, Self().GetCurrentProperty<Vector3>(Actor::Property::PARENT_ORIGIN));
833   mPopupContainer.SetProperty(Actor::Property::ANCHOR_POINT, Self().GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT));
834
835   // If there is only a title, use less padding.
836   if(mTitle)
837   {
838     if(!mContent && !mFooter)
839     {
840       mTitle.SetProperty(Actor::Property::PADDING, DEFAULT_TITLE_ONLY_PADDING);
841     }
842     else
843     {
844       mTitle.SetProperty(Actor::Property::PADDING, DEFAULT_TITLE_PADDING);
845     }
846   }
847
848   // Allow derived classes to perform any layout they may need to do.
849   OnLayoutSetup();
850
851   // Update background visibility.
852   mPopupContainer.SetProperty(Actor::Property::VISIBLE, !(!mFooter && mPopupLayout.GetChildCount() == 0));
853
854   // Create / destroy / position the tail as needed.
855   LayoutTail();
856
857   // Setup any layout and initialisation required for the selected animation.
858   LayoutAnimation();
859
860   RelayoutRequest();
861 }
862
863 void Popup::LayoutTail()
864 {
865   // Removes the tail actor.
866   if(mTailImage && mTailImage.GetParent())
867   {
868     mTailImage.GetParent().Remove(mTailImage);
869     mTailImage.Reset();
870   }
871
872   if(!mTailVisible)
873   {
874     return;
875   }
876
877   const Vector3& parentOrigin = GetTailPosition();
878   Vector3        position;
879   std::string    image;
880   Vector3        anchorPoint;
881
882   // depending on position of tail around ParentOrigin, a different tail image is used...
883   if(parentOrigin.y < Math::MACHINE_EPSILON_1)
884   {
885     image       = mTailUpImage;
886     anchorPoint = AnchorPoint::BOTTOM_CENTER;
887     position.y  = mBackgroundBorder.top;
888   }
889   else if(parentOrigin.y > (1.0f - Math::MACHINE_EPSILON_1))
890   {
891     image       = mTailDownImage;
892     anchorPoint = AnchorPoint::TOP_CENTER;
893     position.y  = -mBackgroundBorder.bottom;
894   }
895   else if(parentOrigin.x < Math::MACHINE_EPSILON_1)
896   {
897     image       = mTailLeftImage;
898     anchorPoint = AnchorPoint::CENTER_RIGHT;
899     position.x  = mBackgroundBorder.left;
900   }
901   else if(parentOrigin.x > (1.0f - Math::MACHINE_EPSILON_1))
902   {
903     image       = mTailRightImage;
904     anchorPoint = AnchorPoint::CENTER_LEFT;
905     position.x  = -mBackgroundBorder.right;
906   }
907
908   if(!image.empty())
909   {
910     // Adds the tail actor.
911     mTailImage = Toolkit::ImageView::New(image);
912     mTailImage.SetProperty(Dali::Actor::Property::NAME, "tailImage");
913     mTailImage.SetProperty(Actor::Property::PARENT_ORIGIN, parentOrigin);
914     mTailImage.SetProperty(Actor::Property::ANCHOR_POINT, anchorPoint);
915     mTailImage.SetProperty(Actor::Property::POSITION, position);
916
917     if(mPopupBackgroundImage)
918     {
919       mPopupBackgroundImage.Add(mTailImage);
920     }
921   }
922 }
923
924 void Popup::SetContextualMode(Toolkit::Popup::ContextualMode mode)
925 {
926   mContextualMode = mode;
927   mLayoutDirty    = true;
928 }
929
930 Toolkit::Popup::ContextualMode Popup::GetContextualMode() const
931 {
932   return mContextualMode;
933 }
934
935 Toolkit::Control Popup::CreateBacking()
936 {
937   Toolkit::Control backing = Control::New();
938   backing.SetProperty(Toolkit::Control::Property::BACKGROUND,
939                       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)));
940   backing.SetProperty(Dali::Actor::Property::NAME, "popupBacking");
941
942   // Must always be positioned top-left of stage, regardless of parent.
943   backing.SetProperty(Actor::Property::INHERIT_POSITION, false);
944
945   // Always the full size of the stage.
946   backing.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
947   backing.SetProperty(Actor::Property::SIZE, Stage::GetCurrent().GetSize());
948
949   // Catch events.
950   backing.SetProperty(Actor::Property::SENSITIVE, true);
951
952   // Default to being transparent.
953   backing.SetProperty(Actor::Property::COLOR_ALPHA, 0.0f);
954   backing.WheelEventSignal().Connect(this, &Popup::OnBackingWheelEvent);
955   return backing;
956 }
957
958 Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
959 {
960   return mTouchedOutsideSignal;
961 }
962
963 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
964 {
965   return mShowingSignal;
966 }
967
968 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
969 {
970   return mShownSignal;
971 }
972
973 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
974 {
975   return mHidingSignal;
976 }
977
978 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
979 {
980   return mHiddenSignal;
981 }
982
983 void Popup::SetTailVisibility(bool visible)
984 {
985   mTailVisible = visible;
986   mLayoutDirty = true;
987 }
988
989 const bool Popup::IsTailVisible() const
990 {
991   return mTailVisible;
992 }
993
994 void Popup::SetTailPosition(Vector3 position)
995 {
996   mTailPosition = position;
997   mLayoutDirty  = true;
998 }
999
1000 const Vector3& Popup::GetTailPosition() const
1001 {
1002   return mTailPosition;
1003 }
1004
1005 void Popup::SetAnimationDuration(float duration)
1006 {
1007   mAnimationDuration = duration;
1008   mLayoutDirty       = true;
1009 }
1010
1011 float Popup::GetAnimationDuration() const
1012 {
1013   return mAnimationDuration;
1014 }
1015
1016 void Popup::SetAnimationMode(Toolkit::Popup::AnimationMode animationMode)
1017 {
1018   mAnimationMode = animationMode;
1019   mLayoutDirty   = true;
1020 }
1021
1022 Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const
1023 {
1024   return mAnimationMode;
1025 }
1026
1027 void Popup::SetEntryAnimationData(const Property::Map& map)
1028 {
1029   mEntryAnimationData.Clear();
1030   Scripting::NewAnimation(map, mEntryAnimationData);
1031 }
1032
1033 void Popup::SetExitAnimationData(const Property::Map& map)
1034 {
1035   mExitAnimationData.Clear();
1036   Scripting::NewAnimation(map, mExitAnimationData);
1037 }
1038
1039 void Popup::UpdateBackgroundPositionAndSize()
1040 {
1041   if(mPopupBackgroundImage)
1042   {
1043     mPopupBackgroundImage.SetResizePolicy(ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS);
1044     mPopupBackgroundImage.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(mBackgroundBorder.left + mBackgroundBorder.right, mBackgroundBorder.top + mBackgroundBorder.bottom, 0.0f));
1045
1046     // Adjust the position of the background so the transparent areas are set appropriately
1047     mPopupBackgroundImage.SetProperty(Actor::Property::POSITION, Vector2((mBackgroundBorder.right - mBackgroundBorder.left) * 0.5f, (mBackgroundBorder.bottom - mBackgroundBorder.top) * 0.5f));
1048   }
1049 }
1050
1051 void Popup::SetAutoHideDelay(int delay)
1052 {
1053   mAutoHideDelay = delay;
1054 }
1055
1056 int Popup::GetAutoHideDelay() const
1057 {
1058   return mAutoHideDelay;
1059 }
1060
1061 void Popup::SetBackingEnabled(bool enabled)
1062 {
1063   mBackingEnabled = enabled;
1064   mLayoutDirty    = true;
1065 }
1066
1067 const bool Popup::IsBackingEnabled() const
1068 {
1069   return mBackingEnabled;
1070 }
1071
1072 void Popup::SetBackingColor(Vector4 color)
1073 {
1074   mBackingColor = color;
1075   mBacking.SetBackgroundColor(Vector4(color.r, color.g, color.b, 1.0f));
1076   mLayoutDirty = true;
1077 }
1078
1079 const Vector4& Popup::GetBackingColor() const
1080 {
1081   return mBackingColor;
1082 }
1083
1084 void Popup::SetTailUpImage(std::string image)
1085 {
1086   mTailUpImage = image;
1087   mLayoutDirty = true;
1088   LayoutTail();
1089 }
1090
1091 const std::string& Popup::GetTailUpImage() const
1092 {
1093   return mTailUpImage;
1094 }
1095
1096 void Popup::SetTailDownImage(std::string image)
1097 {
1098   mTailDownImage = image;
1099   mLayoutDirty   = true;
1100   LayoutTail();
1101 }
1102
1103 const std::string& Popup::GetTailDownImage() const
1104 {
1105   return mTailDownImage;
1106 }
1107
1108 void Popup::SetTailLeftImage(std::string image)
1109 {
1110   mTailLeftImage = image;
1111   mLayoutDirty   = true;
1112   LayoutTail();
1113 }
1114
1115 const std::string& Popup::GetTailLeftImage() const
1116 {
1117   return mTailLeftImage;
1118 }
1119
1120 void Popup::SetTailRightImage(std::string image)
1121 {
1122   mTailRightImage = image;
1123   mLayoutDirty    = true;
1124   LayoutTail();
1125 }
1126
1127 const std::string& Popup::GetTailRightImage() const
1128 {
1129   return mTailRightImage;
1130 }
1131
1132 void Popup::SetTouchTransparent(bool enabled)
1133 {
1134   if(mTouchTransparent != enabled)
1135   {
1136     mTouchTransparent = enabled;
1137     SetupTouch();
1138   }
1139 }
1140
1141 const bool Popup::IsTouchTransparent() const
1142 {
1143   return mTouchTransparent;
1144 }
1145
1146 void Popup::SetProperty(BaseObject* object, Property::Index propertyIndex, const Property::Value& value)
1147 {
1148   Toolkit::Popup popup = Toolkit::Popup::DownCast(Dali::BaseHandle(object));
1149
1150   if(popup)
1151   {
1152     Popup& popupImpl(GetImpl(popup));
1153
1154     switch(propertyIndex)
1155     {
1156       case Toolkit::Popup::Property::TITLE:
1157       {
1158         Property::Map valueMap;
1159         if(value.Get(valueMap))
1160         {
1161           popupImpl.SetTitle(Scripting::NewActor(valueMap));
1162         }
1163         break;
1164       }
1165       case Toolkit::Popup::Property::CONTENT:
1166       {
1167         Property::Map valueMap;
1168         if(value.Get(valueMap))
1169         {
1170           popupImpl.SetContent(Scripting::NewActor(valueMap));
1171         }
1172         break;
1173       }
1174       case Toolkit::Popup::Property::FOOTER:
1175       {
1176         Property::Map valueMap;
1177         if(value.Get(valueMap))
1178         {
1179           popupImpl.SetFooter(Scripting::NewActor(valueMap));
1180         }
1181         break;
1182       }
1183       case Toolkit::Popup::Property::DISPLAY_STATE:
1184       {
1185         std::string valueString;
1186         if(value.Get(valueString))
1187         {
1188           Toolkit::Popup::DisplayState displayState(Toolkit::Popup::HIDDEN);
1189           if(Scripting::GetEnumeration<Toolkit::Popup::DisplayState>(valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState))
1190           {
1191             popupImpl.SetDisplayState(displayState);
1192           }
1193         }
1194         break;
1195       }
1196       case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1197       {
1198         bool valueBool;
1199         if(value.Get(valueBool))
1200         {
1201           popupImpl.SetTouchTransparent(valueBool);
1202         }
1203         break;
1204       }
1205       case Toolkit::Popup::Property::TAIL_VISIBILITY:
1206       {
1207         bool valueBool;
1208         if(value.Get(valueBool))
1209         {
1210           popupImpl.SetTailVisibility(valueBool);
1211         }
1212         break;
1213       }
1214       case Toolkit::Popup::Property::TAIL_POSITION:
1215       {
1216         Vector3 valueVector3;
1217         if(value.Get(valueVector3))
1218         {
1219           popupImpl.SetTailPosition(valueVector3);
1220         }
1221         break;
1222       }
1223       case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1224       {
1225         std::string valueString;
1226         if(value.Get(valueString))
1227         {
1228           Toolkit::Popup::ContextualMode contextualMode(Toolkit::Popup::BELOW);
1229           if(Scripting::GetEnumeration<Toolkit::Popup::ContextualMode>(valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode))
1230           {
1231             popupImpl.SetContextualMode(contextualMode);
1232           }
1233         }
1234         break;
1235       }
1236       case Toolkit::Popup::Property::ANIMATION_DURATION:
1237       {
1238         float valueFloat;
1239         if(value.Get(valueFloat))
1240         {
1241           popupImpl.SetAnimationDuration(valueFloat);
1242         }
1243         break;
1244       }
1245       case Toolkit::Popup::Property::ANIMATION_MODE:
1246       {
1247         std::string valueString;
1248         if(value.Get(valueString))
1249         {
1250           Toolkit::Popup::AnimationMode animationMode(Toolkit::Popup::FADE);
1251           if(Scripting::GetEnumeration<Toolkit::Popup::AnimationMode>(valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode))
1252           {
1253             popupImpl.SetAnimationMode(animationMode);
1254           }
1255         }
1256         break;
1257       }
1258       case Toolkit::Popup::Property::ENTRY_ANIMATION:
1259       {
1260         Property::Map valueMap;
1261         if(value.Get(valueMap))
1262         {
1263           popupImpl.SetEntryAnimationData(valueMap);
1264         }
1265         break;
1266       }
1267       case Toolkit::Popup::Property::EXIT_ANIMATION:
1268       {
1269         Property::Map valueMap;
1270         if(value.Get(valueMap))
1271         {
1272           popupImpl.SetExitAnimationData(valueMap);
1273         }
1274         break;
1275       }
1276       case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1277       {
1278         int valueInt;
1279         if(value.Get(valueInt))
1280         {
1281           popupImpl.SetAutoHideDelay(valueInt);
1282         }
1283         break;
1284       }
1285       case Toolkit::Popup::Property::BACKING_ENABLED:
1286       {
1287         bool valueBool;
1288         if(value.Get(valueBool))
1289         {
1290           popupImpl.SetBackingEnabled(valueBool);
1291         }
1292         break;
1293       }
1294       case Toolkit::Popup::Property::BACKING_COLOR:
1295       {
1296         Vector4 valueVector4;
1297         if(value.Get(valueVector4))
1298         {
1299           popupImpl.SetBackingColor(valueVector4);
1300         }
1301         break;
1302       }
1303       case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1304       {
1305         std::string valueString;
1306         if(value.Get(valueString))
1307         {
1308           Toolkit::ImageView actor = Toolkit::ImageView::New(valueString);
1309           popupImpl.SetPopupBackgroundImage(actor);
1310         }
1311         break;
1312       }
1313       case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1314       {
1315         bool valueUpdated = false;
1316
1317         Vector4 valueVector4;
1318         if(value.Get(popupImpl.mBackgroundBorder))
1319         {
1320           valueUpdated = true;
1321         }
1322         else if(value.Get(valueVector4))
1323         {
1324           popupImpl.mBackgroundBorder.left   = valueVector4.x;
1325           popupImpl.mBackgroundBorder.right  = valueVector4.y;
1326           popupImpl.mBackgroundBorder.bottom = valueVector4.z;
1327           popupImpl.mBackgroundBorder.top    = valueVector4.w;
1328           valueUpdated                       = true;
1329         }
1330
1331         if(valueUpdated)
1332         {
1333           popupImpl.LayoutTail();                      // Update the tail if required
1334           popupImpl.UpdateBackgroundPositionAndSize(); // Update the background's size and position
1335         }
1336         break;
1337       }
1338       case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1339       {
1340         std::string valueString;
1341         if(value.Get(valueString))
1342         {
1343           popupImpl.SetTailUpImage(valueString);
1344         }
1345         break;
1346       }
1347       case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1348       {
1349         std::string valueString;
1350         if(value.Get(valueString))
1351         {
1352           popupImpl.SetTailDownImage(valueString);
1353         }
1354         break;
1355       }
1356       case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1357       {
1358         std::string valueString;
1359         if(value.Get(valueString))
1360         {
1361           popupImpl.SetTailLeftImage(valueString);
1362         }
1363         break;
1364       }
1365       case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1366       {
1367         std::string valueString;
1368         if(value.Get(valueString))
1369         {
1370           popupImpl.SetTailRightImage(valueString);
1371         }
1372         break;
1373       }
1374     }
1375   }
1376 }
1377
1378 Property::Value Popup::GetProperty(BaseObject* object, Property::Index propertyIndex)
1379 {
1380   Property::Value value;
1381
1382   Toolkit::Popup popup = Toolkit::Popup::DownCast(Dali::BaseHandle(object));
1383
1384   if(popup)
1385   {
1386     Popup& popupImpl(GetImpl(popup));
1387
1388     switch(propertyIndex)
1389     {
1390       case Toolkit::Popup::Property::TITLE:
1391       {
1392         Property::Map map;
1393         Scripting::CreatePropertyMap(popupImpl.GetTitle(), map);
1394         value = map;
1395         break;
1396       }
1397       case Toolkit::Popup::Property::CONTENT:
1398       {
1399         Property::Map map;
1400         Scripting::CreatePropertyMap(popupImpl.GetContent(), map);
1401         value = map;
1402         break;
1403       }
1404       case Toolkit::Popup::Property::FOOTER:
1405       {
1406         Property::Map map;
1407         Scripting::CreatePropertyMap(popupImpl.GetFooter(), map);
1408         value = map;
1409         break;
1410       }
1411       case Toolkit::Popup::Property::DISPLAY_STATE:
1412       {
1413         value = Scripting::GetLinearEnumerationName<Toolkit::Popup::DisplayState>(popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount);
1414         break;
1415       }
1416       case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1417       {
1418         value = popupImpl.IsTouchTransparent();
1419         break;
1420       }
1421       case Toolkit::Popup::Property::TAIL_VISIBILITY:
1422       {
1423         value = popupImpl.IsTailVisible();
1424         break;
1425       }
1426       case Toolkit::Popup::Property::TAIL_POSITION:
1427       {
1428         value = popupImpl.GetTailPosition();
1429         break;
1430       }
1431       case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1432       {
1433         value = Scripting::GetLinearEnumerationName<Toolkit::Popup::ContextualMode>(popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount);
1434         break;
1435       }
1436       case Toolkit::Popup::Property::ANIMATION_DURATION:
1437       {
1438         value = popupImpl.GetAnimationDuration();
1439         break;
1440       }
1441       case Toolkit::Popup::Property::ANIMATION_MODE:
1442       {
1443         value = Scripting::GetLinearEnumerationName<Toolkit::Popup::AnimationMode>(popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount);
1444         break;
1445       }
1446       case Toolkit::Popup::Property::ENTRY_ANIMATION:
1447       {
1448         // Note: Cannot retrieve property map from animation.
1449         Property::Map map;
1450         value = map;
1451         break;
1452       }
1453       case Toolkit::Popup::Property::EXIT_ANIMATION:
1454       {
1455         // Note: Cannot retrieve property map from animation.
1456         Property::Map map;
1457         value = map;
1458         break;
1459       }
1460       case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1461       {
1462         value = popupImpl.GetAutoHideDelay();
1463         break;
1464       }
1465       case Toolkit::Popup::Property::BACKING_ENABLED:
1466       {
1467         value = popupImpl.IsBackingEnabled();
1468         break;
1469       }
1470       case Toolkit::Popup::Property::BACKING_COLOR:
1471       {
1472         value = popupImpl.GetBackingColor();
1473         break;
1474       }
1475       case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1476       {
1477         Toolkit::ImageView imageView = Toolkit::ImageView::DownCast(popupImpl.GetPopupBackgroundImage());
1478         if(imageView)
1479         {
1480           value = imageView.GetProperty(Toolkit::ImageView::Property::IMAGE);
1481         }
1482         break;
1483       }
1484       case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1485       {
1486         value = popupImpl.mBackgroundBorder;
1487         break;
1488       }
1489       case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1490       {
1491         value = popupImpl.GetTailUpImage();
1492         break;
1493       }
1494       case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1495       {
1496         value = popupImpl.GetTailDownImage();
1497         break;
1498       }
1499       case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1500       {
1501         value = popupImpl.GetTailLeftImage();
1502         break;
1503       }
1504       case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1505       {
1506         value = popupImpl.GetTailRightImage();
1507         break;
1508       }
1509     }
1510   }
1511
1512   return value;
1513 }
1514
1515 bool Popup::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
1516 {
1517   Dali::BaseHandle handle(object);
1518
1519   bool           connected(true);
1520   Toolkit::Popup popup = Toolkit::Popup::DownCast(handle);
1521
1522   if(0 == strcmp(signalName.c_str(), SIGNAL_TOUCHED_OUTSIDE))
1523   {
1524     popup.OutsideTouchedSignal().Connect(tracker, functor);
1525   }
1526   else if(0 == strcmp(signalName.c_str(), SIGNAL_SHOWING))
1527   {
1528     popup.ShowingSignal().Connect(tracker, functor);
1529   }
1530   else if(0 == strcmp(signalName.c_str(), SIGNAL_SHOWN))
1531   {
1532     popup.ShownSignal().Connect(tracker, functor);
1533   }
1534   else if(0 == strcmp(signalName.c_str(), SIGNAL_HIDING))
1535   {
1536     popup.HidingSignal().Connect(tracker, functor);
1537   }
1538   else if(0 == strcmp(signalName.c_str(), SIGNAL_HIDDEN))
1539   {
1540     popup.HiddenSignal().Connect(tracker, functor);
1541   }
1542   else
1543   {
1544     // signalName does not match any signal
1545     connected = false;
1546   }
1547
1548   return connected;
1549 }
1550
1551 bool Popup::OnBackingTouched(Actor actor, const TouchEvent& touch)
1552 {
1553   // Allow events to pass through if the backing isn't the hit-actor
1554   if((touch.GetHitActor(0) == actor) &&
1555      (touch.GetPointCount() > 0) &&
1556      (touch.GetState(0) == PointState::DOWN))
1557   {
1558     // Guard against destruction during signal emission.
1559     Toolkit::Popup handle(GetOwner());
1560
1561     mTouchedOutsideSignal.Emit();
1562   }
1563
1564   return false;
1565 }
1566
1567 bool Popup::OnBackingWheelEvent(Actor actor, const WheelEvent& event)
1568 {
1569   // Allow events to pass through if touch transparency is enabled.
1570   if(mTouchTransparent)
1571   {
1572     return false;
1573   }
1574
1575   return true;
1576 }
1577
1578 bool Popup::OnDialogTouched(Actor actor, const TouchEvent& touch)
1579 {
1580   // Only connecting this so the backing does not become the default hit-actor and inadvertently closes the popup
1581   return false;
1582 }
1583
1584 void Popup::OnSceneConnection(int depth)
1585 {
1586   mLayoutDirty = true;
1587   RelayoutRequest();
1588
1589   Control::OnSceneConnection(depth);
1590 }
1591
1592 void Popup::OnChildAdd(Actor& child)
1593 {
1594   // Re-parent any children added by user to the body layer.
1595   if(mAlterAddedChild)
1596   {
1597     SetContent(child);
1598   }
1599   else
1600   {
1601     mLayoutDirty = true;
1602     RelayoutRequest();
1603   }
1604
1605   Control::OnChildAdd(child);
1606 }
1607
1608 void Popup::LayoutContext(const Vector2& size)
1609 {
1610   // Do nothing if not in a contextual mode (or there is no parent context).
1611   Actor self   = Self();
1612   Actor parent = self.GetParent();
1613   if((mContextualMode == Toolkit::Popup::NON_CONTEXTUAL) || !parent)
1614   {
1615     return;
1616   }
1617
1618   mPopupContainer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
1619   // We always anchor to the CENTER, rather than a different anchor point for each contextual
1620   // mode to allow code-reuse of the bound checking code (for maintainability).
1621   mPopupContainer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
1622
1623   // Setup with some pre-calculations for speed.
1624   Vector3 halfStageSize(Stage().GetCurrent().GetSize() / 2.0f);
1625   Vector3 parentPosition(parent.GetCurrentProperty<Vector3>(Actor::Property::POSITION));
1626   Vector2 halfSize(size / 2.0f);
1627   Vector2 halfParentSize(parent.GetRelayoutSize(Dimension::WIDTH) / 2.0f, parent.GetRelayoutSize(Dimension::HEIGHT) / 2.0f);
1628   Vector3 newPosition(Vector3::ZERO);
1629
1630   // Perform different positioning based on the specified contextual layout mode.
1631   switch(mContextualMode)
1632   {
1633     case Toolkit::Popup::BELOW:
1634     {
1635       newPosition.x += halfSize.x - halfParentSize.x;
1636       newPosition.y += halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1637       break;
1638     }
1639     case Toolkit::Popup::ABOVE:
1640     {
1641       newPosition.x += halfSize.x - halfParentSize.x;
1642       newPosition.y -= halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1643       break;
1644     }
1645     case Toolkit::Popup::RIGHT:
1646     {
1647       newPosition.x += halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1648       newPosition.y += halfSize.y - halfParentSize.y;
1649       break;
1650     }
1651     case Toolkit::Popup::LEFT:
1652     {
1653       newPosition.x -= halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1654       newPosition.y += halfSize.y - halfParentSize.y;
1655       break;
1656     }
1657     case Toolkit::Popup::NON_CONTEXTUAL:
1658     {
1659       // Code won't reach here (caught earlier).
1660       break;
1661     }
1662   }
1663
1664   // On-screen position checking.
1665   // Check new position is not too far right. If so, correct it.
1666   // Note: Check for right rather than left first, so if popup is too wide, the left check overrides
1667   // the right check and we at least see the left portion of the popup (as this is more useful).
1668   if(newPosition.x >= (halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x))
1669   {
1670     newPosition.x = halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x;
1671   }
1672   // Check new position is not too far left. If so, correct it.
1673   if(newPosition.x < halfSize.x - (parentPosition.x + halfStageSize.x) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x)
1674   {
1675     newPosition.x = halfSize.x - (parentPosition.x + halfStageSize.x) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x; // - parentSize.x;
1676   }
1677   // Check new position is not too far down. If so, correct it.
1678   if(newPosition.y >= (halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y))
1679   {
1680     newPosition.y = halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1681   }
1682   // Check new position is not too far up. If so, correct it.
1683   if(newPosition.y < halfSize.y - (parentPosition.y + halfStageSize.y) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y)
1684   {
1685     newPosition.y = halfSize.y - (parentPosition.y + halfStageSize.y) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1686   }
1687
1688   // Set the final position.
1689   mPopupContainer.SetProperty(Actor::Property::POSITION, newPosition);
1690 }
1691
1692 void Popup::OnRelayout(const Vector2& size, RelayoutContainer& container)
1693 {
1694   Vector2 useSize(size);
1695
1696   // Use the Popup layouts size, unless requested to use a fixed size.
1697   // In which case take the size set for the Popup itself.
1698   ResizePolicy::Type widthPolicy  = Self().GetResizePolicy(Dimension::WIDTH);
1699   ResizePolicy::Type heightPolicy = Self().GetResizePolicy(Dimension::HEIGHT);
1700
1701   // Width calculations:
1702   if(widthPolicy == ResizePolicy::USE_NATURAL_SIZE || widthPolicy == ResizePolicy::FIT_TO_CHILDREN)
1703   {
1704     // If we using a child-based policy, take the size from the popup layout.
1705     mPopupLayout.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH);
1706     useSize.width = mPopupLayout.GetRelayoutSize(Dimension::WIDTH);
1707
1708     mPopupLayout.SetFitWidth(0u);
1709   }
1710   else
1711   {
1712     // If we using a parent-based policy, take the size from the popup object itself (self).
1713     mPopupLayout.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH);
1714
1715     mPopupLayout.SetFixedWidth(0u, useSize.width);
1716   }
1717
1718   // Height calculations:
1719   // Title: Let the title be as high as it needs to be.
1720   mPopupLayout.SetFitHeight(0u);
1721
1722   // Footer: Convert the footer's resize policy to a TableView row policy.
1723   if(mFooter)
1724   {
1725     ResizePolicy::Type footerHeightPolicy = mFooter.GetResizePolicy(Dimension::HEIGHT);
1726     if((footerHeightPolicy == ResizePolicy::USE_NATURAL_SIZE) ||
1727        (footerHeightPolicy == ResizePolicy::FIT_TO_CHILDREN))
1728     {
1729       mPopupLayout.SetFitHeight(2u);
1730     }
1731     else if(footerHeightPolicy == ResizePolicy::FIXED)
1732     {
1733       mPopupLayout.SetFixedHeight(2u, mFooter.GetRelayoutSize(Dimension::HEIGHT));
1734     }
1735     else
1736     {
1737       mPopupLayout.SetRelativeHeight(2u, 1.0f);
1738     }
1739   }
1740   else
1741   {
1742     mPopupLayout.SetFixedHeight(2u, 0.0f);
1743   }
1744
1745   // Popup contents: Adjust the tableview's policies based on the popup's policies.
1746   if(heightPolicy == ResizePolicy::USE_NATURAL_SIZE || heightPolicy == ResizePolicy::FIT_TO_CHILDREN)
1747   {
1748     mPopupLayout.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
1749
1750     // Let both the contents expand as necessary.
1751     mPopupLayout.SetFitHeight(1u);
1752     useSize.height = mPopupLayout.GetRelayoutSize(Dimension::HEIGHT);
1753   }
1754   else
1755   {
1756     mPopupLayout.SetResizePolicy(heightPolicy, Dimension::HEIGHT);
1757
1758     // Let the content expand to fill the remaining space.
1759     mPopupLayout.SetRelativeHeight(1u, 1.0f);
1760     mPopupLayout.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT);
1761   }
1762
1763   // Relayout the popup-layout to give it it's new size this frame.
1764   container.Add(mPopupLayout, useSize);
1765
1766   if(mContent)
1767   {
1768     container.Add(mContent, Vector2(mContent.GetRelayoutSize(Dimension::WIDTH), mContent.GetRelayoutSize(Dimension::HEIGHT)));
1769   }
1770
1771   // Perform contextual layout setup if required.
1772   // This is done each time in case the parent moves.
1773   // This will have no effect if no contextual mode is selected.
1774   LayoutContext(useSize);
1775 }
1776
1777 void Popup::OnSetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension)
1778 {
1779   // To get the popup to emulate fit-to-children, we need to actually set use-natural-size.
1780   if((dimension & Dimension::HEIGHT) && (policy == ResizePolicy::FIT_TO_CHILDREN))
1781   {
1782     Self().SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
1783   }
1784
1785   mLayoutDirty = true;
1786   return;
1787 }
1788
1789 Vector3 Popup::GetNaturalSize()
1790 {
1791   return mPopupLayout.GetNaturalSize();
1792 }
1793
1794 float Popup::GetHeightForWidth(float width)
1795 {
1796   return mPopupLayout.GetHeightForWidth(width);
1797 }
1798
1799 float Popup::GetWidthForHeight(float height)
1800 {
1801   return mPopupLayout.GetWidthForHeight(height);
1802 }
1803
1804 bool Popup::OnKeyEvent(const KeyEvent& event)
1805 {
1806   // Allow events to pass through if touch transparency is enabled.
1807   if(mTouchTransparent)
1808   {
1809     return false;
1810   }
1811
1812   bool consumed = false;
1813
1814   if(event.GetState() == KeyEvent::DOWN)
1815   {
1816     if(event.GetKeyCode() == Dali::DALI_KEY_ESCAPE || event.GetKeyCode() == Dali::DALI_KEY_BACK)
1817     {
1818       SetDisplayState(Toolkit::Popup::HIDDEN);
1819       consumed = true;
1820     }
1821   }
1822
1823   return consumed;
1824 }
1825
1826 void Popup::AddFocusableChildrenRecursive(Actor parent, std::vector<Actor>& focusableActors)
1827 {
1828   if(parent)
1829   {
1830     Toolkit::Control control       = Toolkit::Control::DownCast(parent);
1831     bool             layoutControl = control && GetImplementation(control).IsKeyboardNavigationSupported();
1832
1833     if(parent.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) || layoutControl)
1834     {
1835       focusableActors.push_back(parent);
1836
1837       if(!layoutControl)
1838       {
1839         for(unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i)
1840         {
1841           Actor child(parent.GetChildAt(i));
1842           AddFocusableChildrenRecursive(child, focusableActors);
1843         }
1844       }
1845     }
1846   }
1847 }
1848
1849 void Popup::AddFocusableChildren(Actor parent, std::vector<Actor>& focusableActors)
1850 {
1851   if(parent)
1852   {
1853     Toolkit::Control control = Toolkit::Control::DownCast(parent);
1854     if(!GetImplementation(control).IsKeyboardNavigationSupported())
1855     {
1856       for(unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i)
1857       {
1858         Actor child(parent.GetChildAt(i));
1859         AddFocusableChildrenRecursive(child, focusableActors);
1860       }
1861     }
1862     else
1863     {
1864       focusableActors.push_back(parent);
1865     }
1866   }
1867 }
1868
1869 Actor Popup::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
1870 {
1871   std::string currentStr;
1872   if(currentFocusedActor)
1873   {
1874     currentStr = currentFocusedActor.GetProperty<std::string>(Dali::Actor::Property::NAME);
1875   }
1876
1877   Actor nextFocusableActor(currentFocusedActor);
1878   Actor currentFocusGroup;
1879   if(currentFocusedActor)
1880   {
1881     currentFocusGroup = KeyboardFocusManager::Get().GetFocusGroup(currentFocusedActor);
1882   }
1883
1884   // TODO: Needs to be optimised
1885   // The following statement checks that if we have a current focused actor, then the current focus group is not the popup content or footer.
1886   // This is to detect if the focus is currently outside the popup, and if so, move it inside.
1887   if(!currentFocusedActor ||
1888      (currentFocusedActor && ((!mContent || (currentFocusGroup != mContent)) && (!mFooter || (currentFocusGroup != mFooter)))))
1889   {
1890     // The current focused actor is not within popup.
1891     if(mContent && mContent.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
1892     {
1893       // If the content is focusable, move the focus to the content.
1894       nextFocusableActor = mContent;
1895     }
1896     else if(mFooter && mFooter.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
1897     {
1898       // If the footer is focusable, move the focus to the footer.
1899       nextFocusableActor = mFooter;
1900     }
1901   }
1902   else
1903   {
1904     // Rebuild the focus chain because controls or content can be added or removed dynamically
1905     std::vector<Actor> focusableActors;
1906
1907     AddFocusableChildren(mContent, focusableActors);
1908     AddFocusableChildren(mFooter, focusableActors);
1909
1910     std::vector<Actor>::iterator endIterator     = focusableActors.end();
1911     std::vector<Actor>::iterator currentIterator = focusableActors.begin();
1912     for(std::vector<Actor>::iterator iterator = focusableActors.begin(); iterator != endIterator; ++iterator)
1913     {
1914       if(currentFocusedActor == *iterator)
1915       {
1916         currentIterator = iterator;
1917       }
1918     }
1919
1920     if(currentIterator != endIterator)
1921     {
1922       switch(direction)
1923       {
1924         case Toolkit::Control::KeyboardFocus::LEFT:
1925         {
1926           if(currentIterator == focusableActors.begin())
1927           {
1928             nextFocusableActor = *(endIterator - 1);
1929           }
1930           else
1931           {
1932             nextFocusableActor = *(currentIterator - 1);
1933           }
1934           break;
1935         }
1936         case Toolkit::Control::KeyboardFocus::RIGHT:
1937         {
1938           if(currentIterator == endIterator - 1)
1939           {
1940             nextFocusableActor = *(focusableActors.begin());
1941           }
1942           else
1943           {
1944             nextFocusableActor = *(currentIterator + 1);
1945           }
1946           break;
1947         }
1948
1949         case Toolkit::Control::KeyboardFocus::UP:
1950         {
1951           nextFocusableActor = *(focusableActors.begin());
1952           break;
1953         }
1954
1955         case Toolkit::Control::KeyboardFocus::DOWN:
1956         {
1957           nextFocusableActor = *(endIterator - 1);
1958           break;
1959         }
1960
1961         default:
1962         {
1963           break;
1964         }
1965       }
1966
1967       if(!nextFocusableActor)
1968       {
1969         DALI_LOG_WARNING("Can not decide next focusable actor\n");
1970       }
1971     }
1972   }
1973
1974   return nextFocusableActor;
1975 }
1976
1977 void Popup::SetupTouch()
1978 {
1979   if(!mTouchTransparent)
1980   {
1981     // Connect all the signals and set us up to consume all touch events
1982     mBacking.TouchedSignal().Connect(this, &Popup::OnBackingTouched);
1983     mPopupBackgroundImage.TouchedSignal().Connect(this, &Popup::OnDialogTouched);
1984     mPopupLayout.TouchedSignal().Connect(this, &Popup::OnDialogTouched);
1985     mLayer.SetProperty(Layer::Property::CONSUMES_TOUCH, true);
1986   }
1987   else
1988   {
1989     // We are touch transparent so disconnect all signals and ensure our layer does not consumed all touch events
1990     mBacking.TouchedSignal().Disconnect(this, &Popup::OnBackingTouched);
1991     mPopupBackgroundImage.TouchedSignal().Disconnect(this, &Popup::OnDialogTouched);
1992     mPopupLayout.TouchedSignal().Disconnect(this, &Popup::OnDialogTouched);
1993     mLayer.SetProperty(Layer::Property::CONSUMES_TOUCH, false);
1994   }
1995 }
1996
1997 std::string Popup::AccessibleImpl::GetNameRaw() const
1998 {
1999   auto        popup = Toolkit::Popup::DownCast(Self());
2000   std::string title;
2001   Actor       popupTitle = popup.GetTitle();
2002   if(popupTitle)
2003   {
2004     std::string titleText = popupTitle.GetProperty<std::string>(Toolkit::TextLabel::Property::TEXT);
2005     title                 = titleText;
2006   }
2007   else
2008   {
2009     Actor popupContent = popup.GetContent();
2010     if(popupContent)
2011     {
2012       std::string contentText = popupContent.GetProperty<std::string>(Toolkit::TextLabel::Property::TEXT);
2013       title                   = contentText;
2014     }
2015   }
2016   return title;
2017 }
2018
2019 Dali::Accessibility::States Popup::AccessibleImpl::CalculateStates()
2020 {
2021   auto states       = DevelControl::ControlAccessible::CalculateStates();
2022   auto popup        = Toolkit::Popup::DownCast(Self());
2023   auto displayState = popup.GetProperty<std::string>(Toolkit::Popup::Property::DISPLAY_STATE);
2024
2025   states[Dali::Accessibility::State::SHOWING] = (displayState == "SHOWN" || displayState == "SHOWING");
2026
2027   return states;
2028 }
2029
2030 } // namespace Internal
2031
2032 } // namespace Toolkit
2033
2034 } // namespace Dali