de3528933a1f6a2018a73fe30a6f97983e5469a2
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / popup / popup-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/popup/popup-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 #include <dali/devel-api/adaptor-framework/physical-keyboard.h>
24 #include <dali/devel-api/object/type-registry-helper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/adaptor-framework/key.h>
27 #include <dali/public-api/animation/constraints.h>
28 #include <dali/public-api/common/stage.h>
29 #include <dali/public-api/events/key-event.h>
30 #include <dali/public-api/events/touch-event.h>
31 #include <dali/public-api/images/resource-image.h>
32 #include <dali/public-api/object/type-registry.h>
33 #include <dali/devel-api/scripting/scripting.h>
34 #include <dali/public-api/size-negotiation/relayout-container.h>
35
36 // INTERNAL INCLUDES
37 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
38 #include <dali-toolkit/public-api/controls/control-impl.h>
39 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
40 #include <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
41 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
42
43 using namespace Dali;
44
45 namespace Dali
46 {
47
48 namespace Toolkit
49 {
50
51 namespace Internal
52 {
53
54 namespace
55 {
56
57 /**
58  * Creation function for main Popup type.
59  * @return Handle to the new popup object.
60  */
61 BaseHandle Create()
62 {
63   return Toolkit::Popup::New();
64 }
65
66 // Toast style defaults.
67 const int          DEFAULT_TOAST_AUTO_HIDE_DELAY = 3000;                                    ///< Toast will auto-hide after 3000ms (3 seconds)
68 const float        DEFAULT_TOAST_TRANSITION_TIME = 0.65f;                                   ///< Default time the toast Popup will take to show and hide.
69 const Vector3      DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN( 0.5f, 0.94f, 0.5f );                 ///< This is similar to BOTTOM_CENTER, but vertically higher up, as a ratio of parent height.
70 const Vector3      DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO( 0.75f, 0.75f, 0.75f );               ///< Amount of the stage's width that the toast popup will take up.
71
72 /**
73  * Creation function for named type "popupToast".
74  * @return Handle to the new toast popup object.
75  */
76 BaseHandle CreateToast()
77 {
78   Toolkit::Popup popup = Toolkit::Popup::New();
79
80   // Setup for Toast Popup type.
81   popup.SetSizeModeFactor( DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO );
82   popup.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
83   popup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
84   popup.SetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE, Toolkit::Popup::NON_CONTEXTUAL );
85   popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, DEFAULT_TOAST_TRANSITION_TIME );
86   popup.SetProperty( Toolkit::Popup::Property::TAIL_VISIBILITY, false );
87
88   // Disable the dimmed backing.
89   popup.SetProperty( Toolkit::Popup::Property::BACKING_ENABLED, false );
90
91   // The toast popup should fade in (not zoom).
92   popup.SetProperty( Toolkit::Popup::Property::ANIMATION_MODE, Toolkit::Popup::FADE );
93
94   // The toast popup should auto-hide.
95   popup.SetProperty( Toolkit::Popup::Property::AUTO_HIDE_DELAY, DEFAULT_TOAST_AUTO_HIDE_DELAY );
96
97   // Align to the bottom of the screen.
98   popup.SetParentOrigin( DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN );
99   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
100
101   // Let events pass through the toast popup.
102   popup.SetProperty( Toolkit::Popup::Property::TOUCH_TRANSPARENT, true );
103
104   return popup;
105 }
106
107 // Setup properties, signals and actions using the type-registry.
108 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Popup, Toolkit::Control, Create )
109
110 // Main content related properties.
111 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "title",                             MAP,              TITLE                  )
112 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "content",                           MAP,              CONTENT                )
113 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "footer",                            MAP,              FOOTER                 )
114 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "displayState",                      STRING,           DISPLAY_STATE          )
115 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "touchTransparent",                  BOOLEAN,          TOUCH_TRANSPARENT      )
116
117 // Contextual related properties.
118 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailVisibility",                    BOOLEAN,          TAIL_VISIBILITY        )
119 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailPosition",                      VECTOR3,          TAIL_POSITION          )
120 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "contextualMode",                    STRING,           CONTEXTUAL_MODE        )
121
122 // Animation related properties.
123 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "animationDuration",                 FLOAT,            ANIMATION_DURATION     )
124 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "animationMode",                     STRING,           ANIMATION_MODE         )
125 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "entryAnimation",                    MAP,              ENTRY_ANIMATION        )
126 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "exitAnimation",                     MAP,              EXIT_ANIMATION         )
127 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "autoHideDelay",                     INTEGER,          AUTO_HIDE_DELAY        )
128
129 // Style related properties.
130 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "backingEnabled",                    BOOLEAN,          BACKING_ENABLED        )
131 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "backingColor",                      VECTOR4,          BACKING_COLOR          )
132 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "popupBackgroundImage",              STRING,           POPUP_BACKGROUND_IMAGE )
133 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailUpImage",                       STRING,           TAIL_UP_IMAGE          )
134 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailDownImage",                     STRING,           TAIL_DOWN_IMAGE        )
135 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailLeftImage",                     STRING,           TAIL_LEFT_IMAGE        )
136 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailRightImage",                    STRING,           TAIL_RIGHT_IMAGE       )
137
138 // Signals.
139 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "touchedOutside",                                      SIGNAL_TOUCHED_OUTSIDE )
140 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "showing",                                             SIGNAL_SHOWING         )
141 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "shown",                                               SIGNAL_SHOWN           )
142 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "hiding",                                              SIGNAL_HIDING          )
143 DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "hidden",                                              SIGNAL_HIDDEN          )
144
145 DALI_TYPE_REGISTRATION_END()
146
147 // Named type registration.
148
149 // Toast Popup: Non-modal popup that displays information at the bottom of the screen.
150 TypeRegistration typeRegistrationToast( "PopupToast",  typeid( Toolkit::Popup ), CreateToast );
151
152 // Enumeration to / from string conversion tables
153
154 const Scripting::StringEnum DisplayStateTable[] = {
155   { "SHOWING", Toolkit::Popup::SHOWING },
156   { "SHOWN",   Toolkit::Popup::SHOWN   },
157   { "HIDING",  Toolkit::Popup::HIDING  },
158   { "HIDDEN",  Toolkit::Popup::HIDDEN  },
159 }; const unsigned int DisplayStateTableCount = sizeof( DisplayStateTable ) / sizeof( DisplayStateTable[0] );
160
161 const Scripting::StringEnum AnimationModeTable[] = {
162   { "NONE",    Toolkit::Popup::NONE    },
163   { "ZOOM",    Toolkit::Popup::ZOOM    },
164   { "FADE",    Toolkit::Popup::FADE    },
165   { "CUSTOM",  Toolkit::Popup::CUSTOM  },
166 }; const unsigned int AnimationModeTableCount = sizeof( AnimationModeTable ) / sizeof( AnimationModeTable[0] );
167
168 const Scripting::StringEnum ContextualModeTable[] = {
169   { "NON_CONTEXTUAL", Toolkit::Popup::NON_CONTEXTUAL },
170   { "ABOVE",          Toolkit::Popup::ABOVE          },
171   { "RIGHT",          Toolkit::Popup::RIGHT          },
172   { "BELOW",          Toolkit::Popup::BELOW          },
173   { "LEFT",           Toolkit::Popup::LEFT           },
174 }; const unsigned int ContextualModeTableCount = sizeof( ContextualModeTable ) / sizeof( ContextualModeTable[0] );
175
176 // Popup defaults.
177 const Vector3 DEFAULT_POPUP_PARENT_RELATIVE_SIZE( 0.75f, 1.0f, 1.0f );                      ///< Default size percentage of parent.
178 const float   DEFAULT_POPUP_ANIMATION_DURATION =  0.6f;                                     ///< Duration of hide/show animations.
179 const float   POPUP_OUT_MARGIN_WIDTH =            16.f;                                     ///< Space between the screen edge and the popup edge in the horizontal dimension.
180 const float   POPUP_OUT_MARGIN_HEIGHT =           36.f;                                     ///< Space between the screen edge and the popup edge in the vertical dimension.
181 const Vector3 DEFAULT_TAIL_POSITION( 0.5f, 1.0f, 0.0f );                                    ///< Position the tail will be displayed when enabled without setting the position.
182
183 // Contextual defaults.
184 const Vector2 DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN( 10.0f, 10.0f );                          ///< How close the Popup will be to it's contextual parent.
185 const Vector2 DEFAULT_CONTEXTUAL_STAGE_BORDER( 15.0f, 15.0f );                              ///< How close the Popup can be to the stage edges.
186
187 // Popup style defaults.
188 const char*   DEFAULT_BACKGROUND_IMAGE_PATH =     DALI_IMAGE_DIR "00_popup_bg.9.png";       ///< Background image.
189 const char*   DEFAULT_TAIL_UP_IMAGE_PATH =        DALI_IMAGE_DIR "popup_tail_up.png";       ///< Tail up image.
190 const char*   DEFAULT_TAIL_DOWN_IMAGE_PATH =      DALI_IMAGE_DIR "popup_tail_down.png";     ///< Tail down image.
191 const char*   DEFAULT_TAIL_LEFT_IMAGE_PATH =      DALI_IMAGE_DIR "popup_tail_left.png";     ///< Tail left image.
192 const char*   DEFAULT_TAIL_RIGHT_IMAGE_PATH =     DALI_IMAGE_DIR "popup_tail_right.png";    ///< Tail right image.
193
194 const Vector4 DEFAULT_BACKING_COLOR( 0.0f, 0.0f, 0.0f, 0.5f );                              ///< Color of the dimmed backing.
195 const Vector3 BACKGROUND_OUTER_BORDER( 40.0f, 30.0f, 0.0f );                                ///< External border.
196 const Rect<float>  DEFAULT_TITLE_PADDING( 20.0f, 20.0f, 20.0f, 20.0f );                     ///< Title padding used on popups with content and/or controls (from Tizen GUI UX).
197 const Rect<float>  DEFAULT_TITLE_ONLY_PADDING( 8.0f, 8.0f, 8.0f, 8.0f );                    ///< Title padding used on popups with a title only (like toast popups).
198 const Vector3 FOOTER_SIZE( 620.0f, 96.0f,0.0f );                                            ///< Default size of the bottom control area.
199 const float   DEFAULT_RELATIVE_PARENT_WIDTH =     0.75f;                                    ///< If width is not fixed, relative size to parent is used by default.
200
201 } // Unnamed namespace
202
203 /*
204  * Implementation.
205  */
206
207 Dali::Toolkit::Popup Popup::New()
208 {
209   // Create the implementation
210   PopupPtr popup( new Popup() );
211
212   // Pass ownership to CustomActor via derived handle.
213   Dali::Toolkit::Popup handle( *popup );
214
215   // Second-phase initialisation of the implementation.
216   // This can only be done after the CustomActor connection has been made.
217   popup->Initialize();
218
219   return handle;
220 }
221
222 Popup::Popup()
223 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
224   mTouchedOutsideSignal(),
225   mShowingSignal(),
226   mShownSignal(),
227   mHidingSignal(),
228   mHiddenSignal(),
229   mLayer(),
230   mPopupLayout(),
231   mBacking(),
232   mPreviousFocusedActor(),
233   mTailImage(),
234   mPopupContainer(),
235   mAnimation(),
236   mAlterAddedChild( false ),
237   mLayoutDirty( true ),
238   mAutoHideTimer(),
239   mTouchTransparent( false ),
240   mTitle(),
241   mContent(),
242   mFooter(),
243   mDisplayState( Toolkit::Popup::HIDDEN ), // Hidden until shown with SetDisplayState()
244   mTailVisible( false ),
245   mTailPosition( DEFAULT_TAIL_POSITION ),
246   mContextualMode( Toolkit::Popup::NON_CONTEXTUAL ),
247   mAnimationDuration( DEFAULT_POPUP_ANIMATION_DURATION ),
248   mAnimationMode( Toolkit::Popup::FADE ),
249   mEntryAnimationData(),
250   mExitAnimationData(),
251   mAutoHideDelay( 0 ),
252   mBackingEnabled( true ),
253   mBackingColor( DEFAULT_BACKING_COLOR ),
254   mPopupBackgroundImage(),
255   mBackgroundOuterBorder(),
256   mMargin(),
257   mTailUpImage( DEFAULT_TAIL_UP_IMAGE_PATH ),
258   mTailDownImage( DEFAULT_TAIL_DOWN_IMAGE_PATH ),
259   mTailLeftImage( DEFAULT_TAIL_LEFT_IMAGE_PATH ),
260   mTailRightImage( DEFAULT_TAIL_RIGHT_IMAGE_PATH )
261 {
262   SetKeyboardNavigationSupport( true );
263 }
264
265 void Popup::OnInitialize()
266 {
267   Actor self = Self();
268   self.SetName( "popup" );
269
270   // Apply some default resizing rules.
271   self.SetParentOrigin( ParentOrigin::CENTER );
272   self.SetAnchorPoint( AnchorPoint::CENTER );
273
274   self.SetSizeModeFactor( DEFAULT_POPUP_PARENT_RELATIVE_SIZE );
275   self.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
276   self.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
277
278   // Create a new layer so all Popup components can appear above all other actors.
279   mLayer = Layer::New();
280   mLayer.SetName( "popupLayer" );
281
282   mLayer.SetParentOrigin( ParentOrigin::CENTER );
283   mLayer.SetAnchorPoint( AnchorPoint::CENTER );
284   mLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
285
286   // Important to set as invisible as otherwise, if the popup is parented,
287   // but not shown yet it will appear statically on the screen.
288   mLayer.SetVisible( false );
289
290   // Add the layer to the hierarchy.
291   self.Add( mLayer );
292
293   // Add Backing (Dimmed effect).
294   mBacking = CreateBacking();
295   mLayer.Add( mBacking );
296
297   mPopupContainer = Actor::New();
298   mPopupContainer.SetName( "popupContainer" );
299   mPopupContainer.SetParentOrigin( ParentOrigin::CENTER );
300   mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER );
301   mPopupContainer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
302   mLayer.Add( mPopupContainer );
303
304   // Create the Popup layout to contain all main content.
305   mPopupLayout = Toolkit::TableView::New( 3, 1 );
306
307   // Adds the default background image.
308   SetPopupBackgroundImage( 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.TouchedSignal().Connect( this, &Popup::OnDialogTouched );
322
323   mPopupContainer.Add( mPopupLayout );
324
325   // Any content after this point which is added to Self() will be re-parented to mContent.
326   mAlterAddedChild = true;
327
328   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.TouchedSignal().Connect( this, &Popup::OnDialogTouched );
582
583   // Set the popup border to be slightly larger than the layout contents.
584   mPopupBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
585   mPopupBackgroundImage.SetSizeModeFactor( BACKGROUND_OUTER_BORDER );
586
587   const bool prevAlter = mAlterAddedChild;
588   mAlterAddedChild = false;
589   mPopupContainer.Add( mPopupBackgroundImage );
590   mAlterAddedChild = prevAlter;
591
592   mLayoutDirty = true;
593 }
594
595 Actor Popup::GetPopupBackgroundImage() const
596 {
597   return mPopupBackgroundImage;
598 }
599
600 void Popup::SetTitle( Actor titleActor )
601 {
602   // Replaces the current title actor.
603   if( !mPopupLayout )
604   {
605     return;
606   }
607
608   if( mTitle )
609   {
610     mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 0, 0) );
611   }
612   mTitle = titleActor;
613
614   if( mTitle )
615   {
616     // Set up padding to give sensible default behaviour
617     // (an application developer can later override this if they wish).
618     mTitle.SetPadding( DEFAULT_TITLE_PADDING );
619
620     mPopupLayout.AddChild( mTitle, Toolkit::TableView::CellPosition( 0, 0 ) );
621   }
622
623   mLayoutDirty = true;
624   RelayoutRequest();
625 }
626
627 Actor Popup::GetTitle() const
628 {
629   return mTitle;
630 }
631
632 void Popup::SetContent( Actor content )
633 {
634   // Remove previous content actor.
635   if( mPopupLayout )
636   {
637     mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 1, 0 ) );
638   }
639    // Keep a handle to the new content.
640   mContent = content;
641
642   if( mContent )
643   {
644     mContent.SetName( "popupContent" );
645
646     mPopupLayout.AddChild( mContent, Toolkit::TableView::CellPosition( 1, 0 ) );
647   }
648
649   mLayoutDirty = true;
650   RelayoutRequest();
651 }
652
653 Actor Popup::GetContent() const
654 {
655   return mContent;
656 }
657
658 void Popup::SetFooter( Actor footer )
659 {
660   // Remove previous content actor.
661   if( mPopupLayout )
662   {
663     mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 2, 0 ) );
664   }
665
666   // Keep a handle to the new content.
667   mFooter = footer;
668
669   if( mFooter )
670   {
671     mFooter.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
672
673     // The control container has a fixed height.
674     mPopupLayout.SetFitHeight( 2u );
675     mPopupLayout.AddChild( footer, Toolkit::TableView::CellPosition( 2, 0 ) );
676   }
677
678   mLayoutDirty = true;
679   RelayoutRequest();
680 }
681
682 Actor Popup::GetFooter() const
683 {
684   return mFooter;
685 }
686
687 void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState )
688 {
689   // Convert the 4-way state to a bool, true for show, false for hide.
690   bool display = ( displayState == Toolkit::Popup::SHOWING ) || ( displayState == Toolkit::Popup::SHOWN );
691
692   // Ignore if we are already at the target display state.
693   if( display == ( ( mDisplayState == Toolkit::Popup::SHOWING ) || ( mDisplayState == Toolkit::Popup::SHOWN ) ) )
694   {
695     return;
696   }
697
698   // Convert the bool state to the actual display state to use.
699   mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
700
701   if ( display )
702   {
703     // Update the state to indicate the current intent.
704     mDisplayState = Toolkit::Popup::SHOWING;
705
706     // We are displaying so bring the popup layer to the front, and set it visible so it is rendered.
707     mLayer.RaiseToTop();
708     mLayer.SetVisible( true );
709
710     // Set up the layout if this is the first display or the layout has become dirty.
711     if( mLayoutDirty )
712     {
713       // Bake-in any style and layout options to create the Popup layout.
714       LayoutPopup();
715     }
716
717     // Allow the popup to catch events.
718     mPopupLayout.SetSensitive( true );
719
720     // Handle the keyboard focus when popup is shown.
721     Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
722     if( keyboardFocusManager )
723     {
724       mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor();
725
726       if( Self().IsKeyboardFocusable() )
727       {
728         // Setup the actgor to start focus from.
729         Actor focusActor;
730         if( mContent && mContent.IsKeyboardFocusable() )
731         {
732           // If the content is focusable, move the focus to the content.
733           focusActor = mContent;
734         }
735         else if( mFooter && mFooter.IsKeyboardFocusable() )
736         {
737           // If the footer is focusable, move the focus to the footer.
738           focusActor = mFooter;
739         }
740         else
741         {
742           DALI_LOG_WARNING( "There is no focusable in popup\n" );
743         }
744
745         if( focusActor )
746         {
747           SetKeyInputFocus();
748           keyboardFocusManager.SetCurrentFocusActor( focusActor );
749         }
750       }
751     }
752   }
753   else // Not visible.
754   {
755     mDisplayState = Toolkit::Popup::HIDING;
756     ClearKeyInputFocus();
757
758     // Restore the keyboard focus when popup is hidden.
759     if( mPreviousFocusedActor && mPreviousFocusedActor.IsKeyboardFocusable() )
760     {
761       Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
762       if( keyboardFocusManager )
763       {
764         keyboardFocusManager.SetCurrentFocusActor( mPreviousFocusedActor );
765       }
766     }
767   }
768
769   // Perform animation.
770   StartTransitionAnimation( display );
771 }
772
773 Toolkit::Popup::DisplayState Popup::GetDisplayState() const
774 {
775   return mDisplayState;
776 }
777
778 void Popup::LayoutPopup()
779 {
780   mLayoutDirty = false;
781
782   /* When animating in, we want to respect the origin applied to Self().
783    * For example, if zooming, not only will the final result be anchored to the
784    * selected point, but the zoom will originate from this point also.
785    *
786    * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT :
787    *
788    *       --------                --------
789    *       |X|                     |XXX|
790    *       |``        Animates     |XXX|
791    *       |             to:       |XXX|
792    *       |                       |````
793    *       |                       |
794    */
795   mPopupContainer.SetParentOrigin( Self().GetCurrentParentOrigin() );
796   mPopupContainer.SetAnchorPoint( Self().GetCurrentAnchorPoint() );
797
798   // If there is only a title, use less padding.
799   if( mTitle )
800   {
801     if( !mContent && !mFooter )
802     {
803       mTitle.SetPadding( DEFAULT_TITLE_ONLY_PADDING );
804     }
805     else
806     {
807       mTitle.SetPadding( DEFAULT_TITLE_PADDING );
808     }
809   }
810
811   // Allow derived classes to perform any layout they may need to do.
812   OnLayoutSetup();
813
814   // Update background visibility.
815   mPopupContainer.SetVisible( !( !mFooter && mPopupLayout.GetChildCount() == 0 ) );
816
817   // Create / destroy / position the tail as needed.
818   LayoutTail();
819
820   // Setup any layout and initialisation required for the selected animation.
821   LayoutAnimation();
822
823   RelayoutRequest();
824 }
825
826 void Popup::LayoutTail()
827 {
828   // Removes the tail actor.
829   if( mTailImage && mTailImage.GetParent() )
830   {
831     mTailImage.GetParent().Remove( mTailImage );
832     mTailImage.Reset();
833   }
834
835   if( !mTailVisible )
836   {
837     return;
838   }
839
840   const Vector3& position = GetTailPosition();
841   std::string image;
842
843   // depending on position of tail around ParentOrigin, a different tail image is used...
844   if( position.y < Math::MACHINE_EPSILON_1 )
845   {
846     image = mTailUpImage;
847   }
848   else if( position.y > 1.0f - Math::MACHINE_EPSILON_1 )
849   {
850     image = mTailDownImage;
851   }
852   else if( position.x < Math::MACHINE_EPSILON_1 )
853   {
854     image = mTailLeftImage;
855   }
856   else if( position.x > 1.0f - Math::MACHINE_EPSILON_1 )
857   {
858     image = mTailRightImage;
859   }
860
861   if( !image.empty() )
862   {
863     // Adds the tail actor.
864     Image tail = ResourceImage::New( image );
865     mTailImage = Toolkit::ImageView::New( tail );
866     mTailImage.SetName( "tailImage" );
867     const Vector3 anchorPoint = AnchorPoint::BOTTOM_RIGHT - position;
868     mTailImage.SetParentOrigin( position );
869     mTailImage.SetAnchorPoint( anchorPoint );
870
871     mPopupContainer.Add( mTailImage );
872   }
873 }
874
875 void Popup::SetContextualMode( Toolkit::Popup::ContextualMode mode )
876 {
877   mContextualMode = mode;
878   mLayoutDirty = true;
879 }
880
881 Toolkit::Popup::ContextualMode Popup::GetContextualMode() const
882 {
883   return mContextualMode;
884 }
885
886 Toolkit::Control Popup::CreateBacking()
887 {
888   Toolkit::Control backing = Control::New();
889   backing.SetBackgroundColor( Vector4( mBackingColor.r, mBackingColor.g, mBackingColor.b, 1.0f ) );
890   backing.SetName( "popupBacking" );
891
892   // Must always be positioned top-left of stage, regardless of parent.
893   backing.SetInheritPosition(false);
894   backing.SetAnchorPoint( AnchorPoint::TOP_LEFT );
895
896   // Always the full size of the stage.
897   backing.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
898   backing.SetSize( Stage::GetCurrent().GetSize() );
899
900   // Catch events.
901   backing.SetSensitive( true );
902
903   // Default to being transparent.
904   backing.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f );
905   backing.TouchedSignal().Connect( this, &Popup::OnBackingTouched );
906   backing.WheelEventSignal().Connect( this, &Popup::OnBackingWheelEvent );
907   return backing;
908 }
909
910 Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
911 {
912   return mTouchedOutsideSignal;
913 }
914
915 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
916 {
917   return mShowingSignal;
918 }
919
920 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
921 {
922   return mShownSignal;
923 }
924
925 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
926 {
927   return mHidingSignal;
928 }
929
930 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
931 {
932   return mHiddenSignal;
933 }
934
935 void Popup::SetTailVisibility( bool visible )
936 {
937   mTailVisible = visible;
938   mLayoutDirty = true;
939 }
940
941 const bool Popup::IsTailVisible() const
942 {
943   return mTailVisible;
944 }
945
946 void Popup::SetTailPosition( Vector3 position )
947 {
948   mTailPosition = position;
949   mLayoutDirty = true;
950 }
951
952 const Vector3& Popup::GetTailPosition() const
953 {
954   return mTailPosition;
955 }
956
957 void Popup::SetAnimationDuration( float duration )
958 {
959   mAnimationDuration = duration;
960   mLayoutDirty = true;
961 }
962
963 float Popup::GetAnimationDuration() const
964 {
965   return mAnimationDuration;
966 }
967
968 void Popup::SetAnimationMode( Toolkit::Popup::AnimationMode animationMode )
969 {
970   mAnimationMode = animationMode;
971   mLayoutDirty = true;
972 }
973
974 Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const
975 {
976   return mAnimationMode;
977 }
978
979 void Popup::SetEntryAnimationData( const Property::Map& map )
980 {
981   mEntryAnimationData.Clear();
982   Scripting::NewAnimation( map, mEntryAnimationData );
983 }
984
985 void Popup::SetExitAnimationData( const Property::Map& map )
986 {
987   mExitAnimationData.Clear();
988   Scripting::NewAnimation( map, mExitAnimationData );
989 }
990
991 void Popup::SetAutoHideDelay( int delay )
992 {
993   mAutoHideDelay = delay;
994 }
995
996 int Popup::GetAutoHideDelay() const
997 {
998   return mAutoHideDelay;
999 }
1000
1001 void Popup::SetBackingEnabled( bool enabled )
1002 {
1003   mBackingEnabled = enabled;
1004   mLayoutDirty = true;
1005 }
1006
1007 const bool Popup::IsBackingEnabled() const
1008 {
1009   return mBackingEnabled;
1010 }
1011
1012 void Popup::SetBackingColor( Vector4 color )
1013 {
1014   mBackingColor = color;
1015   mBacking.SetBackgroundColor( Vector4( color.r, color.g, color.b, 1.0f ) );
1016   mLayoutDirty = true;
1017 }
1018
1019 const Vector4& Popup::GetBackingColor() const
1020 {
1021   return mBackingColor;
1022 }
1023
1024 void Popup::SetTailUpImage( std::string image )
1025 {
1026   mTailUpImage = image;
1027   mLayoutDirty = true;
1028 }
1029
1030 const std::string& Popup::GetTailUpImage() const
1031 {
1032   return mTailUpImage;
1033 }
1034
1035 void Popup::SetTailDownImage( std::string image )
1036 {
1037   mTailDownImage = image;
1038   mLayoutDirty = true;
1039 }
1040
1041 const std::string& Popup::GetTailDownImage() const
1042 {
1043   return mTailDownImage;
1044 }
1045
1046 void Popup::SetTailLeftImage( std::string image )
1047 {
1048   mTailLeftImage = image;
1049   mLayoutDirty = true;
1050 }
1051
1052 const std::string& Popup::GetTailLeftImage() const
1053 {
1054   return mTailLeftImage;
1055 }
1056
1057 void Popup::SetTailRightImage( std::string image )
1058 {
1059   mTailRightImage = image;
1060   mLayoutDirty = true;
1061 }
1062
1063 const std::string& Popup::GetTailRightImage() const
1064 {
1065   return mTailRightImage;
1066 }
1067
1068 void Popup::SetTouchTransparent( bool enabled )
1069 {
1070   mTouchTransparent = enabled;
1071 }
1072
1073 const bool Popup::IsTouchTransparent() const
1074 {
1075   return mTouchTransparent;
1076 }
1077
1078 void Popup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1079 {
1080   Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1081
1082   if ( popup )
1083   {
1084     Popup& popupImpl( GetImpl( popup ) );
1085
1086     switch ( propertyIndex )
1087     {
1088       case Toolkit::Popup::Property::TITLE:
1089       {
1090         Property::Map valueMap;
1091         if( value.Get( valueMap ) )
1092         {
1093           popupImpl.SetTitle( Scripting::NewActor( valueMap ) );
1094         }
1095         break;
1096       }
1097       case Toolkit::Popup::Property::CONTENT:
1098       {
1099         Property::Map valueMap;
1100         if( value.Get( valueMap ) )
1101         {
1102           popupImpl.SetContent( Scripting::NewActor( valueMap ) );
1103         }
1104         break;
1105       }
1106       case Toolkit::Popup::Property::FOOTER:
1107       {
1108         Property::Map valueMap;
1109         if( value.Get( valueMap ) )
1110         {
1111           popupImpl.SetFooter( Scripting::NewActor( valueMap ) );
1112         }
1113         break;
1114       }
1115       case Toolkit::Popup::Property::DISPLAY_STATE:
1116       {
1117         std::string valueString;
1118         if( value.Get( valueString ) )
1119         {
1120           Toolkit::Popup::DisplayState displayState( Toolkit::Popup::HIDDEN );
1121           if( Scripting::GetEnumeration< Toolkit::Popup::DisplayState >( valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState ) )
1122           {
1123             popupImpl.SetDisplayState( displayState );
1124           }
1125         }
1126         break;
1127       }
1128       case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1129       {
1130         bool valueBool;
1131         if( value.Get( valueBool ) )
1132         {
1133           popupImpl.SetTouchTransparent( valueBool );
1134         }
1135         break;
1136       }
1137       case Toolkit::Popup::Property::TAIL_VISIBILITY:
1138       {
1139         bool valueBool;
1140         if( value.Get( valueBool ) )
1141         {
1142           popupImpl.SetTailVisibility( valueBool );
1143         }
1144         break;
1145       }
1146       case Toolkit::Popup::Property::TAIL_POSITION:
1147       {
1148         Vector3 valueVector3;
1149         if( value.Get( valueVector3 ) )
1150         {
1151           popupImpl.SetTailPosition( valueVector3 );
1152         }
1153         break;
1154       }
1155       case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1156       {
1157         std::string valueString;
1158         if( value.Get( valueString ) )
1159         {
1160           Toolkit::Popup::ContextualMode contextualMode( Toolkit::Popup::BELOW );
1161           if( Scripting::GetEnumeration< Toolkit::Popup::ContextualMode >( valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode ) )
1162           {
1163             popupImpl.SetContextualMode( contextualMode );
1164           }
1165         }
1166         break;
1167       }
1168       case Toolkit::Popup::Property::ANIMATION_DURATION:
1169       {
1170         float valueFloat;
1171         if( value.Get( valueFloat ) )
1172         {
1173           popupImpl.SetAnimationDuration( valueFloat );
1174         }
1175         break;
1176       }
1177       case Toolkit::Popup::Property::ANIMATION_MODE:
1178       {
1179         std::string valueString;
1180         if( value.Get( valueString ) )
1181         {
1182           Toolkit::Popup::AnimationMode animationMode( Toolkit::Popup::FADE );
1183           if( Scripting::GetEnumeration< Toolkit::Popup::AnimationMode >( valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode ) )
1184           {
1185             popupImpl.SetAnimationMode( animationMode );
1186           }
1187         }
1188         break;
1189       }
1190       case Toolkit::Popup::Property::ENTRY_ANIMATION:
1191       {
1192         Property::Map valueMap;
1193         if( value.Get( valueMap ) )
1194         {
1195           popupImpl.SetEntryAnimationData( valueMap );
1196         }
1197         break;
1198       }
1199       case Toolkit::Popup::Property::EXIT_ANIMATION:
1200       {
1201         Property::Map valueMap;
1202         if( value.Get( valueMap ) )
1203         {
1204           popupImpl.SetExitAnimationData( valueMap );
1205         }
1206         break;
1207       }
1208       case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1209       {
1210         int valueInt;
1211         if( value.Get( valueInt ) )
1212         {
1213           popupImpl.SetAutoHideDelay( valueInt );
1214         }
1215         break;
1216       }
1217       case Toolkit::Popup::Property::BACKING_ENABLED:
1218       {
1219         bool valueBool;
1220         if( value.Get( valueBool ) )
1221         {
1222           popupImpl.SetBackingEnabled( valueBool );
1223         }
1224         break;
1225       }
1226       case Toolkit::Popup::Property::BACKING_COLOR:
1227       {
1228         Vector4 valueVector4;
1229         if( value.Get( valueVector4 ) )
1230         {
1231           popupImpl.SetBackingColor( valueVector4 );
1232         }
1233         break;
1234       }
1235       case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1236       {
1237         std::string valueString;
1238         if( value.Get( valueString ) )
1239         {
1240           Image image = ResourceImage::New( valueString );
1241           if( image )
1242           {
1243             Toolkit::ImageView actor = Toolkit::ImageView::New( image );
1244             popupImpl.SetPopupBackgroundImage( actor );
1245           }
1246         }
1247         break;
1248       }
1249       case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1250       {
1251         std::string valueString;
1252         if( value.Get( valueString ) )
1253         {
1254           popupImpl.SetTailUpImage( valueString );
1255         }
1256         break;
1257       }
1258       case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1259       {
1260         std::string valueString;
1261         if( value.Get( valueString ) )
1262         {
1263           popupImpl.SetTailDownImage( valueString );
1264         }
1265         break;
1266       }
1267       case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1268       {
1269         std::string valueString;
1270         if( value.Get( valueString ) )
1271         {
1272           popupImpl.SetTailLeftImage( valueString );
1273         }
1274         break;
1275       }
1276       case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1277       {
1278         std::string valueString;
1279         if( value.Get( valueString ) )
1280         {
1281           popupImpl.SetTailRightImage( valueString );
1282         }
1283         break;
1284       }
1285     }
1286   }
1287 }
1288
1289 Property::Value Popup::GetProperty( BaseObject* object, Property::Index propertyIndex )
1290 {
1291   Property::Value value;
1292
1293   Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1294
1295   if ( popup )
1296   {
1297     Popup& popupImpl( GetImpl( popup ) );
1298
1299     switch ( propertyIndex )
1300     {
1301       case Toolkit::Popup::Property::TITLE:
1302       {
1303         Property::Map map;
1304         Scripting::CreatePropertyMap( popupImpl.GetTitle(), map );
1305         value = map;
1306         break;
1307       }
1308       case Toolkit::Popup::Property::CONTENT:
1309       {
1310         Property::Map map;
1311         Scripting::CreatePropertyMap( popupImpl.GetContent(), map );
1312         value = map;
1313         break;
1314       }
1315       case Toolkit::Popup::Property::FOOTER:
1316       {
1317         Property::Map map;
1318         Scripting::CreatePropertyMap( popupImpl.GetFooter(), map );
1319         value = map;
1320         break;
1321       }
1322       case Toolkit::Popup::Property::DISPLAY_STATE:
1323       {
1324         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::DisplayState >( popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount );
1325         break;
1326       }
1327       case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1328       {
1329         value = popupImpl.IsTouchTransparent();
1330         break;
1331       }
1332       case Toolkit::Popup::Property::TAIL_VISIBILITY:
1333       {
1334         value = popupImpl.IsTailVisible();
1335         break;
1336       }
1337       case Toolkit::Popup::Property::TAIL_POSITION:
1338       {
1339         value = popupImpl.GetTailPosition();
1340         break;
1341       }
1342       case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1343       {
1344         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::ContextualMode >( popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount );
1345         break;
1346       }
1347       case Toolkit::Popup::Property::ANIMATION_DURATION:
1348       {
1349         value = popupImpl.GetAnimationDuration();
1350         break;
1351       }
1352       case Toolkit::Popup::Property::ANIMATION_MODE:
1353       {
1354         value = Scripting::GetLinearEnumerationName< Toolkit::Popup::AnimationMode >( popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount );
1355         break;
1356       }
1357       case Toolkit::Popup::Property::ENTRY_ANIMATION:
1358       {
1359         // Note: Cannot retrieve property map from animation.
1360         Property::Map map;
1361         value = map;
1362         break;
1363       }
1364       case Toolkit::Popup::Property::EXIT_ANIMATION:
1365       {
1366         // Note: Cannot retrieve property map from animation.
1367         Property::Map map;
1368         value = map;
1369         break;
1370       }
1371       case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1372       {
1373         value = popupImpl.GetAutoHideDelay();
1374         break;
1375       }
1376       case Toolkit::Popup::Property::BACKING_ENABLED:
1377       {
1378         value = popupImpl.IsBackingEnabled();
1379         break;
1380       }
1381       case Toolkit::Popup::Property::BACKING_COLOR:
1382       {
1383         value = popupImpl.GetBackingColor();
1384         break;
1385       }
1386       case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1387       {
1388         ResourceImage image = ResourceImage::DownCast( popupImpl.GetPopupBackgroundImage() );
1389         if( image )
1390         {
1391           value = image.GetUrl();
1392         }
1393         break;
1394       }
1395       case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1396       {
1397         value = popupImpl.GetTailUpImage();
1398         break;
1399       }
1400       case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1401       {
1402         value = popupImpl.GetTailDownImage();
1403         break;
1404       }
1405       case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1406       {
1407         value = popupImpl.GetTailLeftImage();
1408         break;
1409       }
1410       case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1411       {
1412         value = popupImpl.GetTailRightImage();
1413         break;
1414       }
1415     }
1416   }
1417
1418   return value;
1419 }
1420
1421 bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1422 {
1423   Dali::BaseHandle handle( object );
1424
1425   bool connected( true );
1426   Toolkit::Popup popup = Toolkit::Popup::DownCast( handle );
1427
1428   if( 0 == strcmp( signalName.c_str(), SIGNAL_TOUCHED_OUTSIDE ) )
1429   {
1430     popup.OutsideTouchedSignal().Connect( tracker, functor );
1431   }
1432   else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWING ) )
1433   {
1434     popup.ShowingSignal().Connect( tracker, functor );
1435   }
1436   else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWN ) )
1437   {
1438     popup.ShownSignal().Connect( tracker, functor );
1439   }
1440   else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDING ) )
1441   {
1442     popup.HidingSignal().Connect( tracker, functor );
1443   }
1444   else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDDEN ) )
1445   {
1446     popup.HiddenSignal().Connect( tracker, functor );
1447   }
1448   else
1449   {
1450     // signalName does not match any signal
1451     connected = false;
1452   }
1453
1454   return connected;
1455 }
1456
1457 bool Popup::OnBackingTouched( Actor actor, const TouchEvent& event )
1458 {
1459   // Allow events to pass through if touch transparency is enabled.
1460   if( mTouchTransparent )
1461   {
1462     return false;
1463   }
1464
1465   if( event.GetPointCount() > 0 )
1466   {
1467     const TouchPoint& point = event.GetPoint( 0 );
1468
1469     if( point.state == TouchPoint::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 TouchEvent& event)
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