2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/controls/popup/popup-impl.h>
22 #include <cstring> // for strcmp
23 #include <dali/devel-api/adaptor-framework/physical-keyboard.h>
24 #include <dali/public-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-data.h>
31 #include <dali/public-api/object/type-registry.h>
32 #include <dali/devel-api/scripting/scripting.h>
33 #include <dali/devel-api/actors/actor-devel.h>
34 #include <dali/public-api/size-negotiation/relayout-container.h>
37 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
38 #include <dali-toolkit/public-api/controls/control-impl.h>
39 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
40 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
41 #include <dali-toolkit/public-api/visuals/visual-properties.h>
42 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
43 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
60 * Creation function for main Popup type.
61 * @return Handle to the new popup object.
65 return Toolkit::Popup::New();
68 // Toast style defaults.
69 const int DEFAULT_TOAST_AUTO_HIDE_DELAY = 3000; ///< Toast will auto-hide after 3000ms (3 seconds)
70 const float DEFAULT_TOAST_TRANSITION_TIME = 0.65f; ///< Default time the toast Popup will take to show and hide.
71 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.
72 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 * Creation function for named type "popupToast".
76 * @return Handle to the new toast popup object.
78 BaseHandle CreateToast()
80 Toolkit::Popup popup = Toolkit::Popup::New();
82 // Setup for Toast Popup type.
83 popup.SetSizeModeFactor( DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO );
84 popup.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
85 popup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
86 popup.SetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE, Toolkit::Popup::NON_CONTEXTUAL );
87 popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, DEFAULT_TOAST_TRANSITION_TIME );
88 popup.SetProperty( Toolkit::Popup::Property::TAIL_VISIBILITY, false );
90 // Disable the dimmed backing.
91 popup.SetProperty( Toolkit::Popup::Property::BACKING_ENABLED, false );
93 // The toast popup should fade in (not zoom).
94 popup.SetProperty( Toolkit::Popup::Property::ANIMATION_MODE, Toolkit::Popup::FADE );
96 // The toast popup should auto-hide.
97 popup.SetProperty( Toolkit::Popup::Property::AUTO_HIDE_DELAY, DEFAULT_TOAST_AUTO_HIDE_DELAY );
99 // Align to the bottom of the screen.
100 popup.SetParentOrigin( DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN );
101 popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
103 // Let events pass through the toast popup.
104 popup.SetProperty( Toolkit::Popup::Property::TOUCH_TRANSPARENT, true );
109 // Setup properties, signals and actions using the type-registry.
110 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Popup, Toolkit::Control, Create )
112 // Main content related properties.
113 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "title", MAP, TITLE )
114 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "content", MAP, CONTENT )
115 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "footer", MAP, FOOTER )
116 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "displayState", STRING, DISPLAY_STATE )
117 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "touchTransparent", BOOLEAN, TOUCH_TRANSPARENT )
119 // Contextual related properties.
120 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailVisibility", BOOLEAN, TAIL_VISIBILITY )
121 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailPosition", VECTOR3, TAIL_POSITION )
122 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "contextualMode", STRING, CONTEXTUAL_MODE )
124 // Animation related properties.
125 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "animationDuration", FLOAT, ANIMATION_DURATION )
126 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "animationMode", STRING, ANIMATION_MODE )
127 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "entryAnimation", MAP, ENTRY_ANIMATION )
128 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "exitAnimation", MAP, EXIT_ANIMATION )
129 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "autoHideDelay", INTEGER, AUTO_HIDE_DELAY )
131 // Style related properties.
132 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "backingEnabled", BOOLEAN, BACKING_ENABLED )
133 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "backingColor", VECTOR4, BACKING_COLOR )
134 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "popupBackgroundImage", STRING, POPUP_BACKGROUND_IMAGE )
135 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "popupBackgroundBorder", RECTANGLE, POPUP_BACKGROUND_BORDER )
136 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailUpImage", STRING, TAIL_UP_IMAGE )
137 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailDownImage", STRING, TAIL_DOWN_IMAGE )
138 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailLeftImage", STRING, TAIL_LEFT_IMAGE )
139 DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailRightImage", STRING, TAIL_RIGHT_IMAGE )
142 DALI_SIGNAL_REGISTRATION( Toolkit, Popup, "touchedOutside", SIGNAL_TOUCHED_OUTSIDE )
143 DALI_SIGNAL_REGISTRATION( Toolkit, Popup, "showing", SIGNAL_SHOWING )
144 DALI_SIGNAL_REGISTRATION( Toolkit, Popup, "shown", SIGNAL_SHOWN )
145 DALI_SIGNAL_REGISTRATION( Toolkit, Popup, "hiding", SIGNAL_HIDING )
146 DALI_SIGNAL_REGISTRATION( Toolkit, Popup, "hidden", SIGNAL_HIDDEN )
148 DALI_TYPE_REGISTRATION_END()
150 // Named type registration.
152 // Toast Popup: Non-modal popup that displays information at the bottom of the screen.
153 TypeRegistration typeRegistrationToast( "PopupToast", typeid( Toolkit::Popup ), CreateToast );
155 // Enumeration to / from string conversion tables
157 const Scripting::StringEnum DisplayStateTable[] = {
158 { "SHOWING", Toolkit::Popup::SHOWING },
159 { "SHOWN", Toolkit::Popup::SHOWN },
160 { "HIDING", Toolkit::Popup::HIDING },
161 { "HIDDEN", Toolkit::Popup::HIDDEN },
162 }; const unsigned int DisplayStateTableCount = sizeof( DisplayStateTable ) / sizeof( DisplayStateTable[0] );
164 const Scripting::StringEnum AnimationModeTable[] = {
165 { "NONE", Toolkit::Popup::NONE },
166 { "ZOOM", Toolkit::Popup::ZOOM },
167 { "FADE", Toolkit::Popup::FADE },
168 { "CUSTOM", Toolkit::Popup::CUSTOM },
169 }; const unsigned int AnimationModeTableCount = sizeof( AnimationModeTable ) / sizeof( AnimationModeTable[0] );
171 const Scripting::StringEnum ContextualModeTable[] = {
172 { "NON_CONTEXTUAL", Toolkit::Popup::NON_CONTEXTUAL },
173 { "ABOVE", Toolkit::Popup::ABOVE },
174 { "RIGHT", Toolkit::Popup::RIGHT },
175 { "BELOW", Toolkit::Popup::BELOW },
176 { "LEFT", Toolkit::Popup::LEFT },
177 }; const unsigned int ContextualModeTableCount = sizeof( ContextualModeTable ) / sizeof( ContextualModeTable[0] );
180 const Vector3 DEFAULT_POPUP_PARENT_RELATIVE_SIZE( 0.75f, 1.0f, 1.0f ); ///< Default size percentage of parent.
181 const float DEFAULT_POPUP_ANIMATION_DURATION = 0.6f; ///< Duration of hide/show animations.
182 const float POPUP_OUT_MARGIN_WIDTH = 16.f; ///< Space between the screen edge and the popup edge in the horizontal dimension.
183 const float POPUP_OUT_MARGIN_HEIGHT = 36.f; ///< Space between the screen edge and the popup edge in the vertical dimension.
184 const Vector3 DEFAULT_TAIL_POSITION( 0.5f, 1.0f, 0.0f ); ///< Position the tail will be displayed when enabled without setting the position.
186 // Contextual defaults.
187 const Vector2 DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN( 10.0f, 10.0f ); ///< How close the Popup will be to it's contextual parent.
188 const Vector2 DEFAULT_CONTEXTUAL_STAGE_BORDER( 15.0f, 15.0f ); ///< How close the Popup can be to the stage edges.
190 // Popup style defaults.
191 const char* DEFAULT_BACKGROUND_IMAGE_PATH = DALI_IMAGE_DIR "00_popup_bg.9.png"; ///< Background image.
192 const char* DEFAULT_TAIL_UP_IMAGE_PATH = DALI_IMAGE_DIR "popup_tail_up.png"; ///< Tail up image.
193 const char* DEFAULT_TAIL_DOWN_IMAGE_PATH = DALI_IMAGE_DIR "popup_tail_down.png"; ///< Tail down image.
194 const char* DEFAULT_TAIL_LEFT_IMAGE_PATH = DALI_IMAGE_DIR "popup_tail_left.png"; ///< Tail left image.
195 const char* DEFAULT_TAIL_RIGHT_IMAGE_PATH = DALI_IMAGE_DIR "popup_tail_right.png"; ///< Tail right image.
197 const Vector4 DEFAULT_BACKING_COLOR( 0.0f, 0.0f, 0.0f, 0.5f ); ///< Color of the dimmed backing.
198 const Rect<int> DEFAULT_BACKGROUND_BORDER( 17, 17, 13, 13 ); ///< Default border of the background.
199 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).
200 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).
201 const Vector3 FOOTER_SIZE( 620.0f, 96.0f,0.0f ); ///< Default size of the bottom control area.
202 const float DEFAULT_RELATIVE_PARENT_WIDTH = 0.75f; ///< If width is not fixed, relative size to parent is used by default.
204 } // Unnamed namespace
210 Dali::Toolkit::Popup Popup::New()
212 // Create the implementation
213 PopupPtr popup( new Popup() );
215 // Pass ownership to CustomActor via derived handle.
216 Dali::Toolkit::Popup handle( *popup );
218 // Second-phase initialisation of the implementation.
219 // This can only be done after the CustomActor connection has been made.
226 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
227 mTouchedOutsideSignal(),
235 mPreviousFocusedActor(),
239 mAlterAddedChild( false ),
240 mLayoutDirty( true ),
242 mTouchTransparent( false ),
246 mDisplayState( Toolkit::Popup::HIDDEN ), // Hidden until shown with SetDisplayState()
247 mTailVisible( false ),
248 mTailPosition( DEFAULT_TAIL_POSITION ),
249 mContextualMode( Toolkit::Popup::NON_CONTEXTUAL ),
250 mAnimationDuration( DEFAULT_POPUP_ANIMATION_DURATION ),
251 mAnimationMode( Toolkit::Popup::FADE ),
252 mEntryAnimationData(),
253 mExitAnimationData(),
255 mBackingEnabled( true ),
256 mBackingColor( DEFAULT_BACKING_COLOR ),
257 mPopupBackgroundImage(),
258 mBackgroundBorder( DEFAULT_BACKGROUND_BORDER ),
260 mTailUpImage( DEFAULT_TAIL_UP_IMAGE_PATH ),
261 mTailDownImage( DEFAULT_TAIL_DOWN_IMAGE_PATH ),
262 mTailLeftImage( DEFAULT_TAIL_LEFT_IMAGE_PATH ),
263 mTailRightImage( DEFAULT_TAIL_RIGHT_IMAGE_PATH )
265 SetKeyboardNavigationSupport( true );
266 DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
267 return std::unique_ptr< Dali::Accessibility::Accessible >(
268 new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::DIALOG, true ) );
272 void Popup::OnInitialize()
275 self.SetName( "popup" );
277 // Apply some default resizing rules.
278 self.SetParentOrigin( ParentOrigin::CENTER );
279 self.SetAnchorPoint( AnchorPoint::CENTER );
281 self.SetSizeModeFactor( DEFAULT_POPUP_PARENT_RELATIVE_SIZE );
282 self.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
283 self.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
285 // Create a new layer so all Popup components can appear above all other actors.
286 mLayer = Layer::New();
287 mLayer.SetName( "popupLayer" );
289 mLayer.SetParentOrigin( ParentOrigin::CENTER );
290 mLayer.SetAnchorPoint( AnchorPoint::CENTER );
291 mLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
293 // Important to set as invisible as otherwise, if the popup is parented,
294 // but not shown yet it will appear statically on the screen.
295 mLayer.SetVisible( false );
297 // Add the layer to the hierarchy.
300 // Add Backing (Dimmed effect).
301 mBacking = CreateBacking();
302 mLayer.Add( mBacking );
304 mPopupContainer = Actor::New();
305 mPopupContainer.SetName( "popupContainer" );
306 mPopupContainer.SetParentOrigin( ParentOrigin::CENTER );
307 mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER );
308 mPopupContainer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
309 mLayer.Add( mPopupContainer );
311 // Create the Popup layout to contain all main content.
312 mPopupLayout = Toolkit::TableView::New( 3, 1 );
314 // Adds the default background image.
315 SetPopupBackgroundImage( Toolkit::ImageView::New( DEFAULT_BACKGROUND_IMAGE_PATH ) );
317 mPopupLayout.SetName( "popupLayoutTable" );
318 mPopupLayout.SetParentOrigin( ParentOrigin::CENTER );
319 mPopupLayout.SetAnchorPoint( AnchorPoint::CENTER );
321 mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
322 mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
323 mPopupLayout.SetSize( Stage::GetCurrent().GetSize().x * DEFAULT_RELATIVE_PARENT_WIDTH, 0.0f );
325 mPopupLayout.SetFitHeight( 0 ); // Set row to fit.
326 mPopupLayout.SetFitHeight( 1 ); // Set row to fit.
328 mPopupLayout.TouchSignal().Connect( this, &Popup::OnDialogTouched );
330 mPopupContainer.Add( mPopupLayout );
332 // Any content after this point which is added to Self() will be re-parented to mContent.
333 mAlterAddedChild = true;
335 SetAsKeyboardFocusGroup( true );
340 if( DevelControl::GetBoundAccessibilityObject( Self() ) )
341 Accessibility::Bridge::GetCurrentBridge()->RemovePopup( DevelControl::GetBoundAccessibilityObject( Self() ) );
342 mEntryAnimationData.Clear();
343 mExitAnimationData.Clear();
346 void Popup::LayoutAnimation()
348 // Perform setup based on the currently selected animation.
349 switch( mAnimationMode )
351 case Toolkit::Popup::ZOOM:
353 // Zoom animations start fully zoomed out.
354 mPopupContainer.SetScale( Vector3::ZERO );
358 case Toolkit::Popup::FADE:
360 // Fade animations start transparent.
361 mPopupContainer.SetOpacity( 0.0f );
365 case Toolkit::Popup::CUSTOM:
367 // Initialise the custom animation by playing to the end of it's exit animation instantly.
368 // EG. If it was zooming in, then we zoom out fully instantly so the zoom in works.
369 StartTransitionAnimation( false, true );
373 case Toolkit::Popup::NONE:
380 void Popup::StartTransitionAnimation( bool transitionIn, bool instantaneous /* false */ )
382 // Stop and recreate animation.
389 float duration = GetAnimationDuration();
391 // Setup variables ready to start the animations.
392 // If we are performing the animation instantaneously, we do not want to emit a signal.
397 // Setup variables and signal that we are starting the transition.
398 // Note: We signal even if the transition is instant so signal order is consistent.
399 mShowingSignal.Emit();
403 mHidingSignal.Emit();
407 // Perform chosen animation for the Popup.
408 switch( mAnimationMode )
410 case Toolkit::Popup::NONE:
412 mAnimation = Animation::New( 0.0f );
416 case Toolkit::Popup::ZOOM:
418 mAnimation = Animation::New( duration );
419 if( duration > Math::MACHINE_EPSILON_0 )
423 mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT, TimePeriod( duration * 0.25f, duration * 0.75f ) );
427 // Zoom out animation is twice the speed. Modify the duration variable so the backing animation speed is modified also.
429 mAnimation.SetDuration( duration );
430 mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ZERO, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration ) );
435 mPopupContainer.SetScale( transitionIn ? Vector3::ONE : Vector3::ZERO );
440 case Toolkit::Popup::FADE:
442 mAnimation = Animation::New( duration );
443 if( duration > Math::MACHINE_EPSILON_0 )
447 mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) );
451 mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) );
456 mPopupContainer.SetOpacity( transitionIn ? 1.0f : 0.0f );
461 case Toolkit::Popup::CUSTOM:
463 // Use a user specified animation for in and out.
464 // Read the correct animation depending on entry or exit.
465 // Attempt to use animation data defined from script data.
466 Dali::AnimationData* animationData = transitionIn ? &mEntryAnimationData : &mExitAnimationData;
468 // Create a new animation from the pre-defined data in the AnimationData class.
469 // If there is no data, mAnimation is invalidated.
470 mAnimation = animationData->CreateAnimation( mPopupContainer, duration );
472 // If we don't have a valid animation, provide a blank one so play() can still function generically.
475 // No animation was configured (even though custom mode was specified). Create a dummy animation to avoid an exception.
476 mAnimation = Animation::New( 0.0f );
483 // Animate the backing, if enabled.
484 // This is set up last so that different animation modes can have an effect on the backing animation speed.
485 if( mBackingEnabled )
487 // Use the alpha from the user-specified color.
488 float targetAlpha = mBackingColor.a;
489 if( duration > Math::MACHINE_EPSILON_0 )
493 mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), targetAlpha, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) );
497 mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) );
502 mBacking.SetProperty( Actor::Property::COLOR_ALPHA, transitionIn ? targetAlpha : 0.0f );
506 // If we are performing the animation instantaneously, jump to the position directly and do not signal.
509 mAnimation.SetCurrentProgress( 1.0f );
512 else if( duration > Math::MACHINE_EPSILON_0 )
514 // Run the animation.
515 mAnimation.FinishedSignal().Connect( this, &Popup::OnDisplayChangeAnimationFinished );
520 // We did not use an animation to achive the transition.
521 // Trigger the state change directly.
522 DisplayStateChangeComplete();
526 void Popup::OnDisplayChangeAnimationFinished( Animation& source )
528 DisplayStateChangeComplete();
531 void Popup::DisplayStateChangeComplete()
533 // Remove contents from stage if completely hidden.
534 if( mDisplayState == Toolkit::Popup::HIDING )
536 mDisplayState = Toolkit::Popup::HIDDEN;
538 mLayer.SetVisible( false );
539 mPopupLayout.SetSensitive( false );
541 // Guard against destruction during signal emission.
542 Toolkit::Popup handle( GetOwner() );
543 mHiddenSignal.Emit();
545 else if( mDisplayState == Toolkit::Popup::SHOWING )
547 mDisplayState = Toolkit::Popup::SHOWN;
548 Toolkit::Popup handle( GetOwner() );
551 // Start a timer to auto-hide if enabled.
552 if( mAutoHideDelay > 0u )
554 mAutoHideTimer = Timer::New( mAutoHideDelay );
555 mAutoHideTimer.TickSignal().Connect( this, &Popup::OnAutoHideTimeReached );
556 mAutoHideTimer.Start();
561 bool Popup::OnAutoHideTimeReached()
563 // Display timer has expired, auto hide the popup exactly as if the user had clicked outside.
564 SetDisplayState( Toolkit::Popup::HIDDEN );
568 mAutoHideTimer.Stop();
569 mAutoHideTimer.TickSignal().Disconnect( this, &Popup::OnAutoHideTimeReached );
570 mAutoHideTimer.Reset();
575 void Popup::SetPopupBackgroundImage( Actor image )
577 // Removes any previous background.
578 if( mPopupBackgroundImage )
580 mPopupBackgroundImage.Unparent();
583 mTailImage.Unparent();
587 // Adds new background to the dialog.
588 mPopupBackgroundImage = image;
589 mPopupBackgroundImage.SetName( "popupBackgroundImage" );
590 mPopupBackgroundImage.SetAnchorPoint( AnchorPoint::CENTER );
591 mPopupBackgroundImage.SetParentOrigin( ParentOrigin::CENTER );
593 // OnDialogTouched only consumes the event. It prevents the touch event to be caught by the backing.
594 mPopupBackgroundImage.TouchSignal().Connect( this, &Popup::OnDialogTouched );
596 // Set the popup border to be slightly larger than the layout contents.
597 UpdateBackgroundPositionAndSize();
599 const bool prevAlter = mAlterAddedChild;
600 mAlterAddedChild = false;
601 mPopupContainer.Add( mPopupBackgroundImage );
602 mPopupBackgroundImage.LowerToBottom();
603 mAlterAddedChild = prevAlter;
607 mPopupBackgroundImage.Add( mTailImage );
613 Actor Popup::GetPopupBackgroundImage() const
615 return mPopupBackgroundImage;
618 void Popup::SetTitle( Actor titleActor )
620 // Replaces the current title actor.
628 mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 0, 0) );
634 // Set up padding to give sensible default behaviour
635 // (an application developer can later override this if they wish).
636 mTitle.SetPadding( DEFAULT_TITLE_PADDING );
638 mPopupLayout.AddChild( mTitle, Toolkit::TableView::CellPosition( 0, 0 ) );
645 Actor Popup::GetTitle() const
650 void Popup::SetContent( Actor content )
652 // Remove previous content actor.
655 mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 1, 0 ) );
657 // Keep a handle to the new content.
662 mContent.SetName( "popupContent" );
664 mPopupLayout.AddChild( mContent, Toolkit::TableView::CellPosition( 1, 0 ) );
671 Actor Popup::GetContent() const
676 void Popup::SetFooter( Actor footer )
678 // Remove previous content actor.
681 mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 2, 0 ) );
684 // Keep a handle to the new content.
689 mFooter.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
691 // The control container has a fixed height.
692 mPopupLayout.SetFitHeight( 2u );
693 mPopupLayout.AddChild( footer, Toolkit::TableView::CellPosition( 2, 0 ) );
700 Actor Popup::GetFooter() const
705 void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState )
707 // Convert the 4-way state to a bool, true for show, false for hide.
708 bool display = ( displayState == Toolkit::Popup::SHOWING ) || ( displayState == Toolkit::Popup::SHOWN );
710 // Ignore if we are already at the target display state.
711 if( display == ( ( mDisplayState == Toolkit::Popup::SHOWING ) || ( mDisplayState == Toolkit::Popup::SHOWN ) ) )
716 // Convert the bool state to the actual display state to use.
717 mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
721 // Update the state to indicate the current intent.
722 mDisplayState = Toolkit::Popup::SHOWING;
724 // We want the popup to have key input focus when it is displayed
727 // We are displaying so bring the popup layer to the front, and set it visible so it is rendered.
729 mLayer.SetVisible( true );
731 // Set up the layout if this is the first display or the layout has become dirty.
734 // Bake-in any style and layout options to create the Popup layout.
738 // Allow the popup to catch events.
739 mPopupLayout.SetSensitive( true );
741 // Handle the keyboard focus when popup is shown.
742 Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
743 if( keyboardFocusManager )
745 mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor();
747 if( Self().IsKeyboardFocusable() )
749 // Setup the actgor to start focus from.
751 if( mContent && mContent.IsKeyboardFocusable() )
753 // If the content is focusable, move the focus to the content.
754 focusActor = mContent;
756 else if( mFooter && mFooter.IsKeyboardFocusable() )
758 // If the footer is focusable, move the focus to the footer.
759 focusActor = mFooter;
763 DALI_LOG_WARNING( "There is no focusable in popup\n" );
768 keyboardFocusManager.SetCurrentFocusActor( focusActor );
775 mDisplayState = Toolkit::Popup::HIDING;
776 ClearKeyInputFocus();
778 // Restore the keyboard focus when popup is hidden.
779 if( mPreviousFocusedActor && mPreviousFocusedActor.IsKeyboardFocusable() )
781 Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
782 if( keyboardFocusManager )
784 keyboardFocusManager.SetCurrentFocusActor( mPreviousFocusedActor );
789 // Perform animation.
790 StartTransitionAnimation( display );
793 Toolkit::Popup::DisplayState Popup::GetDisplayState() const
795 return mDisplayState;
798 void Popup::LayoutPopup()
800 mLayoutDirty = false;
802 /* When animating in, we want to respect the origin applied to Self().
803 * For example, if zooming, not only will the final result be anchored to the
804 * selected point, but the zoom will originate from this point also.
806 * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT :
815 mPopupContainer.SetParentOrigin( Self().GetCurrentParentOrigin() );
816 mPopupContainer.SetAnchorPoint( Self().GetCurrentAnchorPoint() );
818 // If there is only a title, use less padding.
821 if( !mContent && !mFooter )
823 mTitle.SetPadding( DEFAULT_TITLE_ONLY_PADDING );
827 mTitle.SetPadding( DEFAULT_TITLE_PADDING );
831 // Allow derived classes to perform any layout they may need to do.
834 // Update background visibility.
835 mPopupContainer.SetVisible( !( !mFooter && mPopupLayout.GetChildCount() == 0 ) );
837 // Create / destroy / position the tail as needed.
840 // Setup any layout and initialisation required for the selected animation.
846 void Popup::LayoutTail()
848 // Removes the tail actor.
849 if( mTailImage && mTailImage.GetParent() )
851 mTailImage.GetParent().Remove( mTailImage );
860 const Vector3& parentOrigin = GetTailPosition();
865 // depending on position of tail around ParentOrigin, a different tail image is used...
866 if( parentOrigin.y < Math::MACHINE_EPSILON_1 )
868 image = mTailUpImage;
869 anchorPoint = AnchorPoint::BOTTOM_CENTER;
870 position.y = mBackgroundBorder.top;
872 else if( parentOrigin.y > ( 1.0f - Math::MACHINE_EPSILON_1 ) )
874 image = mTailDownImage;
875 anchorPoint = AnchorPoint::TOP_CENTER;
876 position.y = - mBackgroundBorder.bottom;
878 else if( parentOrigin.x < Math::MACHINE_EPSILON_1 )
880 image = mTailLeftImage;
881 anchorPoint = AnchorPoint::CENTER_RIGHT;
882 position.x = mBackgroundBorder.left;
884 else if( parentOrigin.x > ( 1.0f - Math::MACHINE_EPSILON_1 ) )
886 image = mTailRightImage;
887 anchorPoint = AnchorPoint::CENTER_LEFT;
888 position.x = - mBackgroundBorder.right;
893 // Adds the tail actor.
894 mTailImage = Toolkit::ImageView::New( image );
895 mTailImage.SetName( "tailImage" );
896 mTailImage.SetParentOrigin( parentOrigin );
897 mTailImage.SetAnchorPoint( anchorPoint );
898 mTailImage.SetPosition( position );
900 if( mPopupBackgroundImage )
902 mPopupBackgroundImage.Add( mTailImage );
907 void Popup::SetContextualMode( Toolkit::Popup::ContextualMode mode )
909 mContextualMode = mode;
913 Toolkit::Popup::ContextualMode Popup::GetContextualMode() const
915 return mContextualMode;
918 Toolkit::Control Popup::CreateBacking()
920 Toolkit::Control backing = Control::New();
921 backing.SetProperty( Toolkit::Control::Property::BACKGROUND,
922 Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR )
923 .Add( Toolkit::ColorVisual::Property::MIX_COLOR, Vector4( mBackingColor.r, mBackingColor.g, mBackingColor.b, 1.0f ) ) );
924 backing.SetName( "popupBacking" );
926 // Must always be positioned top-left of stage, regardless of parent.
927 backing.SetInheritPosition(false);
929 // Always the full size of the stage.
930 backing.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
931 backing.SetSize( Stage::GetCurrent().GetSize() );
934 backing.SetSensitive( true );
936 // Default to being transparent.
937 backing.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f );
938 backing.TouchSignal().Connect( this, &Popup::OnBackingTouched );
939 backing.WheelEventSignal().Connect( this, &Popup::OnBackingWheelEvent );
943 Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
945 return mTouchedOutsideSignal;
948 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
950 return mShowingSignal;
953 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
958 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
960 return mHidingSignal;
963 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
965 return mHiddenSignal;
968 void Popup::SetTailVisibility( bool visible )
970 mTailVisible = visible;
974 const bool Popup::IsTailVisible() const
979 void Popup::SetTailPosition( Vector3 position )
981 mTailPosition = position;
985 const Vector3& Popup::GetTailPosition() const
987 return mTailPosition;
990 void Popup::SetAnimationDuration( float duration )
992 mAnimationDuration = duration;
996 float Popup::GetAnimationDuration() const
998 return mAnimationDuration;
1001 void Popup::SetAnimationMode( Toolkit::Popup::AnimationMode animationMode )
1003 mAnimationMode = animationMode;
1004 mLayoutDirty = true;
1007 Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const
1009 return mAnimationMode;
1012 void Popup::SetEntryAnimationData( const Property::Map& map )
1014 mEntryAnimationData.Clear();
1015 Scripting::NewAnimation( map, mEntryAnimationData );
1018 void Popup::SetExitAnimationData( const Property::Map& map )
1020 mExitAnimationData.Clear();
1021 Scripting::NewAnimation( map, mExitAnimationData );
1024 void Popup::UpdateBackgroundPositionAndSize()
1026 if( mPopupBackgroundImage )
1028 mPopupBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
1029 mPopupBackgroundImage.SetSizeModeFactor( Vector3( mBackgroundBorder.left + mBackgroundBorder.right, mBackgroundBorder.top + mBackgroundBorder.bottom, 0.0f ) );
1031 // Adjust the position of the background so the transparent areas are set appropriately
1032 mPopupBackgroundImage.SetPosition( ( mBackgroundBorder.right - mBackgroundBorder.left ) * 0.5f, ( mBackgroundBorder.bottom - mBackgroundBorder.top ) * 0.5f );
1036 void Popup::SetAutoHideDelay( int delay )
1038 mAutoHideDelay = delay;
1041 int Popup::GetAutoHideDelay() const
1043 return mAutoHideDelay;
1046 void Popup::SetBackingEnabled( bool enabled )
1048 mBackingEnabled = enabled;
1049 mLayoutDirty = true;
1052 const bool Popup::IsBackingEnabled() const
1054 return mBackingEnabled;
1057 void Popup::SetBackingColor( Vector4 color )
1059 mBackingColor = color;
1060 mBacking.SetBackgroundColor( Vector4( color.r, color.g, color.b, 1.0f ) );
1061 mLayoutDirty = true;
1064 const Vector4& Popup::GetBackingColor() const
1066 return mBackingColor;
1069 void Popup::SetTailUpImage( std::string image )
1071 mTailUpImage = image;
1072 mLayoutDirty = true;
1076 const std::string& Popup::GetTailUpImage() const
1078 return mTailUpImage;
1081 void Popup::SetTailDownImage( std::string image )
1083 mTailDownImage = image;
1084 mLayoutDirty = true;
1088 const std::string& Popup::GetTailDownImage() const
1090 return mTailDownImage;
1093 void Popup::SetTailLeftImage( std::string image )
1095 mTailLeftImage = image;
1096 mLayoutDirty = true;
1100 const std::string& Popup::GetTailLeftImage() const
1102 return mTailLeftImage;
1105 void Popup::SetTailRightImage( std::string image )
1107 mTailRightImage = image;
1108 mLayoutDirty = true;
1112 const std::string& Popup::GetTailRightImage() const
1114 return mTailRightImage;
1117 void Popup::SetTouchTransparent( bool enabled )
1119 mTouchTransparent = enabled;
1122 const bool Popup::IsTouchTransparent() const
1124 return mTouchTransparent;
1127 void Popup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1129 Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1133 Popup& popupImpl( GetImpl( popup ) );
1135 switch ( propertyIndex )
1137 case Toolkit::Popup::Property::TITLE:
1139 Property::Map valueMap;
1140 if( value.Get( valueMap ) )
1142 popupImpl.SetTitle( Scripting::NewActor( valueMap ) );
1146 case Toolkit::Popup::Property::CONTENT:
1148 Property::Map valueMap;
1149 if( value.Get( valueMap ) )
1151 popupImpl.SetContent( Scripting::NewActor( valueMap ) );
1155 case Toolkit::Popup::Property::FOOTER:
1157 Property::Map valueMap;
1158 if( value.Get( valueMap ) )
1160 popupImpl.SetFooter( Scripting::NewActor( valueMap ) );
1164 case Toolkit::Popup::Property::DISPLAY_STATE:
1166 std::string valueString;
1167 if( value.Get( valueString ) )
1169 Toolkit::Popup::DisplayState displayState( Toolkit::Popup::HIDDEN );
1170 if( Scripting::GetEnumeration< Toolkit::Popup::DisplayState >( valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState ) )
1172 popupImpl.SetDisplayState( displayState );
1177 case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1180 if( value.Get( valueBool ) )
1182 popupImpl.SetTouchTransparent( valueBool );
1186 case Toolkit::Popup::Property::TAIL_VISIBILITY:
1189 if( value.Get( valueBool ) )
1191 popupImpl.SetTailVisibility( valueBool );
1195 case Toolkit::Popup::Property::TAIL_POSITION:
1197 Vector3 valueVector3;
1198 if( value.Get( valueVector3 ) )
1200 popupImpl.SetTailPosition( valueVector3 );
1204 case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1206 std::string valueString;
1207 if( value.Get( valueString ) )
1209 Toolkit::Popup::ContextualMode contextualMode( Toolkit::Popup::BELOW );
1210 if( Scripting::GetEnumeration< Toolkit::Popup::ContextualMode >( valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode ) )
1212 popupImpl.SetContextualMode( contextualMode );
1217 case Toolkit::Popup::Property::ANIMATION_DURATION:
1220 if( value.Get( valueFloat ) )
1222 popupImpl.SetAnimationDuration( valueFloat );
1226 case Toolkit::Popup::Property::ANIMATION_MODE:
1228 std::string valueString;
1229 if( value.Get( valueString ) )
1231 Toolkit::Popup::AnimationMode animationMode( Toolkit::Popup::FADE );
1232 if( Scripting::GetEnumeration< Toolkit::Popup::AnimationMode >( valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode ) )
1234 popupImpl.SetAnimationMode( animationMode );
1239 case Toolkit::Popup::Property::ENTRY_ANIMATION:
1241 Property::Map valueMap;
1242 if( value.Get( valueMap ) )
1244 popupImpl.SetEntryAnimationData( valueMap );
1248 case Toolkit::Popup::Property::EXIT_ANIMATION:
1250 Property::Map valueMap;
1251 if( value.Get( valueMap ) )
1253 popupImpl.SetExitAnimationData( valueMap );
1257 case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1260 if( value.Get( valueInt ) )
1262 popupImpl.SetAutoHideDelay( valueInt );
1266 case Toolkit::Popup::Property::BACKING_ENABLED:
1269 if( value.Get( valueBool ) )
1271 popupImpl.SetBackingEnabled( valueBool );
1275 case Toolkit::Popup::Property::BACKING_COLOR:
1277 Vector4 valueVector4;
1278 if( value.Get( valueVector4 ) )
1280 popupImpl.SetBackingColor( valueVector4 );
1284 case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1286 std::string valueString;
1287 if( value.Get( valueString ) )
1289 Toolkit::ImageView actor = Toolkit::ImageView::New( valueString );
1290 popupImpl.SetPopupBackgroundImage( actor );
1294 case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1296 bool valueUpdated = false;
1298 Vector4 valueVector4;
1299 if( value.Get( popupImpl.mBackgroundBorder ) )
1301 valueUpdated = true;
1303 else if( value.Get( valueVector4 ) )
1305 popupImpl.mBackgroundBorder.left = valueVector4.x;
1306 popupImpl.mBackgroundBorder.right = valueVector4.y;
1307 popupImpl.mBackgroundBorder.bottom = valueVector4.z;
1308 popupImpl.mBackgroundBorder.top = valueVector4.w;
1309 valueUpdated = true;
1314 popupImpl.LayoutTail(); // Update the tail if required
1315 popupImpl.UpdateBackgroundPositionAndSize(); // Update the background's size and position
1319 case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1321 std::string valueString;
1322 if( value.Get( valueString ) )
1324 popupImpl.SetTailUpImage( valueString );
1328 case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1330 std::string valueString;
1331 if( value.Get( valueString ) )
1333 popupImpl.SetTailDownImage( valueString );
1337 case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1339 std::string valueString;
1340 if( value.Get( valueString ) )
1342 popupImpl.SetTailLeftImage( valueString );
1346 case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1348 std::string valueString;
1349 if( value.Get( valueString ) )
1351 popupImpl.SetTailRightImage( valueString );
1359 Property::Value Popup::GetProperty( BaseObject* object, Property::Index propertyIndex )
1361 Property::Value value;
1363 Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1367 Popup& popupImpl( GetImpl( popup ) );
1369 switch ( propertyIndex )
1371 case Toolkit::Popup::Property::TITLE:
1374 Scripting::CreatePropertyMap( popupImpl.GetTitle(), map );
1378 case Toolkit::Popup::Property::CONTENT:
1381 Scripting::CreatePropertyMap( popupImpl.GetContent(), map );
1385 case Toolkit::Popup::Property::FOOTER:
1388 Scripting::CreatePropertyMap( popupImpl.GetFooter(), map );
1392 case Toolkit::Popup::Property::DISPLAY_STATE:
1394 value = Scripting::GetLinearEnumerationName< Toolkit::Popup::DisplayState >( popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount );
1397 case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1399 value = popupImpl.IsTouchTransparent();
1402 case Toolkit::Popup::Property::TAIL_VISIBILITY:
1404 value = popupImpl.IsTailVisible();
1407 case Toolkit::Popup::Property::TAIL_POSITION:
1409 value = popupImpl.GetTailPosition();
1412 case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1414 value = Scripting::GetLinearEnumerationName< Toolkit::Popup::ContextualMode >( popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount );
1417 case Toolkit::Popup::Property::ANIMATION_DURATION:
1419 value = popupImpl.GetAnimationDuration();
1422 case Toolkit::Popup::Property::ANIMATION_MODE:
1424 value = Scripting::GetLinearEnumerationName< Toolkit::Popup::AnimationMode >( popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount );
1427 case Toolkit::Popup::Property::ENTRY_ANIMATION:
1429 // Note: Cannot retrieve property map from animation.
1434 case Toolkit::Popup::Property::EXIT_ANIMATION:
1436 // Note: Cannot retrieve property map from animation.
1441 case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1443 value = popupImpl.GetAutoHideDelay();
1446 case Toolkit::Popup::Property::BACKING_ENABLED:
1448 value = popupImpl.IsBackingEnabled();
1451 case Toolkit::Popup::Property::BACKING_COLOR:
1453 value = popupImpl.GetBackingColor();
1456 case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1458 Toolkit::ImageView imageView = Toolkit::ImageView::DownCast( popupImpl.GetPopupBackgroundImage() );
1461 value = imageView.GetProperty( Toolkit::ImageView::Property::IMAGE );
1465 case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1467 value = popupImpl.mBackgroundBorder;
1470 case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1472 value = popupImpl.GetTailUpImage();
1475 case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1477 value = popupImpl.GetTailDownImage();
1480 case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1482 value = popupImpl.GetTailLeftImage();
1485 case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1487 value = popupImpl.GetTailRightImage();
1496 bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1498 Dali::BaseHandle handle( object );
1500 bool connected( true );
1501 Toolkit::Popup popup = Toolkit::Popup::DownCast( handle );
1503 if( 0 == strcmp( signalName.c_str(), SIGNAL_TOUCHED_OUTSIDE ) )
1505 popup.OutsideTouchedSignal().Connect( tracker, functor );
1507 else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWING ) )
1509 popup.ShowingSignal().Connect( tracker, functor );
1511 else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWN ) )
1513 popup.ShownSignal().Connect( tracker, functor );
1515 else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDING ) )
1517 popup.HidingSignal().Connect( tracker, functor );
1519 else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDDEN ) )
1521 popup.HiddenSignal().Connect( tracker, functor );
1525 // signalName does not match any signal
1532 bool Popup::OnBackingTouched( Actor actor, const TouchData& touch )
1534 // Allow events to pass through if touch transparency is enabled.
1535 if( mTouchTransparent )
1540 if( touch.GetPointCount() > 0 )
1542 if( touch.GetState( 0 ) == PointState::DOWN )
1544 // Guard against destruction during signal emission.
1545 Toolkit::Popup handle( GetOwner() );
1547 mTouchedOutsideSignal.Emit();
1551 // Block anything behind backing becoming touched.
1552 mLayer.SetTouchConsumed( true );
1556 bool Popup::OnBackingWheelEvent( Actor actor, const WheelEvent& event )
1558 // Allow events to pass through if touch transparency is enabled.
1559 if( mTouchTransparent )
1564 // Consume wheel event in dimmed backing actor.
1565 mLayer.SetTouchConsumed( true );
1569 bool Popup::OnDialogTouched( Actor actor, const TouchData& touch )
1571 // Allow events to pass through if touch transparency is enabled.
1572 if( mTouchTransparent )
1577 // Consume event (stops backing actor receiving touch events)
1578 mLayer.SetTouchConsumed( true );
1582 void Popup::OnStageDisconnection()
1584 auto p = Dali::Accessibility::Accessible::Get(Self());
1585 Accessibility::Bridge::GetCurrentBridge()->RemovePopup( p );
1586 Control::OnStageDisconnection();
1589 void Popup::OnStageConnection( int depth )
1591 mLayoutDirty = true;
1594 Control::OnStageConnection( depth );
1595 auto p = Dali::Accessibility::Accessible::Get(Self());
1596 Accessibility::Bridge::GetCurrentBridge()->AddPopup( p );
1599 void Popup::OnChildAdd( Actor& child )
1601 // Re-parent any children added by user to the body layer.
1602 if( mAlterAddedChild )
1604 SetContent( child );
1608 mLayoutDirty = true;
1612 Control::OnChildAdd( child );
1615 void Popup::LayoutContext( const Vector2& size )
1617 // Do nothing if not in a contextual mode (or there is no parent context).
1618 Actor self = Self();
1619 Actor parent = self.GetParent();
1620 if( ( mContextualMode == Toolkit::Popup::NON_CONTEXTUAL ) || !parent )
1625 mPopupContainer.SetParentOrigin( ParentOrigin::CENTER );
1626 // We always anchor to the CENTER, rather than a different anchor point for each contextual
1627 // mode to allow code-reuse of the bound checking code (for maintainability).
1628 mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER );
1630 // Setup with some pre-calculations for speed.
1631 Vector3 halfStageSize( Stage().GetCurrent().GetSize() / 2.0f );
1632 Vector3 parentPosition( parent.GetCurrentPosition() );
1633 Vector2 halfSize( size / 2.0f );
1634 Vector2 halfParentSize( parent.GetRelayoutSize( Dimension::WIDTH ) / 2.0f, parent.GetRelayoutSize( Dimension::HEIGHT ) / 2.0f );
1635 Vector3 newPosition( Vector3::ZERO );
1637 // Perform different positioning based on the specified contextual layout mode.
1638 switch( mContextualMode )
1640 case Toolkit::Popup::BELOW:
1642 newPosition.x += halfSize.x - halfParentSize.x;
1643 newPosition.y += halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1646 case Toolkit::Popup::ABOVE:
1648 newPosition.x += halfSize.x - halfParentSize.x;
1649 newPosition.y -= halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1652 case Toolkit::Popup::RIGHT:
1654 newPosition.x += halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1655 newPosition.y += halfSize.y - halfParentSize.y;
1658 case Toolkit::Popup::LEFT:
1660 newPosition.x -= halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1661 newPosition.y += halfSize.y - halfParentSize.y;
1664 case Toolkit::Popup::NON_CONTEXTUAL:
1666 // Code won't reach here (caught earlier).
1671 // On-screen position checking.
1672 // Check new position is not too far right. If so, correct it.
1673 // Note: Check for right rather than left first, so if popup is too wide, the left check overrides
1674 // the right check and we at least see the left portion of the popup (as this is more useful).
1675 if( newPosition.x >= ( halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x ) )
1677 newPosition.x = halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x;
1679 // Check new position is not too far left. If so, correct it.
1680 if( newPosition.x < halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x )
1682 newPosition.x = halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x;// - parentSize.x;
1684 // Check new position is not too far down. If so, correct it.
1685 if( newPosition.y >= ( halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y ) )
1687 newPosition.y = halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1689 // Check new position is not too far up. If so, correct it.
1690 if( newPosition.y < halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y )
1692 newPosition.y = halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1695 // Set the final position.
1696 mPopupContainer.SetPosition( newPosition );
1699 void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container )
1701 Vector2 useSize( size );
1703 // Use the Popup layouts size, unless requested to use a fixed size.
1704 // In which case take the size set for the Popup itself.
1705 ResizePolicy::Type widthPolicy = Self().GetResizePolicy( Dimension::WIDTH );
1706 ResizePolicy::Type heightPolicy = Self().GetResizePolicy( Dimension::HEIGHT );
1708 // Width calculations:
1709 if( widthPolicy == ResizePolicy::USE_NATURAL_SIZE || widthPolicy == ResizePolicy::FIT_TO_CHILDREN )
1711 // If we using a child-based policy, take the size from the popup layout.
1712 mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
1713 useSize.width = mPopupLayout.GetRelayoutSize( Dimension::WIDTH );
1715 mPopupLayout.SetFitWidth( 0u );
1719 // If we using a parent-based policy, take the size from the popup object itself (self).
1720 mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
1722 mPopupLayout.SetFixedWidth( 0u, useSize.width );
1725 // Height calculations:
1726 // Title: Let the title be as high as it needs to be.
1727 mPopupLayout.SetFitHeight( 0u );
1729 // Footer: Convert the footer's resize policy to a TableView row policy.
1732 ResizePolicy::Type footerHeightPolicy = mFooter.GetResizePolicy( Dimension::HEIGHT );
1733 if( ( footerHeightPolicy == ResizePolicy::USE_NATURAL_SIZE ) ||
1734 ( footerHeightPolicy == ResizePolicy::FIT_TO_CHILDREN ) )
1736 mPopupLayout.SetFitHeight( 2u );
1738 else if( footerHeightPolicy == ResizePolicy::FIXED )
1740 mPopupLayout.SetFixedHeight( 2u, mFooter.GetRelayoutSize( Dimension::HEIGHT) );
1744 mPopupLayout.SetRelativeHeight( 2u, 1.0f );
1749 mPopupLayout.SetFixedHeight( 2u, 0.0f );
1752 // Popup contents: Adjust the tableview's policies based on the popup's policies.
1753 if( heightPolicy == ResizePolicy::USE_NATURAL_SIZE || heightPolicy == ResizePolicy::FIT_TO_CHILDREN )
1755 mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
1757 // Let both the contents expand as necessary.
1758 mPopupLayout.SetFitHeight( 1u );
1759 useSize.height = mPopupLayout.GetRelayoutSize( Dimension::HEIGHT );
1763 mPopupLayout.SetResizePolicy( heightPolicy, Dimension::HEIGHT );
1765 // Let the content expand to fill the remaining space.
1766 mPopupLayout.SetRelativeHeight( 1u, 1.0f );
1767 mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
1770 // Relayout the popup-layout to give it it's new size this frame.
1771 container.Add( mPopupLayout, useSize );
1775 container.Add( mContent, Vector2( mContent.GetRelayoutSize( Dimension::WIDTH ), mContent.GetRelayoutSize( Dimension::HEIGHT ) ) );
1778 // Perform contextual layout setup if required.
1779 // This is done each time in case the parent moves.
1780 // This will have no effect if no contextual mode is selected.
1781 LayoutContext( useSize );
1784 void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
1786 // To get the popup to emulate fit-to-children, we need to actually set use-natural-size.
1787 if( ( dimension & Dimension::HEIGHT ) && ( policy == ResizePolicy::FIT_TO_CHILDREN ) )
1789 Self().SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
1792 mLayoutDirty = true;
1796 Vector3 Popup::GetNaturalSize()
1798 return mPopupLayout.GetNaturalSize();
1801 float Popup::GetHeightForWidth( float width )
1803 return mPopupLayout.GetHeightForWidth( width );
1806 float Popup::GetWidthForHeight( float height )
1808 return mPopupLayout.GetWidthForHeight( height );
1811 bool Popup::OnKeyEvent( const KeyEvent& event )
1813 // Allow events to pass through if touch transparency is enabled.
1814 if( mTouchTransparent )
1819 bool consumed = false;
1821 if( event.state == KeyEvent::Down )
1823 if (event.keyCode == Dali::DALI_KEY_ESCAPE || event.keyCode == Dali::DALI_KEY_BACK)
1825 SetDisplayState( Toolkit::Popup::HIDDEN );
1833 void Popup::AddFocusableChildrenRecursive( Actor parent, std::vector< Actor >& focusableActors )
1837 Toolkit::Control control = Toolkit::Control::DownCast( parent );
1838 bool layoutControl = control && GetImplementation( control ).IsKeyboardNavigationSupported();
1840 if( parent.IsKeyboardFocusable() || layoutControl )
1842 focusableActors.push_back( parent );
1844 if( !layoutControl )
1846 for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
1848 Actor child( parent.GetChildAt( i ) );
1849 AddFocusableChildrenRecursive( child, focusableActors );
1856 void Popup::AddFocusableChildren( Actor parent, std::vector< Actor >& focusableActors )
1860 Toolkit::Control control = Toolkit::Control::DownCast( parent );
1861 if( !GetImplementation( control ).IsKeyboardNavigationSupported() )
1863 for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
1865 Actor child( parent.GetChildAt( i ) );
1866 AddFocusableChildrenRecursive( child, focusableActors );
1871 focusableActors.push_back( parent );
1876 Actor Popup::GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled )
1878 std::string currentStr;
1879 if( currentFocusedActor )
1881 currentStr = currentFocusedActor.GetName();
1884 Actor nextFocusableActor( currentFocusedActor );
1885 Actor currentFocusGroup;
1886 if( currentFocusedActor )
1888 currentFocusGroup = KeyboardFocusManager::Get().GetFocusGroup( currentFocusedActor );
1891 // TODO: Needs to be optimised
1892 // The following statement checks that if we have a current focused actor, then the current focus group is not the popup content or footer.
1893 // This is to detect if the focus is currently outside the popup, and if so, move it inside.
1894 if( !currentFocusedActor ||
1895 ( currentFocusedActor && ( ( !mContent || ( currentFocusGroup != mContent ) ) && ( !mFooter || ( currentFocusGroup != mFooter ) ) ) ) )
1897 // The current focused actor is not within popup.
1898 if( mContent && mContent.IsKeyboardFocusable() )
1900 // If the content is focusable, move the focus to the content.
1901 nextFocusableActor = mContent;
1903 else if( mFooter && mFooter.IsKeyboardFocusable() )
1905 // If the footer is focusable, move the focus to the footer.
1906 nextFocusableActor = mFooter;
1911 // Rebuild the focus chain because controls or content can be added or removed dynamically
1912 std::vector< Actor > focusableActors;
1914 AddFocusableChildren( mContent, focusableActors );
1915 AddFocusableChildren( mFooter, focusableActors );
1917 std::vector< Actor >::iterator endIterator = focusableActors.end();
1918 std::vector< Actor >::iterator currentIterator = focusableActors.begin();
1919 for( std::vector< Actor >::iterator iterator = focusableActors.begin(); iterator != endIterator; ++iterator )
1921 if( currentFocusedActor == *iterator )
1923 currentIterator = iterator;
1927 if( currentIterator != endIterator )
1931 case Toolkit::Control::KeyboardFocus::LEFT:
1933 if( currentIterator == focusableActors.begin() )
1935 nextFocusableActor = *( endIterator - 1 );
1939 nextFocusableActor = *( currentIterator - 1 );
1943 case Toolkit::Control::KeyboardFocus::RIGHT:
1945 if( currentIterator == endIterator - 1 )
1947 nextFocusableActor = *( focusableActors.begin() );
1951 nextFocusableActor = *( currentIterator + 1 );
1956 case Toolkit::Control::KeyboardFocus::UP:
1958 nextFocusableActor = *( focusableActors.begin() );
1962 case Toolkit::Control::KeyboardFocus::DOWN:
1964 nextFocusableActor = *( endIterator - 1 );
1974 if( !nextFocusableActor )
1976 DALI_LOG_WARNING( "Can not decide next focusable actor\n" );
1981 return nextFocusableActor;
1985 } // namespace Internal
1987 } // namespace Toolkit