Changed control defaults to listen to style change
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / popup / popup-impl.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/popup/popup-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 #include <dali/devel-api/adaptor-framework/physical-keyboard.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/adaptor-framework/key.h>
27 #include <dali/public-api/animation/constraints.h>
28 #include <dali/public-api/common/stage.h>
29 #include <dali/public-api/events/key-event.h>
30 #include <dali/public-api/events/touch-data.h>
31 #include <dali/public-api/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( CONTROL_BEHAVIOUR_DEFAULT ) ),
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 want the popup to have key input focus when it is displayed
707     SetKeyInputFocus();
708
709     // We are displaying so bring the popup layer to the front, and set it visible so it is rendered.
710     mLayer.RaiseToTop();
711     mLayer.SetVisible( true );
712
713     // Set up the layout if this is the first display or the layout has become dirty.
714     if( mLayoutDirty )
715     {
716       // Bake-in any style and layout options to create the Popup layout.
717       LayoutPopup();
718     }
719
720     // Allow the popup to catch events.
721     mPopupLayout.SetSensitive( true );
722
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( Self().IsKeyboardFocusable() )
730       {
731         // Setup the actgor to start focus from.
732         Actor focusActor;
733         if( mContent && mContent.IsKeyboardFocusable() )
734         {
735           // If the content is focusable, move the focus to the content.
736           focusActor = mContent;
737         }
738         else if( mFooter && mFooter.IsKeyboardFocusable() )
739         {
740           // If the footer is focusable, move the focus to the footer.
741           focusActor = mFooter;
742         }
743         else
744         {
745           DALI_LOG_WARNING( "There is no focusable in popup\n" );
746         }
747
748         if( focusActor )
749         {
750           keyboardFocusManager.SetCurrentFocusActor( focusActor );
751         }
752       }
753     }
754   }
755   else // Not visible.
756   {
757     mDisplayState = Toolkit::Popup::HIDING;
758     ClearKeyInputFocus();
759
760     // Restore the keyboard focus when popup is hidden.
761     if( mPreviousFocusedActor && mPreviousFocusedActor.IsKeyboardFocusable() )
762     {
763       Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
764       if( keyboardFocusManager )
765       {
766         keyboardFocusManager.SetCurrentFocusActor( mPreviousFocusedActor );
767       }
768     }
769   }
770
771   // Perform animation.
772   StartTransitionAnimation( display );
773 }
774
775 Toolkit::Popup::DisplayState Popup::GetDisplayState() const
776 {
777   return mDisplayState;
778 }
779
780 void Popup::LayoutPopup()
781 {
782   mLayoutDirty = false;
783
784   /* When animating in, we want to respect the origin applied to Self().
785    * For example, if zooming, not only will the final result be anchored to the
786    * selected point, but the zoom will originate from this point also.
787    *
788    * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT :
789    *
790    *       --------                --------
791    *       |X|                     |XXX|
792    *       |``        Animates     |XXX|
793    *       |             to:       |XXX|
794    *       |                       |````
795    *       |                       |
796    */
797   mPopupContainer.SetParentOrigin( Self().GetCurrentParentOrigin() );
798   mPopupContainer.SetAnchorPoint( Self().GetCurrentAnchorPoint() );
799
800   // If there is only a title, use less padding.
801   if( mTitle )
802   {
803     if( !mContent && !mFooter )
804     {
805       mTitle.SetPadding( DEFAULT_TITLE_ONLY_PADDING );
806     }
807     else
808     {
809       mTitle.SetPadding( DEFAULT_TITLE_PADDING );
810     }
811   }
812
813   // Allow derived classes to perform any layout they may need to do.
814   OnLayoutSetup();
815
816   // Update background visibility.
817   mPopupContainer.SetVisible( !( !mFooter && mPopupLayout.GetChildCount() == 0 ) );
818
819   // Create / destroy / position the tail as needed.
820   LayoutTail();
821
822   // Setup any layout and initialisation required for the selected animation.
823   LayoutAnimation();
824
825   RelayoutRequest();
826 }
827
828 void Popup::LayoutTail()
829 {
830   // Removes the tail actor.
831   if( mTailImage && mTailImage.GetParent() )
832   {
833     mTailImage.GetParent().Remove( mTailImage );
834     mTailImage.Reset();
835   }
836
837   if( !mTailVisible )
838   {
839     return;
840   }
841
842   const Vector3& position = GetTailPosition();
843   std::string image;
844
845   // depending on position of tail around ParentOrigin, a different tail image is used...
846   if( position.y < Math::MACHINE_EPSILON_1 )
847   {
848     image = mTailUpImage;
849   }
850   else if( position.y > 1.0f - Math::MACHINE_EPSILON_1 )
851   {
852     image = mTailDownImage;
853   }
854   else if( position.x < Math::MACHINE_EPSILON_1 )
855   {
856     image = mTailLeftImage;
857   }
858   else if( position.x > 1.0f - Math::MACHINE_EPSILON_1 )
859   {
860     image = mTailRightImage;
861   }
862
863   if( !image.empty() )
864   {
865     // Adds the tail actor.
866     Image tail = ResourceImage::New( image );
867     mTailImage = Toolkit::ImageView::New( tail );
868     mTailImage.SetName( "tailImage" );
869     const Vector3 anchorPoint = AnchorPoint::BOTTOM_RIGHT - position;
870     mTailImage.SetParentOrigin( position );
871     mTailImage.SetAnchorPoint( anchorPoint );
872
873     mPopupContainer.Add( mTailImage );
874   }
875 }
876
877 void Popup::SetContextualMode( Toolkit::Popup::ContextualMode mode )
878 {
879   mContextualMode = mode;
880   mLayoutDirty = true;
881 }
882
883 Toolkit::Popup::ContextualMode Popup::GetContextualMode() const
884 {
885   return mContextualMode;
886 }
887
888 Toolkit::Control Popup::CreateBacking()
889 {
890   Toolkit::Control backing = Control::New();
891   backing.SetBackgroundColor( Vector4( mBackingColor.r, mBackingColor.g, mBackingColor.b, 1.0f ) );
892   backing.SetName( "popupBacking" );
893
894   // Must always be positioned top-left of stage, regardless of parent.
895   backing.SetInheritPosition(false);
896   backing.SetAnchorPoint( AnchorPoint::TOP_LEFT );
897
898   // Always the full size of the stage.
899   backing.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
900   backing.SetSize( Stage::GetCurrent().GetSize() );
901
902   // Catch events.
903   backing.SetSensitive( true );
904
905   // Default to being transparent.
906   backing.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f );
907   backing.TouchSignal().Connect( this, &Popup::OnBackingTouched );
908   backing.WheelEventSignal().Connect( this, &Popup::OnBackingWheelEvent );
909   return backing;
910 }
911
912 Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
913 {
914   return mTouchedOutsideSignal;
915 }
916
917 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
918 {
919   return mShowingSignal;
920 }
921
922 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
923 {
924   return mShownSignal;
925 }
926
927 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
928 {
929   return mHidingSignal;
930 }
931
932 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
933 {
934   return mHiddenSignal;
935 }
936
937 void Popup::SetTailVisibility( bool visible )
938 {
939   mTailVisible = visible;
940   mLayoutDirty = true;
941 }
942
943 const bool Popup::IsTailVisible() const
944 {
945   return mTailVisible;
946 }
947
948 void Popup::SetTailPosition( Vector3 position )
949 {
950   mTailPosition = position;
951   mLayoutDirty = true;
952 }
953
954 const Vector3& Popup::GetTailPosition() const
955 {
956   return mTailPosition;
957 }
958
959 void Popup::SetAnimationDuration( float duration )
960 {
961   mAnimationDuration = duration;
962   mLayoutDirty = true;
963 }
964
965 float Popup::GetAnimationDuration() const
966 {
967   return mAnimationDuration;
968 }
969
970 void Popup::SetAnimationMode( Toolkit::Popup::AnimationMode animationMode )
971 {
972   mAnimationMode = animationMode;
973   mLayoutDirty = true;
974 }
975
976 Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const
977 {
978   return mAnimationMode;
979 }
980
981 void Popup::SetEntryAnimationData( const Property::Map& map )
982 {
983   mEntryAnimationData.Clear();
984   Scripting::NewAnimation( map, mEntryAnimationData );
985 }
986
987 void Popup::SetExitAnimationData( const Property::Map& map )
988 {
989   mExitAnimationData.Clear();
990   Scripting::NewAnimation( map, mExitAnimationData );
991 }
992
993 void Popup::SetAutoHideDelay( int delay )
994 {
995   mAutoHideDelay = delay;
996 }
997
998 int Popup::GetAutoHideDelay() const
999 {
1000   return mAutoHideDelay;
1001 }
1002
1003 void Popup::SetBackingEnabled( bool enabled )
1004 {
1005   mBackingEnabled = enabled;
1006   mLayoutDirty = true;
1007 }
1008
1009 const bool Popup::IsBackingEnabled() const
1010 {
1011   return mBackingEnabled;
1012 }
1013
1014 void Popup::SetBackingColor( Vector4 color )
1015 {
1016   mBackingColor = color;
1017   mBacking.SetBackgroundColor( Vector4( color.r, color.g, color.b, 1.0f ) );
1018   mLayoutDirty = true;
1019 }
1020
1021 const Vector4& Popup::GetBackingColor() const
1022 {
1023   return mBackingColor;
1024 }
1025
1026 void Popup::SetTailUpImage( std::string image )
1027 {
1028   mTailUpImage = image;
1029   mLayoutDirty = true;
1030 }
1031
1032 const std::string& Popup::GetTailUpImage() const
1033 {
1034   return mTailUpImage;
1035 }
1036
1037 void Popup::SetTailDownImage( std::string image )
1038 {
1039   mTailDownImage = image;
1040   mLayoutDirty = true;
1041 }
1042
1043 const std::string& Popup::GetTailDownImage() const
1044 {
1045   return mTailDownImage;
1046 }
1047
1048 void Popup::SetTailLeftImage( std::string image )
1049 {
1050   mTailLeftImage = image;
1051   mLayoutDirty = true;
1052 }
1053
1054 const std::string& Popup::GetTailLeftImage() const
1055 {
1056   return mTailLeftImage;
1057 }
1058
1059 void Popup::SetTailRightImage( std::string image )
1060 {
1061   mTailRightImage = image;
1062   mLayoutDirty = true;
1063 }
1064
1065 const std::string& Popup::GetTailRightImage() const
1066 {
1067   return mTailRightImage;
1068 }
1069
1070 void Popup::SetTouchTransparent( bool enabled )
1071 {
1072   mTouchTransparent = enabled;
1073 }
1074
1075 const bool Popup::IsTouchTransparent() const
1076 {
1077   return mTouchTransparent;
1078 }
1079
1080 void Popup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1081 {
1082   Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1083
1084   if ( popup )
1085   {
1086     Popup& popupImpl( GetImpl( popup ) );
1087
1088     switch ( propertyIndex )
1089     {
1090       case Toolkit::Popup::Property::TITLE:
1091       {
1092         Property::Map valueMap;
1093         if( value.Get( valueMap ) )
1094         {
1095           popupImpl.SetTitle( Scripting::NewActor( valueMap ) );
1096         }
1097         break;
1098       }
1099       case Toolkit::Popup::Property::CONTENT:
1100       {
1101         Property::Map valueMap;
1102         if( value.Get( valueMap ) )
1103         {
1104           popupImpl.SetContent( Scripting::NewActor( valueMap ) );
1105         }
1106         break;
1107       }
1108       case Toolkit::Popup::Property::FOOTER:
1109       {
1110         Property::Map valueMap;
1111         if( value.Get( valueMap ) )
1112         {
1113           popupImpl.SetFooter( Scripting::NewActor( valueMap ) );
1114         }
1115         break;
1116       }
1117       case Toolkit::Popup::Property::DISPLAY_STATE:
1118       {
1119         std::string valueString;
1120         if( value.Get( valueString ) )
1121         {
1122           Toolkit::Popup::DisplayState displayState( Toolkit::Popup::HIDDEN );
1123           if( Scripting::GetEnumeration< Toolkit::Popup::DisplayState >( valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState ) )
1124           {
1125             popupImpl.SetDisplayState( displayState );
1126           }
1127         }
1128         break;
1129       }
1130       case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1131       {
1132         bool valueBool;
1133         if( value.Get( valueBool ) )
1134         {
1135           popupImpl.SetTouchTransparent( valueBool );
1136         }
1137         break;
1138       }
1139       case Toolkit::Popup::Property::TAIL_VISIBILITY:
1140       {
1141         bool valueBool;
1142         if( value.Get( valueBool ) )
1143         {
1144           popupImpl.SetTailVisibility( valueBool );
1145         }
1146         break;
1147       }
1148       case Toolkit::Popup::Property::TAIL_POSITION:
1149       {
1150         Vector3 valueVector3;
1151         if( value.Get( valueVector3 ) )
1152         {
1153           popupImpl.SetTailPosition( valueVector3 );
1154         }
1155         break;
1156       }
1157       case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1158       {
1159         std::string valueString;
1160         if( value.Get( valueString ) )
1161         {
1162           Toolkit::Popup::ContextualMode contextualMode( Toolkit::Popup::BELOW );
1163           if( Scripting::GetEnumeration< Toolkit::Popup::ContextualMode >( valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode ) )
1164           {
1165             popupImpl.SetContextualMode( contextualMode );
1166           }
1167         }
1168         break;
1169       }
1170       case Toolkit::Popup::Property::ANIMATION_DURATION:
1171       {
1172         float valueFloat;
1173         if( value.Get( valueFloat ) )
1174         {
1175           popupImpl.SetAnimationDuration( valueFloat );
1176         }
1177         break;
1178       }
1179       case Toolkit::Popup::Property::ANIMATION_MODE:
1180       {
1181         std::string valueString;
1182         if( value.Get( valueString ) )
1183         {
1184           Toolkit::Popup::AnimationMode animationMode( Toolkit::Popup::FADE );
1185           if( Scripting::GetEnumeration< Toolkit::Popup::AnimationMode >( valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode ) )
1186           {
1187             popupImpl.SetAnimationMode( animationMode );
1188           }
1189         }
1190         break;
1191       }
1192       case Toolkit::Popup::Property::ENTRY_ANIMATION:
1193       {
1194         Property::Map valueMap;
1195         if( value.Get( valueMap ) )
1196         {
1197           popupImpl.SetEntryAnimationData( valueMap );
1198         }
1199         break;
1200       }
1201       case Toolkit::Popup::Property::EXIT_ANIMATION:
1202       {
1203         Property::Map valueMap;
1204         if( value.Get( valueMap ) )
1205         {
1206           popupImpl.SetExitAnimationData( valueMap );
1207         }
1208         break;
1209       }
1210       case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1211       {
1212         int valueInt;
1213         if( value.Get( valueInt ) )
1214         {
1215           popupImpl.SetAutoHideDelay( valueInt );
1216         }
1217         break;
1218       }
1219       case Toolkit::Popup::Property::BACKING_ENABLED:
1220       {
1221         bool valueBool;
1222         if( value.Get( valueBool ) )
1223         {
1224           popupImpl.SetBackingEnabled( valueBool );
1225         }
1226         break;
1227       }
1228       case Toolkit::Popup::Property::BACKING_COLOR:
1229       {
1230         Vector4 valueVector4;
1231         if( value.Get( valueVector4 ) )
1232         {
1233           popupImpl.SetBackingColor( valueVector4 );
1234         }
1235         break;
1236       }
1237       case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1238       {
1239         std::string valueString;
1240         if( value.Get( valueString ) )
1241         {
1242           Image image = ResourceImage::New( valueString );
1243           if( image )
1244           {
1245             Toolkit::ImageView actor = Toolkit::ImageView::New( image );
1246             popupImpl.SetPopupBackgroundImage( actor );
1247           }
1248         }
1249         break;
1250       }
1251       case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1252       {
1253         std::string valueString;
1254         if( value.Get( valueString ) )
1255         {
1256           popupImpl.SetTailUpImage( valueString );
1257         }
1258         break;
1259       }
1260       case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1261       {
1262         std::string valueString;
1263         if( value.Get( valueString ) )
1264         {
1265           popupImpl.SetTailDownImage( valueString );
1266         }
1267         break;
1268       }
1269       case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1270       {
1271         std::string valueString;
1272         if( value.Get( valueString ) )
1273         {
1274           popupImpl.SetTailLeftImage( valueString );
1275         }
1276         break;
1277       }
1278       case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1279       {
1280         std::string valueString;
1281         if( value.Get( valueString ) )
1282         {
1283           popupImpl.SetTailRightImage( valueString );
1284         }
1285         break;
1286       }
1287     }
1288   }
1289 }
1290
1291 Property::Value Popup::GetProperty( BaseObject* object, Property::Index propertyIndex )
1292 {
1293   Property::Value value;
1294
1295   Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1296
1297   if ( popup )
1298   {
1299     Popup& popupImpl( GetImpl( popup ) );
1300
1301     switch ( propertyIndex )
1302     {
1303       case Toolkit::Popup::Property::TITLE:
1304       {
1305         Property::Map map;
1306         Scripting::CreatePropertyMap( popupImpl.GetTitle(), map );
1307         value = map;
1308         break;
1309       }
1310       case Toolkit::Popup::Property::CONTENT:
1311       {
1312         Property::Map map;
1313         Scripting::CreatePropertyMap( popupImpl.GetContent(), map );
1314         value = map;
1315         break;
1316       }
1317       case Toolkit::Popup::Property::FOOTER:
1318       {
1319         Property::Map map;
1320         Scripting::CreatePropertyMap( popupImpl.GetFooter(), map );
1321         value = map;
1322         break;
1323       }
1324       case Toolkit::Popup::Property::DISPLAY_STATE:
1325       {
1326         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::DisplayState >( popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount );
1327         break;
1328       }
1329       case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1330       {
1331         value = popupImpl.IsTouchTransparent();
1332         break;
1333       }
1334       case Toolkit::Popup::Property::TAIL_VISIBILITY:
1335       {
1336         value = popupImpl.IsTailVisible();
1337         break;
1338       }
1339       case Toolkit::Popup::Property::TAIL_POSITION:
1340       {
1341         value = popupImpl.GetTailPosition();
1342         break;
1343       }
1344       case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1345       {
1346         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::ContextualMode >( popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount );
1347         break;
1348       }
1349       case Toolkit::Popup::Property::ANIMATION_DURATION:
1350       {
1351         value = popupImpl.GetAnimationDuration();
1352         break;
1353       }
1354       case Toolkit::Popup::Property::ANIMATION_MODE:
1355       {
1356         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::AnimationMode >( popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount );
1357         break;
1358       }
1359       case Toolkit::Popup::Property::ENTRY_ANIMATION:
1360       {
1361         // Note: Cannot retrieve property map from animation.
1362         Property::Map map;
1363         value = map;
1364         break;
1365       }
1366       case Toolkit::Popup::Property::EXIT_ANIMATION:
1367       {
1368         // Note: Cannot retrieve property map from animation.
1369         Property::Map map;
1370         value = map;
1371         break;
1372       }
1373       case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1374       {
1375         value = popupImpl.GetAutoHideDelay();
1376         break;
1377       }
1378       case Toolkit::Popup::Property::BACKING_ENABLED:
1379       {
1380         value = popupImpl.IsBackingEnabled();
1381         break;
1382       }
1383       case Toolkit::Popup::Property::BACKING_COLOR:
1384       {
1385         value = popupImpl.GetBackingColor();
1386         break;
1387       }
1388       case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1389       {
1390         ResourceImage image = ResourceImage::DownCast( popupImpl.GetPopupBackgroundImage() );
1391         if( image )
1392         {
1393           value = image.GetUrl();
1394         }
1395         break;
1396       }
1397       case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1398       {
1399         value = popupImpl.GetTailUpImage();
1400         break;
1401       }
1402       case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1403       {
1404         value = popupImpl.GetTailDownImage();
1405         break;
1406       }
1407       case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1408       {
1409         value = popupImpl.GetTailLeftImage();
1410         break;
1411       }
1412       case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1413       {
1414         value = popupImpl.GetTailRightImage();
1415         break;
1416       }
1417     }
1418   }
1419
1420   return value;
1421 }
1422
1423 bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1424 {
1425   Dali::BaseHandle handle( object );
1426
1427   bool connected( true );
1428   Toolkit::Popup popup = Toolkit::Popup::DownCast( handle );
1429
1430   if( 0 == strcmp( signalName.c_str(), SIGNAL_TOUCHED_OUTSIDE ) )
1431   {
1432     popup.OutsideTouchedSignal().Connect( tracker, functor );
1433   }
1434   else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWING ) )
1435   {
1436     popup.ShowingSignal().Connect( tracker, functor );
1437   }
1438   else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWN ) )
1439   {
1440     popup.ShownSignal().Connect( tracker, functor );
1441   }
1442   else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDING ) )
1443   {
1444     popup.HidingSignal().Connect( tracker, functor );
1445   }
1446   else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDDEN ) )
1447   {
1448     popup.HiddenSignal().Connect( tracker, functor );
1449   }
1450   else
1451   {
1452     // signalName does not match any signal
1453     connected = false;
1454   }
1455
1456   return connected;
1457 }
1458
1459 bool Popup::OnBackingTouched( Actor actor, const TouchData& touch )
1460 {
1461   // Allow events to pass through if touch transparency is enabled.
1462   if( mTouchTransparent )
1463   {
1464     return false;
1465   }
1466
1467   if( touch.GetPointCount() > 0 )
1468   {
1469     if( touch.GetState( 0 ) == PointState::DOWN )
1470     {
1471       // Guard against destruction during signal emission.
1472       Toolkit::Popup handle( GetOwner() );
1473
1474       mTouchedOutsideSignal.Emit();
1475     }
1476   }
1477
1478   // Block anything behind backing becoming touched.
1479   mLayer.SetTouchConsumed( true );
1480   return true;
1481 }
1482
1483 bool Popup::OnBackingWheelEvent( Actor actor, const WheelEvent& event )
1484 {
1485   // Allow events to pass through if touch transparency is enabled.
1486   if( mTouchTransparent )
1487   {
1488     return false;
1489   }
1490
1491   // Consume wheel event in dimmed backing actor.
1492   mLayer.SetTouchConsumed( true );
1493   return true;
1494 }
1495
1496 bool Popup::OnDialogTouched( Actor actor, const TouchData& touch )
1497 {
1498   // Allow events to pass through if touch transparency is enabled.
1499   if( mTouchTransparent )
1500   {
1501     return false;
1502   }
1503
1504   // Consume event (stops backing actor receiving touch events)
1505   mLayer.SetTouchConsumed( true );
1506   return true;
1507 }
1508
1509 void Popup::OnStageConnection( int depth )
1510 {
1511   Control::OnStageConnection( depth );
1512
1513   mLayoutDirty = true;
1514   RelayoutRequest();
1515 }
1516
1517 void Popup::OnChildAdd( Actor& child )
1518 {
1519   Control::OnChildAdd( child );
1520
1521   // Re-parent any children added by user to the body layer.
1522   if( mAlterAddedChild )
1523   {
1524     SetContent( child );
1525   }
1526   else
1527   {
1528     mLayoutDirty = true;
1529     RelayoutRequest();
1530   }
1531 }
1532
1533 void Popup::LayoutContext( const Vector2& size )
1534 {
1535   // Do nothing if not in a contextual mode (or there is no parent context).
1536   Actor self = Self();
1537   Actor parent = self.GetParent();
1538   if( ( mContextualMode == Toolkit::Popup::NON_CONTEXTUAL ) || !parent )
1539   {
1540     return;
1541   }
1542
1543   mPopupContainer.SetParentOrigin( ParentOrigin::CENTER );
1544   // We always anchor to the CENTER, rather than a different anchor point for each contextual
1545   // mode to allow code-reuse of the bound checking code (for maintainability).
1546   mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER );
1547
1548   // Setup with some pre-calculations for speed.
1549   Vector3 halfStageSize( Stage().GetCurrent().GetSize() / 2.0f );
1550   Vector3 parentPosition( parent.GetCurrentPosition() );
1551   Vector2 halfSize( size / 2.0f );
1552   Vector2 halfParentSize( parent.GetRelayoutSize( Dimension::WIDTH ) / 2.0f, parent.GetRelayoutSize( Dimension::HEIGHT ) / 2.0f );
1553   Vector3 newPosition( Vector3::ZERO );
1554
1555   // Perform different positioning based on the specified contextual layout mode.
1556   switch( mContextualMode )
1557   {
1558     case Toolkit::Popup::BELOW:
1559     {
1560       newPosition.x += halfSize.x - halfParentSize.x;
1561       newPosition.y += halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1562       break;
1563     }
1564     case Toolkit::Popup::ABOVE:
1565     {
1566       newPosition.x += halfSize.x - halfParentSize.x;
1567       newPosition.y -= halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1568       break;
1569     }
1570     case Toolkit::Popup::RIGHT:
1571     {
1572       newPosition.x += halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1573       newPosition.y += halfSize.y - halfParentSize.y;
1574       break;
1575     }
1576     case Toolkit::Popup::LEFT:
1577     {
1578       newPosition.x -= halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1579       newPosition.y += halfSize.y - halfParentSize.y;
1580       break;
1581     }
1582     case Toolkit::Popup::NON_CONTEXTUAL:
1583     {
1584       // Code won't reach here (caught earlier).
1585       break;
1586     }
1587   }
1588
1589   // On-screen position checking.
1590   // Check new position is not too far right. If so, correct it.
1591   // Note: Check for right rather than left first, so if popup is too wide, the left check overrides
1592   // the right check and we at least see the left portion of the popup (as this is more useful).
1593   if( newPosition.x >= ( halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x ) )
1594   {
1595     newPosition.x = halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x;
1596   }
1597   // Check new position is not too far left. If so, correct it.
1598   if( newPosition.x < halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x )
1599   {
1600     newPosition.x = halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x;// - parentSize.x;
1601   }
1602   // Check new position is not too far down. If so, correct it.
1603   if( newPosition.y >= ( halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y ) )
1604   {
1605     newPosition.y = halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1606   }
1607   // Check new position is not too far up. If so, correct it.
1608   if( newPosition.y < halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y )
1609   {
1610     newPosition.y = halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1611   }
1612
1613   // Set the final position.
1614   mPopupContainer.SetPosition( newPosition );
1615 }
1616
1617 void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container )
1618 {
1619   Vector2 useSize( size );
1620
1621   // Use the Popup layouts size, unless requested to use a fixed size.
1622   // In which case take the size set for the Popup itself.
1623   ResizePolicy::Type widthPolicy = Self().GetResizePolicy( Dimension::WIDTH );
1624   ResizePolicy::Type heightPolicy = Self().GetResizePolicy( Dimension::HEIGHT );
1625
1626   // Width calculations:
1627   if( widthPolicy == ResizePolicy::USE_NATURAL_SIZE || widthPolicy == ResizePolicy::FIT_TO_CHILDREN )
1628   {
1629     // If we using a child-based policy, take the size from the popup layout.
1630     mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
1631     useSize.width = mPopupLayout.GetRelayoutSize( Dimension::WIDTH );
1632
1633     mPopupLayout.SetFitWidth( 0u );
1634   }
1635   else
1636   {
1637     // If we using a parent-based policy, take the size from the popup object itself (self).
1638     mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
1639
1640     mPopupLayout.SetFixedWidth( 0u, useSize.width );
1641   }
1642
1643   // Height calculations:
1644   // Title: Let the title be as high as it needs to be.
1645   mPopupLayout.SetFitHeight( 0u );
1646
1647   // Footer: Convert the footer's resize policy to a TableView row policy.
1648   if( mFooter )
1649   {
1650     ResizePolicy::Type footerHeightPolicy = mFooter.GetResizePolicy( Dimension::HEIGHT );
1651     if( ( footerHeightPolicy == ResizePolicy::USE_NATURAL_SIZE ) ||
1652         ( footerHeightPolicy == ResizePolicy::FIT_TO_CHILDREN ) )
1653     {
1654       mPopupLayout.SetFitHeight( 2u );
1655     }
1656     else if( footerHeightPolicy == ResizePolicy::FIXED )
1657     {
1658       mPopupLayout.SetFixedHeight( 2u, mFooter.GetRelayoutSize( Dimension::HEIGHT) );
1659     }
1660     else
1661     {
1662       mPopupLayout.SetRelativeHeight( 2u, 1.0f );
1663     }
1664   }
1665   else
1666   {
1667     mPopupLayout.SetFixedHeight( 2u, 0.0f );
1668   }
1669
1670   // Popup contents: Adjust the tableview's policies based on the popup's policies.
1671   if( heightPolicy == ResizePolicy::USE_NATURAL_SIZE || heightPolicy == ResizePolicy::FIT_TO_CHILDREN )
1672   {
1673     mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
1674
1675     // Let both the contents expand as necessary.
1676     mPopupLayout.SetFitHeight( 1u );
1677     useSize.height = mPopupLayout.GetRelayoutSize( Dimension::HEIGHT );
1678   }
1679   else
1680   {
1681     mPopupLayout.SetResizePolicy( heightPolicy, Dimension::HEIGHT );
1682
1683     // Let the content expand to fill the remaining space.
1684     mPopupLayout.SetRelativeHeight( 1u, 1.0f );
1685     mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
1686   }
1687
1688   // Relayout the popup-layout to give it it's new size this frame.
1689   container.Add( mPopupLayout, useSize );
1690
1691   if( mContent )
1692   {
1693     container.Add( mContent, Vector2( mContent.GetRelayoutSize( Dimension::WIDTH ), mContent.GetRelayoutSize( Dimension::HEIGHT ) ) );
1694   }
1695
1696   // Perform contextual layout setup if required.
1697   // This is done each time in case the parent moves.
1698   // This will have no effect if no contextual mode is selected.
1699   LayoutContext( useSize );
1700 }
1701
1702 void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
1703 {
1704   // To get the popup to emulate fit-to-children, we need to actually set use-natural-size.
1705   if( ( dimension & Dimension::HEIGHT ) && ( policy == ResizePolicy::FIT_TO_CHILDREN ) )
1706   {
1707     Self().SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
1708   }
1709
1710   mLayoutDirty = true;
1711   return;
1712 }
1713
1714 Vector3 Popup::GetNaturalSize()
1715 {
1716   return mPopupLayout.GetNaturalSize();
1717 }
1718
1719 float Popup::GetHeightForWidth( float width )
1720 {
1721   return mPopupLayout.GetHeightForWidth( width );
1722 }
1723
1724 float Popup::GetWidthForHeight( float height )
1725 {
1726   return mPopupLayout.GetWidthForHeight( height );
1727 }
1728
1729 bool Popup::OnKeyEvent( const KeyEvent& event )
1730 {
1731   // Allow events to pass through if touch transparency is enabled.
1732   if( mTouchTransparent )
1733   {
1734     return false;
1735   }
1736
1737   bool consumed = false;
1738
1739   if( event.state == KeyEvent::Down )
1740   {
1741     if (event.keyCode == Dali::DALI_KEY_ESCAPE || event.keyCode == Dali::DALI_KEY_BACK)
1742     {
1743       SetDisplayState( Toolkit::Popup::HIDDEN );
1744       consumed = true;
1745     }
1746   }
1747
1748   return consumed;
1749 }
1750
1751 void Popup::AddFocusableChildrenRecursive( Actor parent, std::vector< Actor >& focusableActors )
1752 {
1753   if( parent )
1754   {
1755     Toolkit::Control control = Toolkit::Control::DownCast( parent );
1756     bool layoutControl = control && GetImplementation( control ).IsKeyboardNavigationSupported();
1757
1758     if( parent.IsKeyboardFocusable() || layoutControl )
1759     {
1760       focusableActors.push_back( parent );
1761
1762       if( !layoutControl )
1763       {
1764         for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
1765         {
1766           Actor child( parent.GetChildAt( i ) );
1767           AddFocusableChildrenRecursive( child, focusableActors );
1768         }
1769       }
1770     }
1771   }
1772 }
1773
1774 void Popup::AddFocusableChildren( Actor parent, std::vector< Actor >& focusableActors )
1775 {
1776   if( parent )
1777   {
1778     Toolkit::Control control = Toolkit::Control::DownCast( parent );
1779     if( !GetImplementation( control ).IsKeyboardNavigationSupported() )
1780     {
1781       for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
1782       {
1783         Actor child( parent.GetChildAt( i ) );
1784         AddFocusableChildrenRecursive( child, focusableActors );
1785       }
1786     }
1787     else
1788     {
1789       focusableActors.push_back( parent );
1790     }
1791   }
1792 }
1793
1794 Actor Popup::GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled )
1795 {
1796   std::string currentStr;
1797   if( currentFocusedActor )
1798   {
1799     currentStr = currentFocusedActor.GetName();
1800   }
1801
1802   Actor nextFocusableActor( currentFocusedActor );
1803   Actor currentFocusGroup;
1804   if( currentFocusedActor )
1805   {
1806     currentFocusGroup = KeyboardFocusManager::Get().GetFocusGroup( currentFocusedActor );
1807   }
1808
1809   // TODO: Needs to be optimised
1810   // The following statement checks that if we have a current focused actor, then the current focus group is not the popup content or footer.
1811   // This is to detect if the focus is currently outside the popup, and if so, move it inside.
1812   if( !currentFocusedActor ||
1813     ( currentFocusedActor && ( ( !mContent || ( currentFocusGroup != mContent ) ) && ( !mFooter || ( currentFocusGroup != mFooter ) ) ) ) )
1814   {
1815     // The current focused actor is not within popup.
1816     if( mContent && mContent.IsKeyboardFocusable() )
1817     {
1818       // If the content is focusable, move the focus to the content.
1819       nextFocusableActor = mContent;
1820     }
1821     else if( mFooter && mFooter.IsKeyboardFocusable() )
1822     {
1823       // If the footer is focusable, move the focus to the footer.
1824       nextFocusableActor = mFooter;
1825     }
1826   }
1827   else
1828   {
1829     // Rebuild the focus chain because controls or content can be added or removed dynamically
1830     std::vector< Actor > focusableActors;
1831
1832     AddFocusableChildren( mContent, focusableActors );
1833     AddFocusableChildren( mFooter, focusableActors );
1834
1835     std::vector< Actor >::iterator endIterator = focusableActors.end();
1836     std::vector< Actor >::iterator currentIterator = focusableActors.begin();
1837     for( std::vector< Actor >::iterator iterator = focusableActors.begin(); iterator != endIterator; ++iterator )
1838     {
1839       if( currentFocusedActor == *iterator )
1840       {
1841         currentIterator = iterator;
1842       }
1843     }
1844
1845     if( currentIterator != endIterator )
1846     {
1847       switch( direction )
1848       {
1849         case Toolkit::Control::KeyboardFocus::LEFT:
1850         {
1851           if( currentIterator == focusableActors.begin() )
1852           {
1853             nextFocusableActor = *( endIterator - 1 );
1854           }
1855           else
1856           {
1857             nextFocusableActor = *( currentIterator - 1 );
1858           }
1859           break;
1860         }
1861         case Toolkit::Control::KeyboardFocus::RIGHT:
1862         {
1863           if( currentIterator == endIterator - 1 )
1864           {
1865             nextFocusableActor = *( focusableActors.begin() );
1866           }
1867           else
1868           {
1869             nextFocusableActor = *( currentIterator + 1 );
1870           }
1871           break;
1872         }
1873
1874         case Toolkit::Control::KeyboardFocus::UP:
1875         {
1876           nextFocusableActor = *(  focusableActors.begin() );
1877           break;
1878         }
1879
1880         case Toolkit::Control::KeyboardFocus::DOWN:
1881         {
1882           nextFocusableActor = *( endIterator - 1 );
1883           break;
1884         }
1885       }
1886
1887       if( !nextFocusableActor )
1888       {
1889         DALI_LOG_WARNING( "Can not decide next focusable actor\n" );
1890       }
1891     }
1892   }
1893
1894   return nextFocusableActor;
1895 }
1896
1897
1898 } // namespace Internal
1899
1900 } // namespace Toolkit
1901
1902 } // namespace Dali