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