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