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