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