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