2 * Copyright (c) 2020 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/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/devel-api/common/stage.h>
30 #include <dali/public-api/events/key-event.h>
31 #include <dali/public-api/events/touch-event.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>
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/visuals/color-visual-properties.h>
43 #include <dali-toolkit/public-api/visuals/visual-properties.h>
44 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
45 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
62 * Creation function for main Popup type.
63 * @return Handle to the new popup object.
67 return Toolkit::Popup::New();
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.
77 * Creation function for named type "popupToast".
78 * @return Handle to the new toast popup object.
80 BaseHandle CreateToast()
82 Toolkit::Popup popup = Toolkit::Popup::New();
84 // Setup for Toast Popup type.
85 popup.SetProperty( Actor::Property::SIZE_MODE_FACTOR, 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 );
92 // Disable the dimmed backing.
93 popup.SetProperty( Toolkit::Popup::Property::BACKING_ENABLED, false );
95 // The toast popup should fade in (not zoom).
96 popup.SetProperty( Toolkit::Popup::Property::ANIMATION_MODE, Toolkit::Popup::FADE );
98 // The toast popup should auto-hide.
99 popup.SetProperty( Toolkit::Popup::Property::AUTO_HIDE_DELAY, DEFAULT_TOAST_AUTO_HIDE_DELAY );
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 );
105 // Let events pass through the toast popup.
106 popup.SetProperty( Toolkit::Popup::Property::TOUCH_TRANSPARENT, true );
111 // Setup properties, signals and actions using the type-registry.
112 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Popup, Toolkit::Control, Create )
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 )
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 )
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 )
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 )
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 )
150 DALI_TYPE_REGISTRATION_END()
152 // Named type registration.
154 // Toast Popup: Non-modal popup that displays information at the bottom of the screen.
155 TypeRegistration typeRegistrationToast( "PopupToast", typeid( Toolkit::Popup ), CreateToast );
157 // Enumeration to / from string conversion tables
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] );
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] );
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] );
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.
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.
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.
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.
206 } // Unnamed namespace
212 Dali::Toolkit::Popup Popup::New()
214 // Create the implementation
215 PopupPtr popup( new Popup() );
217 // Pass ownership to CustomActor via derived handle.
218 Dali::Toolkit::Popup handle( *popup );
220 // Second-phase initialisation of the implementation.
221 // This can only be done after the CustomActor connection has been made.
228 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
229 mTouchedOutsideSignal(),
237 mPreviousFocusedActor(),
241 mAlterAddedChild( false ),
242 mLayoutDirty( true ),
244 mTouchTransparent( false ),
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(),
257 mBackingEnabled( true ),
258 mBackingColor( DEFAULT_BACKING_COLOR ),
259 mPopupBackgroundImage(),
260 mBackgroundBorder( DEFAULT_BACKGROUND_BORDER ),
267 SetKeyboardNavigationSupport( true );
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;
276 void Popup::OnInitialize()
279 self.SetProperty( Dali::Actor::Property::NAME, "popup" );
281 // Apply some default resizing rules.
282 self.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
283 self.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
285 self.SetProperty( Actor::Property::SIZE_MODE_FACTOR, DEFAULT_POPUP_PARENT_RELATIVE_SIZE );
286 self.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
287 self.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
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" );
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 );
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 );
301 // Add the layer to the hierarchy.
304 // Add Backing (Dimmed effect).
305 mBacking = CreateBacking();
306 mLayer.Add( mBacking );
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 );
315 // Create the Popup layout to contain all main content.
316 mPopupLayout = Toolkit::TableView::New( 3, 1 );
318 // Adds the default background image.
319 const std::string imageDirPath = AssetManager::GetDaliImagePath();
320 SetPopupBackgroundImage( Toolkit::ImageView::New( imageDirPath + DEFAULT_BACKGROUND_IMAGE_FILE_NAME ) );
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 );
326 mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
327 mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
328 mPopupLayout.SetProperty( Actor::Property::SIZE, Vector2( Stage::GetCurrent().GetSize().x * DEFAULT_RELATIVE_PARENT_WIDTH, 0.0f ) );
330 mPopupLayout.SetFitHeight( 0 ); // Set row to fit.
331 mPopupLayout.SetFitHeight( 1 ); // Set row to fit.
333 mPopupContainer.Add( mPopupLayout );
335 // Any content after this point which is added to Self() will be re-parented to mContent.
336 mAlterAddedChild = true;
338 SetAsKeyboardFocusGroup( true );
342 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor)
344 return std::unique_ptr<Dali::Accessibility::Accessible>(new AccessibleImpl(actor, Dali::Accessibility::Role::DIALOG, true));
350 mEntryAnimationData.Clear();
351 mExitAnimationData.Clear();
354 void Popup::LayoutAnimation()
356 // Perform setup based on the currently selected animation.
357 switch( mAnimationMode )
359 case Toolkit::Popup::ZOOM:
361 // Zoom animations start fully zoomed out.
362 mPopupContainer.SetProperty( Actor::Property::SCALE, Vector3::ZERO );
366 case Toolkit::Popup::FADE:
368 // Fade animations start transparent.
369 mPopupContainer.SetProperty( Actor::Property::OPACITY, 0.0f );
373 case Toolkit::Popup::CUSTOM:
375 // Initialise the custom animation by playing to the end of it's exit animation instantly.
376 // EG. If it was zooming in, then we zoom out fully instantly so the zoom in works.
377 StartTransitionAnimation( false, true );
381 case Toolkit::Popup::NONE:
388 void Popup::StartTransitionAnimation( bool transitionIn, bool instantaneous /* false */ )
390 // Stop and recreate animation.
397 float duration = GetAnimationDuration();
399 // Setup variables ready to start the animations.
400 // If we are performing the animation instantaneously, we do not want to emit a signal.
405 // Setup variables and signal that we are starting the transition.
406 // Note: We signal even if the transition is instant so signal order is consistent.
407 mShowingSignal.Emit();
411 mHidingSignal.Emit();
415 // Perform chosen animation for the Popup.
416 switch( mAnimationMode )
418 case Toolkit::Popup::NONE:
420 mAnimation = Animation::New( 0.0f );
424 case Toolkit::Popup::ZOOM:
426 mAnimation = Animation::New( duration );
427 if( duration > Math::MACHINE_EPSILON_0 )
431 mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT, TimePeriod( duration * 0.25f, duration * 0.75f ) );
435 // Zoom out animation is twice the speed. Modify the duration variable so the backing animation speed is modified also.
437 mAnimation.SetDuration( duration );
438 mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ZERO, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration ) );
443 mPopupContainer.SetProperty( Actor::Property::SCALE, transitionIn ? Vector3::ONE : Vector3::ZERO );
448 case Toolkit::Popup::FADE:
450 mAnimation = Animation::New( duration );
451 if( duration > Math::MACHINE_EPSILON_0 )
455 mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) );
459 mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) );
464 mPopupContainer.SetProperty( Actor::Property::OPACITY, transitionIn ? 1.0f : 0.0f );
469 case Toolkit::Popup::CUSTOM:
471 // Use a user specified animation for in and out.
472 // Read the correct animation depending on entry or exit.
473 // Attempt to use animation data defined from script data.
474 Dali::AnimationData* animationData = transitionIn ? &mEntryAnimationData : &mExitAnimationData;
476 // Create a new animation from the pre-defined data in the AnimationData class.
477 // If there is no data, mAnimation is invalidated.
478 mAnimation = animationData->CreateAnimation( mPopupContainer, duration );
480 // If we don't have a valid animation, provide a blank one so play() can still function generically.
483 // No animation was configured (even though custom mode was specified). Create a dummy animation to avoid an exception.
484 mAnimation = Animation::New( 0.0f );
491 // Animate the backing, if enabled.
492 // This is set up last so that different animation modes can have an effect on the backing animation speed.
493 if( mBackingEnabled )
495 // Use the alpha from the user-specified color.
496 float targetAlpha = mBackingColor.a;
497 if( duration > Math::MACHINE_EPSILON_0 )
501 mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), targetAlpha, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) );
505 mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) );
510 mBacking.SetProperty( Actor::Property::COLOR_ALPHA, transitionIn ? targetAlpha : 0.0f );
514 // If we are performing the animation instantaneously, jump to the position directly and do not signal.
517 mAnimation.SetCurrentProgress( 1.0f );
520 else if( duration > Math::MACHINE_EPSILON_0 )
522 // Run the animation.
523 mAnimation.FinishedSignal().Connect( this, &Popup::OnDisplayChangeAnimationFinished );
528 // We did not use an animation to achive the transition.
529 // Trigger the state change directly.
530 DisplayStateChangeComplete();
534 void Popup::OnDisplayChangeAnimationFinished( Animation& source )
536 DisplayStateChangeComplete();
539 void Popup::DisplayStateChangeComplete()
541 // Remove contents from stage if completely hidden.
542 if( mDisplayState == Toolkit::Popup::HIDING )
544 mDisplayState = Toolkit::Popup::HIDDEN;
546 mLayer.SetProperty( Actor::Property::VISIBLE, false );
547 mPopupLayout.SetProperty( Actor::Property::SENSITIVE, false );
549 // Guard against destruction during signal emission.
550 Toolkit::Popup handle( GetOwner() );
551 mHiddenSignal.Emit();
553 else if( mDisplayState == Toolkit::Popup::SHOWING )
555 mDisplayState = Toolkit::Popup::SHOWN;
556 Toolkit::Popup handle( GetOwner() );
559 // Start a timer to auto-hide if enabled.
560 if( mAutoHideDelay > 0u )
562 mAutoHideTimer = Timer::New( mAutoHideDelay );
563 mAutoHideTimer.TickSignal().Connect( this, &Popup::OnAutoHideTimeReached );
564 mAutoHideTimer.Start();
569 bool Popup::OnAutoHideTimeReached()
571 if (!Dali::Accessibility::IsUp() || true) // TODO: remove 'true' in sync with EFL (UX change)
573 // Display timer has expired, auto hide the popup exactly as if the user had clicked outside.
574 SetDisplayState( Toolkit::Popup::HIDDEN );
579 mAutoHideTimer.Stop();
580 mAutoHideTimer.TickSignal().Disconnect( this, &Popup::OnAutoHideTimeReached );
581 mAutoHideTimer.Reset();
586 void Popup::SetPopupBackgroundImage( Actor image )
588 // Removes any previous background.
589 if( mPopupBackgroundImage )
591 mPopupBackgroundImage.Unparent();
594 mTailImage.Unparent();
598 // Adds new background to the dialog.
599 mPopupBackgroundImage = image;
600 mPopupBackgroundImage.SetProperty( Dali::Actor::Property::NAME, "popupBackgroundImage" );
601 mPopupBackgroundImage.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
602 mPopupBackgroundImage.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
604 // Set the popup border to be slightly larger than the layout contents.
605 UpdateBackgroundPositionAndSize();
607 const bool prevAlter = mAlterAddedChild;
608 mAlterAddedChild = false;
609 mPopupContainer.Add( mPopupBackgroundImage );
610 mPopupBackgroundImage.LowerToBottom();
611 mAlterAddedChild = prevAlter;
615 mPopupBackgroundImage.Add( mTailImage );
621 Actor Popup::GetPopupBackgroundImage() const
623 return mPopupBackgroundImage;
626 void Popup::SetTitle( Actor titleActor )
628 // Replaces the current title actor.
636 mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 0, 0) );
642 // Set up padding to give sensible default behaviour
643 // (an application developer can later override this if they wish).
644 mTitle.SetProperty( Actor::Property::PADDING, DEFAULT_TITLE_PADDING );
646 mPopupLayout.AddChild( mTitle, Toolkit::TableView::CellPosition( 0, 0 ) );
653 Actor Popup::GetTitle() const
658 void Popup::SetContent( Actor content )
660 // Remove previous content actor.
663 mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 1, 0 ) );
665 // Keep a handle to the new content.
670 mContent.SetProperty( Dali::Actor::Property::NAME, "popupContent" );
672 mPopupLayout.AddChild( mContent, Toolkit::TableView::CellPosition( 1, 0 ) );
679 Actor Popup::GetContent() const
684 void Popup::SetFooter( Actor footer )
686 // Remove previous content actor.
689 mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 2, 0 ) );
692 // Keep a handle to the new content.
697 mFooter.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
699 // The control container has a fixed height.
700 mPopupLayout.SetFitHeight( 2u );
701 mPopupLayout.AddChild( footer, Toolkit::TableView::CellPosition( 2, 0 ) );
708 Actor Popup::GetFooter() const
713 void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState )
715 // Convert the 4-way state to a bool, true for show, false for hide.
716 bool display = ( displayState == Toolkit::Popup::SHOWING ) || ( displayState == Toolkit::Popup::SHOWN );
718 // Ignore if we are already at the target display state.
719 if( display == ( ( mDisplayState == Toolkit::Popup::SHOWING ) || ( mDisplayState == Toolkit::Popup::SHOWN ) ) )
724 auto *accessible = Dali::Accessibility::Accessible::Get(Self());
727 Dali::Accessibility::Bridge::GetCurrentBridge()->AddPopup(accessible);
728 accessible->EmitStateChanged(Dali::Accessibility::State::SHOWING, 1, 0);
732 accessible->EmitStateChanged(Dali::Accessibility::State::SHOWING, 0, 0);
733 Dali::Accessibility::Bridge::GetCurrentBridge()->RemovePopup(accessible);
736 // Convert the bool state to the actual display state to use.
737 mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
741 // Update the state to indicate the current intent.
742 mDisplayState = Toolkit::Popup::SHOWING;
744 // We want the popup to have key input focus when it is displayed
747 // We are displaying so bring the popup layer to the front, and set it visible so it is rendered.
749 mLayer.SetProperty( Actor::Property::VISIBLE, true );
751 // Set up the layout if this is the first display or the layout has become dirty.
754 // Bake-in any style and layout options to create the Popup layout.
758 // Allow the popup to catch events.
759 mPopupLayout.SetProperty( Actor::Property::SENSITIVE, true );
761 // Handle the keyboard focus when popup is shown.
762 Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
763 if( keyboardFocusManager )
765 mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor();
767 if( Self().GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) )
769 // Setup the actgor to start focus from.
771 if( mContent && mContent.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) )
773 // If the content is focusable, move the focus to the content.
774 focusActor = mContent;
776 else if( mFooter && mFooter.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) )
778 // If the footer is focusable, move the focus to the footer.
779 focusActor = mFooter;
783 DALI_LOG_WARNING( "There is no focusable in popup\n" );
788 keyboardFocusManager.SetCurrentFocusActor( focusActor );
795 mDisplayState = Toolkit::Popup::HIDING;
796 ClearKeyInputFocus();
798 // Restore the keyboard focus when popup is hidden.
799 if( mPreviousFocusedActor && mPreviousFocusedActor.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) )
801 Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
802 if( keyboardFocusManager )
804 keyboardFocusManager.SetCurrentFocusActor( mPreviousFocusedActor );
809 // Perform animation.
810 StartTransitionAnimation( display );
813 Toolkit::Popup::DisplayState Popup::GetDisplayState() const
815 return mDisplayState;
818 void Popup::LayoutPopup()
820 mLayoutDirty = false;
822 /* When animating in, we want to respect the origin applied to Self().
823 * For example, if zooming, not only will the final result be anchored to the
824 * selected point, but the zoom will originate from this point also.
826 * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT :
835 mPopupContainer.SetProperty( Actor::Property::PARENT_ORIGIN, Self().GetCurrentProperty< Vector3 >( Actor::Property::PARENT_ORIGIN ) );
836 mPopupContainer.SetProperty( Actor::Property::ANCHOR_POINT, Self().GetCurrentProperty< Vector3 >( Actor::Property::ANCHOR_POINT ) );
838 // If there is only a title, use less padding.
841 if( !mContent && !mFooter )
843 mTitle.SetProperty( Actor::Property::PADDING, DEFAULT_TITLE_ONLY_PADDING );
847 mTitle.SetProperty( Actor::Property::PADDING, DEFAULT_TITLE_PADDING );
851 // Allow derived classes to perform any layout they may need to do.
854 // Update background visibility.
855 mPopupContainer.SetProperty( Actor::Property::VISIBLE, !( !mFooter && mPopupLayout.GetChildCount() == 0 ) );
857 // Create / destroy / position the tail as needed.
860 // Setup any layout and initialisation required for the selected animation.
866 void Popup::LayoutTail()
868 // Removes the tail actor.
869 if( mTailImage && mTailImage.GetParent() )
871 mTailImage.GetParent().Remove( mTailImage );
880 const Vector3& parentOrigin = GetTailPosition();
885 // depending on position of tail around ParentOrigin, a different tail image is used...
886 if( parentOrigin.y < Math::MACHINE_EPSILON_1 )
888 image = mTailUpImage;
889 anchorPoint = AnchorPoint::BOTTOM_CENTER;
890 position.y = mBackgroundBorder.top;
892 else if( parentOrigin.y > ( 1.0f - Math::MACHINE_EPSILON_1 ) )
894 image = mTailDownImage;
895 anchorPoint = AnchorPoint::TOP_CENTER;
896 position.y = - mBackgroundBorder.bottom;
898 else if( parentOrigin.x < Math::MACHINE_EPSILON_1 )
900 image = mTailLeftImage;
901 anchorPoint = AnchorPoint::CENTER_RIGHT;
902 position.x = mBackgroundBorder.left;
904 else if( parentOrigin.x > ( 1.0f - Math::MACHINE_EPSILON_1 ) )
906 image = mTailRightImage;
907 anchorPoint = AnchorPoint::CENTER_LEFT;
908 position.x = - mBackgroundBorder.right;
913 // Adds the tail actor.
914 mTailImage = Toolkit::ImageView::New( image );
915 mTailImage.SetProperty( Dali::Actor::Property::NAME, "tailImage" );
916 mTailImage.SetProperty( Actor::Property::PARENT_ORIGIN, parentOrigin );
917 mTailImage.SetProperty( Actor::Property::ANCHOR_POINT, anchorPoint );
918 mTailImage.SetProperty( Actor::Property::POSITION, position );
920 if( mPopupBackgroundImage )
922 mPopupBackgroundImage.Add( mTailImage );
927 void Popup::SetContextualMode( Toolkit::Popup::ContextualMode mode )
929 mContextualMode = mode;
933 Toolkit::Popup::ContextualMode Popup::GetContextualMode() const
935 return mContextualMode;
938 Toolkit::Control Popup::CreateBacking()
940 Toolkit::Control backing = Control::New();
941 backing.SetProperty( Toolkit::Control::Property::BACKGROUND,
942 Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR )
943 .Add( Toolkit::ColorVisual::Property::MIX_COLOR, Vector4( mBackingColor.r, mBackingColor.g, mBackingColor.b, 1.0f ) ) );
944 backing.SetProperty( Dali::Actor::Property::NAME, "popupBacking" );
946 // Must always be positioned top-left of stage, regardless of parent.
947 backing.SetProperty( Actor::Property::INHERIT_POSITION, false );
949 // Always the full size of the stage.
950 backing.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
951 backing.SetProperty( Actor::Property::SIZE, Stage::GetCurrent().GetSize() );
954 backing.SetProperty( Actor::Property::SENSITIVE, true );
956 // Default to being transparent.
957 backing.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f );
958 backing.WheelEventSignal().Connect( this, &Popup::OnBackingWheelEvent );
962 Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
964 return mTouchedOutsideSignal;
967 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
969 return mShowingSignal;
972 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
977 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
979 return mHidingSignal;
982 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
984 return mHiddenSignal;
987 void Popup::SetTailVisibility( bool visible )
989 mTailVisible = visible;
993 const bool Popup::IsTailVisible() const
998 void Popup::SetTailPosition( Vector3 position )
1000 mTailPosition = position;
1001 mLayoutDirty = true;
1004 const Vector3& Popup::GetTailPosition() const
1006 return mTailPosition;
1009 void Popup::SetAnimationDuration( float duration )
1011 mAnimationDuration = duration;
1012 mLayoutDirty = true;
1015 float Popup::GetAnimationDuration() const
1017 return mAnimationDuration;
1020 void Popup::SetAnimationMode( Toolkit::Popup::AnimationMode animationMode )
1022 mAnimationMode = animationMode;
1023 mLayoutDirty = true;
1026 Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const
1028 return mAnimationMode;
1031 void Popup::SetEntryAnimationData( const Property::Map& map )
1033 mEntryAnimationData.Clear();
1034 Scripting::NewAnimation( map, mEntryAnimationData );
1037 void Popup::SetExitAnimationData( const Property::Map& map )
1039 mExitAnimationData.Clear();
1040 Scripting::NewAnimation( map, mExitAnimationData );
1043 void Popup::UpdateBackgroundPositionAndSize()
1045 if( mPopupBackgroundImage )
1047 mPopupBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
1048 mPopupBackgroundImage.SetProperty( Actor::Property::SIZE_MODE_FACTOR, Vector3( mBackgroundBorder.left + mBackgroundBorder.right, mBackgroundBorder.top + mBackgroundBorder.bottom, 0.0f ) );
1050 // Adjust the position of the background so the transparent areas are set appropriately
1051 mPopupBackgroundImage.SetProperty( Actor::Property::POSITION, Vector2( ( mBackgroundBorder.right - mBackgroundBorder.left ) * 0.5f, ( mBackgroundBorder.bottom - mBackgroundBorder.top ) * 0.5f ));
1055 void Popup::SetAutoHideDelay( int delay )
1057 mAutoHideDelay = delay;
1060 int Popup::GetAutoHideDelay() const
1062 return mAutoHideDelay;
1065 void Popup::SetBackingEnabled( bool enabled )
1067 mBackingEnabled = enabled;
1068 mLayoutDirty = true;
1071 const bool Popup::IsBackingEnabled() const
1073 return mBackingEnabled;
1076 void Popup::SetBackingColor( Vector4 color )
1078 mBackingColor = color;
1079 mBacking.SetBackgroundColor( Vector4( color.r, color.g, color.b, 1.0f ) );
1080 mLayoutDirty = true;
1083 const Vector4& Popup::GetBackingColor() const
1085 return mBackingColor;
1088 void Popup::SetTailUpImage( std::string image )
1090 mTailUpImage = image;
1091 mLayoutDirty = true;
1095 const std::string& Popup::GetTailUpImage() const
1097 return mTailUpImage;
1100 void Popup::SetTailDownImage( std::string image )
1102 mTailDownImage = image;
1103 mLayoutDirty = true;
1107 const std::string& Popup::GetTailDownImage() const
1109 return mTailDownImage;
1112 void Popup::SetTailLeftImage( std::string image )
1114 mTailLeftImage = image;
1115 mLayoutDirty = true;
1119 const std::string& Popup::GetTailLeftImage() const
1121 return mTailLeftImage;
1124 void Popup::SetTailRightImage( std::string image )
1126 mTailRightImage = image;
1127 mLayoutDirty = true;
1131 const std::string& Popup::GetTailRightImage() const
1133 return mTailRightImage;
1136 void Popup::SetTouchTransparent( bool enabled )
1138 if( mTouchTransparent != enabled )
1140 mTouchTransparent = enabled;
1145 const bool Popup::IsTouchTransparent() const
1147 return mTouchTransparent;
1150 void Popup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1152 Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1156 Popup& popupImpl( GetImpl( popup ) );
1158 switch ( propertyIndex )
1160 case Toolkit::Popup::Property::TITLE:
1162 Property::Map valueMap;
1163 if( value.Get( valueMap ) )
1165 popupImpl.SetTitle( Scripting::NewActor( valueMap ) );
1169 case Toolkit::Popup::Property::CONTENT:
1171 Property::Map valueMap;
1172 if( value.Get( valueMap ) )
1174 popupImpl.SetContent( Scripting::NewActor( valueMap ) );
1178 case Toolkit::Popup::Property::FOOTER:
1180 Property::Map valueMap;
1181 if( value.Get( valueMap ) )
1183 popupImpl.SetFooter( Scripting::NewActor( valueMap ) );
1187 case Toolkit::Popup::Property::DISPLAY_STATE:
1189 std::string valueString;
1190 if( value.Get( valueString ) )
1192 Toolkit::Popup::DisplayState displayState( Toolkit::Popup::HIDDEN );
1193 if( Scripting::GetEnumeration< Toolkit::Popup::DisplayState >( valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState ) )
1195 popupImpl.SetDisplayState( displayState );
1200 case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1203 if( value.Get( valueBool ) )
1205 popupImpl.SetTouchTransparent( valueBool );
1209 case Toolkit::Popup::Property::TAIL_VISIBILITY:
1212 if( value.Get( valueBool ) )
1214 popupImpl.SetTailVisibility( valueBool );
1218 case Toolkit::Popup::Property::TAIL_POSITION:
1220 Vector3 valueVector3;
1221 if( value.Get( valueVector3 ) )
1223 popupImpl.SetTailPosition( valueVector3 );
1227 case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1229 std::string valueString;
1230 if( value.Get( valueString ) )
1232 Toolkit::Popup::ContextualMode contextualMode( Toolkit::Popup::BELOW );
1233 if( Scripting::GetEnumeration< Toolkit::Popup::ContextualMode >( valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode ) )
1235 popupImpl.SetContextualMode( contextualMode );
1240 case Toolkit::Popup::Property::ANIMATION_DURATION:
1243 if( value.Get( valueFloat ) )
1245 popupImpl.SetAnimationDuration( valueFloat );
1249 case Toolkit::Popup::Property::ANIMATION_MODE:
1251 std::string valueString;
1252 if( value.Get( valueString ) )
1254 Toolkit::Popup::AnimationMode animationMode( Toolkit::Popup::FADE );
1255 if( Scripting::GetEnumeration< Toolkit::Popup::AnimationMode >( valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode ) )
1257 popupImpl.SetAnimationMode( animationMode );
1262 case Toolkit::Popup::Property::ENTRY_ANIMATION:
1264 Property::Map valueMap;
1265 if( value.Get( valueMap ) )
1267 popupImpl.SetEntryAnimationData( valueMap );
1271 case Toolkit::Popup::Property::EXIT_ANIMATION:
1273 Property::Map valueMap;
1274 if( value.Get( valueMap ) )
1276 popupImpl.SetExitAnimationData( valueMap );
1280 case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1283 if( value.Get( valueInt ) )
1285 popupImpl.SetAutoHideDelay( valueInt );
1289 case Toolkit::Popup::Property::BACKING_ENABLED:
1292 if( value.Get( valueBool ) )
1294 popupImpl.SetBackingEnabled( valueBool );
1298 case Toolkit::Popup::Property::BACKING_COLOR:
1300 Vector4 valueVector4;
1301 if( value.Get( valueVector4 ) )
1303 popupImpl.SetBackingColor( valueVector4 );
1307 case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1309 std::string valueString;
1310 if( value.Get( valueString ) )
1312 Toolkit::ImageView actor = Toolkit::ImageView::New( valueString );
1313 popupImpl.SetPopupBackgroundImage( actor );
1317 case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1319 bool valueUpdated = false;
1321 Vector4 valueVector4;
1322 if( value.Get( popupImpl.mBackgroundBorder ) )
1324 valueUpdated = true;
1326 else if( value.Get( valueVector4 ) )
1328 popupImpl.mBackgroundBorder.left = valueVector4.x;
1329 popupImpl.mBackgroundBorder.right = valueVector4.y;
1330 popupImpl.mBackgroundBorder.bottom = valueVector4.z;
1331 popupImpl.mBackgroundBorder.top = valueVector4.w;
1332 valueUpdated = true;
1337 popupImpl.LayoutTail(); // Update the tail if required
1338 popupImpl.UpdateBackgroundPositionAndSize(); // Update the background's size and position
1342 case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1344 std::string valueString;
1345 if( value.Get( valueString ) )
1347 popupImpl.SetTailUpImage( valueString );
1351 case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1353 std::string valueString;
1354 if( value.Get( valueString ) )
1356 popupImpl.SetTailDownImage( valueString );
1360 case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1362 std::string valueString;
1363 if( value.Get( valueString ) )
1365 popupImpl.SetTailLeftImage( valueString );
1369 case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1371 std::string valueString;
1372 if( value.Get( valueString ) )
1374 popupImpl.SetTailRightImage( valueString );
1382 Property::Value Popup::GetProperty( BaseObject* object, Property::Index propertyIndex )
1384 Property::Value value;
1386 Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
1390 Popup& popupImpl( GetImpl( popup ) );
1392 switch ( propertyIndex )
1394 case Toolkit::Popup::Property::TITLE:
1397 Scripting::CreatePropertyMap( popupImpl.GetTitle(), map );
1401 case Toolkit::Popup::Property::CONTENT:
1404 Scripting::CreatePropertyMap( popupImpl.GetContent(), map );
1408 case Toolkit::Popup::Property::FOOTER:
1411 Scripting::CreatePropertyMap( popupImpl.GetFooter(), map );
1415 case Toolkit::Popup::Property::DISPLAY_STATE:
1417 value = Scripting::GetLinearEnumerationName< Toolkit::Popup::DisplayState >( popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount );
1420 case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1422 value = popupImpl.IsTouchTransparent();
1425 case Toolkit::Popup::Property::TAIL_VISIBILITY:
1427 value = popupImpl.IsTailVisible();
1430 case Toolkit::Popup::Property::TAIL_POSITION:
1432 value = popupImpl.GetTailPosition();
1435 case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1437 value = Scripting::GetLinearEnumerationName< Toolkit::Popup::ContextualMode >( popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount );
1440 case Toolkit::Popup::Property::ANIMATION_DURATION:
1442 value = popupImpl.GetAnimationDuration();
1445 case Toolkit::Popup::Property::ANIMATION_MODE:
1447 value = Scripting::GetLinearEnumerationName< Toolkit::Popup::AnimationMode >( popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount );
1450 case Toolkit::Popup::Property::ENTRY_ANIMATION:
1452 // Note: Cannot retrieve property map from animation.
1457 case Toolkit::Popup::Property::EXIT_ANIMATION:
1459 // Note: Cannot retrieve property map from animation.
1464 case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1466 value = popupImpl.GetAutoHideDelay();
1469 case Toolkit::Popup::Property::BACKING_ENABLED:
1471 value = popupImpl.IsBackingEnabled();
1474 case Toolkit::Popup::Property::BACKING_COLOR:
1476 value = popupImpl.GetBackingColor();
1479 case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1481 Toolkit::ImageView imageView = Toolkit::ImageView::DownCast( popupImpl.GetPopupBackgroundImage() );
1484 value = imageView.GetProperty( Toolkit::ImageView::Property::IMAGE );
1488 case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1490 value = popupImpl.mBackgroundBorder;
1493 case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1495 value = popupImpl.GetTailUpImage();
1498 case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1500 value = popupImpl.GetTailDownImage();
1503 case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1505 value = popupImpl.GetTailLeftImage();
1508 case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1510 value = popupImpl.GetTailRightImage();
1519 bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1521 Dali::BaseHandle handle( object );
1523 bool connected( true );
1524 Toolkit::Popup popup = Toolkit::Popup::DownCast( handle );
1526 if( 0 == strcmp( signalName.c_str(), SIGNAL_TOUCHED_OUTSIDE ) )
1528 popup.OutsideTouchedSignal().Connect( tracker, functor );
1530 else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWING ) )
1532 popup.ShowingSignal().Connect( tracker, functor );
1534 else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWN ) )
1536 popup.ShownSignal().Connect( tracker, functor );
1538 else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDING ) )
1540 popup.HidingSignal().Connect( tracker, functor );
1542 else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDDEN ) )
1544 popup.HiddenSignal().Connect( tracker, functor );
1548 // signalName does not match any signal
1555 bool Popup::OnBackingTouched( Actor actor, const TouchEvent& touch )
1557 // Allow events to pass through if the backing isn't the hit-actor
1558 if( (touch.GetHitActor(0) == actor) &&
1559 (touch.GetPointCount() > 0) &&
1560 (touch.GetState( 0 ) == PointState::DOWN))
1562 // Guard against destruction during signal emission.
1563 Toolkit::Popup handle( GetOwner() );
1565 mTouchedOutsideSignal.Emit();
1571 bool Popup::OnBackingWheelEvent( Actor actor, const WheelEvent& event )
1573 // Allow events to pass through if touch transparency is enabled.
1574 if( mTouchTransparent )
1582 bool Popup::OnDialogTouched( Actor actor, const TouchEvent& touch )
1584 // Only connecting this so the backing does not become the default hit-actor and inadvertently closes the popup
1588 void Popup::OnSceneConnection( int depth )
1590 mLayoutDirty = true;
1593 Control::OnSceneConnection( depth );
1596 void Popup::OnChildAdd( Actor& child )
1598 // Re-parent any children added by user to the body layer.
1599 if( mAlterAddedChild )
1601 SetContent( child );
1605 mLayoutDirty = true;
1609 Control::OnChildAdd( child );
1612 void Popup::LayoutContext( const Vector2& size )
1614 // Do nothing if not in a contextual mode (or there is no parent context).
1615 Actor self = Self();
1616 Actor parent = self.GetParent();
1617 if( ( mContextualMode == Toolkit::Popup::NON_CONTEXTUAL ) || !parent )
1622 mPopupContainer.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
1623 // We always anchor to the CENTER, rather than a different anchor point for each contextual
1624 // mode to allow code-reuse of the bound checking code (for maintainability).
1625 mPopupContainer.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
1627 // Setup with some pre-calculations for speed.
1628 Vector3 halfStageSize( Stage().GetCurrent().GetSize() / 2.0f );
1629 Vector3 parentPosition( parent.GetCurrentProperty< Vector3 >( Actor::Property::POSITION ) );
1630 Vector2 halfSize( size / 2.0f );
1631 Vector2 halfParentSize( parent.GetRelayoutSize( Dimension::WIDTH ) / 2.0f, parent.GetRelayoutSize( Dimension::HEIGHT ) / 2.0f );
1632 Vector3 newPosition( Vector3::ZERO );
1634 // Perform different positioning based on the specified contextual layout mode.
1635 switch( mContextualMode )
1637 case Toolkit::Popup::BELOW:
1639 newPosition.x += halfSize.x - halfParentSize.x;
1640 newPosition.y += halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1643 case Toolkit::Popup::ABOVE:
1645 newPosition.x += halfSize.x - halfParentSize.x;
1646 newPosition.y -= halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1649 case Toolkit::Popup::RIGHT:
1651 newPosition.x += halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1652 newPosition.y += halfSize.y - halfParentSize.y;
1655 case Toolkit::Popup::LEFT:
1657 newPosition.x -= halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1658 newPosition.y += halfSize.y - halfParentSize.y;
1661 case Toolkit::Popup::NON_CONTEXTUAL:
1663 // Code won't reach here (caught earlier).
1668 // On-screen position checking.
1669 // Check new position is not too far right. If so, correct it.
1670 // Note: Check for right rather than left first, so if popup is too wide, the left check overrides
1671 // the right check and we at least see the left portion of the popup (as this is more useful).
1672 if( newPosition.x >= ( halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x ) )
1674 newPosition.x = halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x;
1676 // Check new position is not too far left. If so, correct it.
1677 if( newPosition.x < halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x )
1679 newPosition.x = halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x;// - parentSize.x;
1681 // Check new position is not too far down. If so, correct it.
1682 if( newPosition.y >= ( halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y ) )
1684 newPosition.y = halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1686 // Check new position is not too far up. If so, correct it.
1687 if( newPosition.y < halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y )
1689 newPosition.y = halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1692 // Set the final position.
1693 mPopupContainer.SetProperty( Actor::Property::POSITION, newPosition );
1696 void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container )
1698 Vector2 useSize( size );
1700 // Use the Popup layouts size, unless requested to use a fixed size.
1701 // In which case take the size set for the Popup itself.
1702 ResizePolicy::Type widthPolicy = Self().GetResizePolicy( Dimension::WIDTH );
1703 ResizePolicy::Type heightPolicy = Self().GetResizePolicy( Dimension::HEIGHT );
1705 // Width calculations:
1706 if( widthPolicy == ResizePolicy::USE_NATURAL_SIZE || widthPolicy == ResizePolicy::FIT_TO_CHILDREN )
1708 // If we using a child-based policy, take the size from the popup layout.
1709 mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
1710 useSize.width = mPopupLayout.GetRelayoutSize( Dimension::WIDTH );
1712 mPopupLayout.SetFitWidth( 0u );
1716 // If we using a parent-based policy, take the size from the popup object itself (self).
1717 mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
1719 mPopupLayout.SetFixedWidth( 0u, useSize.width );
1722 // Height calculations:
1723 // Title: Let the title be as high as it needs to be.
1724 mPopupLayout.SetFitHeight( 0u );
1726 // Footer: Convert the footer's resize policy to a TableView row policy.
1729 ResizePolicy::Type footerHeightPolicy = mFooter.GetResizePolicy( Dimension::HEIGHT );
1730 if( ( footerHeightPolicy == ResizePolicy::USE_NATURAL_SIZE ) ||
1731 ( footerHeightPolicy == ResizePolicy::FIT_TO_CHILDREN ) )
1733 mPopupLayout.SetFitHeight( 2u );
1735 else if( footerHeightPolicy == ResizePolicy::FIXED )
1737 mPopupLayout.SetFixedHeight( 2u, mFooter.GetRelayoutSize( Dimension::HEIGHT) );
1741 mPopupLayout.SetRelativeHeight( 2u, 1.0f );
1746 mPopupLayout.SetFixedHeight( 2u, 0.0f );
1749 // Popup contents: Adjust the tableview's policies based on the popup's policies.
1750 if( heightPolicy == ResizePolicy::USE_NATURAL_SIZE || heightPolicy == ResizePolicy::FIT_TO_CHILDREN )
1752 mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
1754 // Let both the contents expand as necessary.
1755 mPopupLayout.SetFitHeight( 1u );
1756 useSize.height = mPopupLayout.GetRelayoutSize( Dimension::HEIGHT );
1760 mPopupLayout.SetResizePolicy( heightPolicy, Dimension::HEIGHT );
1762 // Let the content expand to fill the remaining space.
1763 mPopupLayout.SetRelativeHeight( 1u, 1.0f );
1764 mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
1767 // Relayout the popup-layout to give it it's new size this frame.
1768 container.Add( mPopupLayout, useSize );
1772 container.Add( mContent, Vector2( mContent.GetRelayoutSize( Dimension::WIDTH ), mContent.GetRelayoutSize( Dimension::HEIGHT ) ) );
1775 // Perform contextual layout setup if required.
1776 // This is done each time in case the parent moves.
1777 // This will have no effect if no contextual mode is selected.
1778 LayoutContext( useSize );
1781 void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
1783 // To get the popup to emulate fit-to-children, we need to actually set use-natural-size.
1784 if( ( dimension & Dimension::HEIGHT ) && ( policy == ResizePolicy::FIT_TO_CHILDREN ) )
1786 Self().SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
1789 mLayoutDirty = true;
1793 Vector3 Popup::GetNaturalSize()
1795 return mPopupLayout.GetNaturalSize();
1798 float Popup::GetHeightForWidth( float width )
1800 return mPopupLayout.GetHeightForWidth( width );
1803 float Popup::GetWidthForHeight( float height )
1805 return mPopupLayout.GetWidthForHeight( height );
1808 bool Popup::OnKeyEvent( const KeyEvent& event )
1810 // Allow events to pass through if touch transparency is enabled.
1811 if( mTouchTransparent )
1816 bool consumed = false;
1818 if( event.GetState() == KeyEvent::DOWN )
1820 if (event.GetKeyCode() == Dali::DALI_KEY_ESCAPE || event.GetKeyCode() == Dali::DALI_KEY_BACK)
1822 SetDisplayState( Toolkit::Popup::HIDDEN );
1830 void Popup::AddFocusableChildrenRecursive( Actor parent, std::vector< Actor >& focusableActors )
1834 Toolkit::Control control = Toolkit::Control::DownCast( parent );
1835 bool layoutControl = control && GetImplementation( control ).IsKeyboardNavigationSupported();
1837 if( parent.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) || layoutControl )
1839 focusableActors.push_back( parent );
1841 if( !layoutControl )
1843 for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
1845 Actor child( parent.GetChildAt( i ) );
1846 AddFocusableChildrenRecursive( child, focusableActors );
1853 void Popup::AddFocusableChildren( Actor parent, std::vector< Actor >& focusableActors )
1857 Toolkit::Control control = Toolkit::Control::DownCast( parent );
1858 if( !GetImplementation( control ).IsKeyboardNavigationSupported() )
1860 for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
1862 Actor child( parent.GetChildAt( i ) );
1863 AddFocusableChildrenRecursive( child, focusableActors );
1868 focusableActors.push_back( parent );
1873 Actor Popup::GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled )
1875 std::string currentStr;
1876 if( currentFocusedActor )
1878 currentStr = currentFocusedActor.GetProperty< std::string >( Dali::Actor::Property::NAME );
1881 Actor nextFocusableActor( currentFocusedActor );
1882 Actor currentFocusGroup;
1883 if( currentFocusedActor )
1885 currentFocusGroup = KeyboardFocusManager::Get().GetFocusGroup( currentFocusedActor );
1888 // TODO: Needs to be optimised
1889 // The following statement checks that if we have a current focused actor, then the current focus group is not the popup content or footer.
1890 // This is to detect if the focus is currently outside the popup, and if so, move it inside.
1891 if( !currentFocusedActor ||
1892 ( currentFocusedActor && ( ( !mContent || ( currentFocusGroup != mContent ) ) && ( !mFooter || ( currentFocusGroup != mFooter ) ) ) ) )
1894 // The current focused actor is not within popup.
1895 if( mContent && mContent.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) )
1897 // If the content is focusable, move the focus to the content.
1898 nextFocusableActor = mContent;
1900 else if( mFooter && mFooter.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) )
1902 // If the footer is focusable, move the focus to the footer.
1903 nextFocusableActor = mFooter;
1908 // Rebuild the focus chain because controls or content can be added or removed dynamically
1909 std::vector< Actor > focusableActors;
1911 AddFocusableChildren( mContent, focusableActors );
1912 AddFocusableChildren( mFooter, focusableActors );
1914 std::vector< Actor >::iterator endIterator = focusableActors.end();
1915 std::vector< Actor >::iterator currentIterator = focusableActors.begin();
1916 for( std::vector< Actor >::iterator iterator = focusableActors.begin(); iterator != endIterator; ++iterator )
1918 if( currentFocusedActor == *iterator )
1920 currentIterator = iterator;
1924 if( currentIterator != endIterator )
1928 case Toolkit::Control::KeyboardFocus::LEFT:
1930 if( currentIterator == focusableActors.begin() )
1932 nextFocusableActor = *( endIterator - 1 );
1936 nextFocusableActor = *( currentIterator - 1 );
1940 case Toolkit::Control::KeyboardFocus::RIGHT:
1942 if( currentIterator == endIterator - 1 )
1944 nextFocusableActor = *( focusableActors.begin() );
1948 nextFocusableActor = *( currentIterator + 1 );
1953 case Toolkit::Control::KeyboardFocus::UP:
1955 nextFocusableActor = *( focusableActors.begin() );
1959 case Toolkit::Control::KeyboardFocus::DOWN:
1961 nextFocusableActor = *( endIterator - 1 );
1971 if( !nextFocusableActor )
1973 DALI_LOG_WARNING( "Can not decide next focusable actor\n" );
1978 return nextFocusableActor;
1981 void Popup::SetupTouch()
1983 if( ! mTouchTransparent )
1985 // Connect all the signals and set us up to consume all touch events
1986 mBacking.TouchedSignal().Connect( this, &Popup::OnBackingTouched );
1987 mPopupBackgroundImage.TouchedSignal().Connect( this, &Popup::OnDialogTouched );
1988 mPopupLayout.TouchedSignal().Connect( this, &Popup::OnDialogTouched );
1989 mLayer.SetProperty( Layer::Property::CONSUMES_TOUCH, true );
1993 // We are touch transparent so disconnect all signals and ensure our layer does not consumed all touch events
1994 mBacking.TouchedSignal().Disconnect( this, &Popup::OnBackingTouched );
1995 mPopupBackgroundImage.TouchedSignal().Disconnect( this, &Popup::OnDialogTouched );
1996 mPopupLayout.TouchedSignal().Disconnect( this, &Popup::OnDialogTouched );
1997 mLayer.SetProperty( Layer::Property::CONSUMES_TOUCH, false );
2001 Dali::Accessibility::States Popup::AccessibleImpl::CalculateStates()
2003 auto states = Control::Impl::AccessibleImpl::CalculateStates();
2004 auto popup = Toolkit::Popup::DownCast(self);
2005 auto displayState = popup.GetProperty<std::string>(Toolkit::Popup::Property::DISPLAY_STATE);
2007 states[Dali::Accessibility::State::SHOWING] = (displayState == "SHOWN" || displayState == "SHOWING");
2012 } // namespace Internal
2014 } // namespace Toolkit