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