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