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