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