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