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