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