2 * Copyright (c) 2021 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 <dali/devel-api/actors/actor-devel.h>
23 #include <dali/devel-api/adaptor-framework/physical-keyboard.h>
24 #include <dali/devel-api/common/stage.h>
25 #include <dali/devel-api/scripting/scripting.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/public-api/adaptor-framework/key.h>
28 #include <dali/public-api/animation/constraints.h>
29 #include <dali/public-api/events/key-event.h>
30 #include <dali/public-api/events/touch-event.h>
31 #include <dali/public-api/object/type-registry-helper.h>
32 #include <dali/public-api/object/type-registry.h>
33 #include <dali/public-api/size-negotiation/relayout-container.h>
34 #include <cstring> // for strcmp
37 #include <dali-toolkit/dali-toolkit.h>
38 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
39 #include <dali-toolkit/devel-api/controls/control-devel.h>
40 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
41 #include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
42 #include <dali-toolkit/public-api/controls/control-impl.h>
43 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
44 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
45 #include <dali-toolkit/public-api/visuals/visual-properties.h>
58 * Creation function for main Popup type.
59 * @return Handle to the new popup object.
63 return Toolkit::Popup::New();
66 // Toast style defaults.
67 const int DEFAULT_TOAST_AUTO_HIDE_DELAY = 3000; ///< Toast will auto-hide after 3000ms (3 seconds)
68 const float DEFAULT_TOAST_TRANSITION_TIME = 0.65f; ///< Default time the toast Popup will take to show and hide.
69 const Vector3 DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN(0.5f, 0.94f, 0.5f); ///< This is similar to BOTTOM_CENTER, but vertically higher up, as a ratio of parent height.
70 const Vector3 DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO(0.75f, 0.75f, 0.75f); ///< Amount of the stage's width that the toast popup will take up.
73 * Creation function for named type "popupToast".
74 * @return Handle to the new toast popup object.
76 BaseHandle CreateToast()
78 Toolkit::Popup popup = Toolkit::Popup::New();
80 // Setup for Toast Popup type.
81 popup.SetProperty(Actor::Property::SIZE_MODE_FACTOR, DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO);
82 popup.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH);
83 popup.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
84 popup.SetProperty(Toolkit::Popup::Property::CONTEXTUAL_MODE, Toolkit::Popup::NON_CONTEXTUAL);
85 popup.SetProperty(Toolkit::Popup::Property::ANIMATION_DURATION, DEFAULT_TOAST_TRANSITION_TIME);
86 popup.SetProperty(Toolkit::Popup::Property::TAIL_VISIBILITY, false);
88 // Disable the dimmed backing.
89 popup.SetProperty(Toolkit::Popup::Property::BACKING_ENABLED, false);
91 // The toast popup should fade in (not zoom).
92 popup.SetProperty(Toolkit::Popup::Property::ANIMATION_MODE, Toolkit::Popup::FADE);
94 // The toast popup should auto-hide.
95 popup.SetProperty(Toolkit::Popup::Property::AUTO_HIDE_DELAY, DEFAULT_TOAST_AUTO_HIDE_DELAY);
97 // Align to the bottom of the screen.
98 popup.SetProperty(Actor::Property::PARENT_ORIGIN, DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN);
99 popup.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
101 // Let events pass through the toast popup.
102 popup.SetProperty(Toolkit::Popup::Property::TOUCH_TRANSPARENT, true);
108 // Setup properties, signals and actions using the type-registry.
109 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::Popup, Toolkit::Control, Create )
111 // Main content related properties.
112 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "title", MAP, TITLE )
113 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "content", MAP, CONTENT )
114 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "footer", MAP, FOOTER )
115 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "displayState", STRING, DISPLAY_STATE )
116 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "touchTransparent", BOOLEAN, TOUCH_TRANSPARENT )
118 // Contextual related properties.
119 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "tailVisibility", BOOLEAN, TAIL_VISIBILITY )
120 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "tailPosition", VECTOR3, TAIL_POSITION )
121 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "contextualMode", STRING, CONTEXTUAL_MODE )
123 // Animation related properties.
124 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "animationDuration", FLOAT, ANIMATION_DURATION )
125 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "animationMode", STRING, ANIMATION_MODE )
126 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "entryAnimation", MAP, ENTRY_ANIMATION )
127 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "exitAnimation", MAP, EXIT_ANIMATION )
128 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "autoHideDelay", INTEGER, AUTO_HIDE_DELAY )
130 // Style related properties.
131 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "backingEnabled", BOOLEAN, BACKING_ENABLED )
132 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "backingColor", VECTOR4, BACKING_COLOR )
133 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "popupBackgroundImage", STRING, POPUP_BACKGROUND_IMAGE )
134 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "popupBackgroundBorder", RECTANGLE, POPUP_BACKGROUND_BORDER)
135 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "tailUpImage", STRING, TAIL_UP_IMAGE )
136 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "tailDownImage", STRING, TAIL_DOWN_IMAGE )
137 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "tailLeftImage", STRING, TAIL_LEFT_IMAGE )
138 DALI_PROPERTY_REGISTRATION(Toolkit, Popup, "tailRightImage", STRING, TAIL_RIGHT_IMAGE )
141 DALI_SIGNAL_REGISTRATION(Toolkit, Popup, "touchedOutside", SIGNAL_TOUCHED_OUTSIDE)
142 DALI_SIGNAL_REGISTRATION(Toolkit, Popup, "showing", SIGNAL_SHOWING )
143 DALI_SIGNAL_REGISTRATION(Toolkit, Popup, "shown", SIGNAL_SHOWN )
144 DALI_SIGNAL_REGISTRATION(Toolkit, Popup, "hiding", SIGNAL_HIDING )
145 DALI_SIGNAL_REGISTRATION(Toolkit, Popup, "hidden", SIGNAL_HIDDEN )
147 DALI_TYPE_REGISTRATION_END()
149 // Named type registration.
151 // Toast Popup: Non-modal popup that displays information at the bottom of the screen.
152 TypeRegistration typeRegistrationToast("PopupToast", typeid( Toolkit::Popup ), CreateToast);
154 // Enumeration to / from string conversion tables
156 const Scripting::StringEnum DisplayStateTable[] =
158 {"SHOWING", Toolkit::Popup::SHOWING},
159 {"SHOWN", Toolkit::Popup::SHOWN },
160 {"HIDING", Toolkit::Popup::HIDING },
161 {"HIDDEN", Toolkit::Popup::HIDDEN },
163 const unsigned int DisplayStateTableCount = sizeof(DisplayStateTable) / sizeof(DisplayStateTable[0]);
165 const Scripting::StringEnum AnimationModeTable[] =
167 {"NONE", Toolkit::Popup::NONE },
168 {"ZOOM", Toolkit::Popup::ZOOM },
169 {"FADE", Toolkit::Popup::FADE },
170 {"CUSTOM", Toolkit::Popup::CUSTOM},
172 const unsigned int AnimationModeTableCount = sizeof(AnimationModeTable) / sizeof(AnimationModeTable[0]);
174 const Scripting::StringEnum ContextualModeTable[] =
176 {"NON_CONTEXTUAL", Toolkit::Popup::NON_CONTEXTUAL},
177 {"ABOVE", Toolkit::Popup::ABOVE },
178 {"RIGHT", Toolkit::Popup::RIGHT },
179 {"BELOW", Toolkit::Popup::BELOW },
180 {"LEFT", Toolkit::Popup::LEFT },
182 const unsigned int ContextualModeTableCount = sizeof(ContextualModeTable) / sizeof(ContextualModeTable[0]);
186 const Vector3 DEFAULT_POPUP_PARENT_RELATIVE_SIZE(0.75f, 1.0f, 1.0f); ///< Default size percentage of parent.
187 const float DEFAULT_POPUP_ANIMATION_DURATION = 0.6f; ///< Duration of hide/show animations.
188 const float POPUP_OUT_MARGIN_WIDTH = 16.f; ///< Space between the screen edge and the popup edge in the horizontal dimension.
189 const float POPUP_OUT_MARGIN_HEIGHT = 36.f; ///< Space between the screen edge and the popup edge in the vertical dimension.
190 const Vector3 DEFAULT_TAIL_POSITION(0.5f, 1.0f, 0.0f); ///< Position the tail will be displayed when enabled without setting the position.
192 // Contextual defaults.
193 const Vector2 DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN(10.0f, 10.0f); ///< How close the Popup will be to it's contextual parent.
194 const Vector2 DEFAULT_CONTEXTUAL_STAGE_BORDER(15.0f, 15.0f); ///< How close the Popup can be to the stage edges.
196 // Popup style defaults.
197 const char* DEFAULT_BACKGROUND_IMAGE_FILE_NAME = "00_popup_bg.9.png"; ///< Background image.
198 const char* DEFAULT_TAIL_UP_IMAGE_FILE_NAME = "popup_tail_up.png"; ///< Tail up image.
199 const char* DEFAULT_TAIL_DOWN_IMAGE_FILE_NAME = "popup_tail_down.png"; ///< Tail down image.
200 const char* DEFAULT_TAIL_LEFT_IMAGE_FILE_NAME = "popup_tail_left.png"; ///< Tail left image.
201 const char* DEFAULT_TAIL_RIGHT_IMAGE_FILE_NAME = "popup_tail_right.png"; ///< Tail right image.
203 const Vector4 DEFAULT_BACKING_COLOR(0.0f, 0.0f, 0.0f, 0.5f); ///< Color of the dimmed backing.
204 const Rect<int> DEFAULT_BACKGROUND_BORDER(17, 17, 13, 13); ///< Default border of the background.
205 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).
206 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).
207 const Vector3 FOOTER_SIZE(620.0f, 96.0f, 0.0f); ///< Default size of the bottom control area.
208 const float DEFAULT_RELATIVE_PARENT_WIDTH = 0.75f; ///< If width is not fixed, relative size to parent is used by default.
210 } // Unnamed namespace
216 Dali::Toolkit::Popup Popup::New()
218 // Create the implementation
219 PopupPtr popup(new Popup());
221 // Pass ownership to CustomActor via derived handle.
222 Dali::Toolkit::Popup handle(*popup);
224 // Second-phase initialisation of the implementation.
225 // This can only be done after the CustomActor connection has been made.
232 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
233 mTouchedOutsideSignal(),
241 mPreviousFocusedActor(),
245 mAlterAddedChild(false),
248 mTouchTransparent(false),
252 mDisplayState(Toolkit::Popup::HIDDEN), // Hidden until shown with SetDisplayState()
254 mTailPosition(DEFAULT_TAIL_POSITION),
255 mContextualMode(Toolkit::Popup::NON_CONTEXTUAL),
256 mAnimationDuration(DEFAULT_POPUP_ANIMATION_DURATION),
257 mAnimationMode(Toolkit::Popup::FADE),
258 mEntryAnimationData(),
259 mExitAnimationData(),
261 mBackingEnabled(true),
262 mBackingColor(DEFAULT_BACKING_COLOR),
263 mPopupBackgroundImage(),
264 mBackgroundBorder(DEFAULT_BACKGROUND_BORDER),
271 SetKeyboardNavigationSupport(true);
273 const std::string imageDirPath = AssetManager::GetDaliImagePath();
274 mTailUpImage = imageDirPath + DEFAULT_TAIL_UP_IMAGE_FILE_NAME;
275 mTailDownImage = imageDirPath + DEFAULT_TAIL_DOWN_IMAGE_FILE_NAME;
276 mTailLeftImage = imageDirPath + DEFAULT_TAIL_LEFT_IMAGE_FILE_NAME;
277 mTailRightImage = imageDirPath + DEFAULT_TAIL_RIGHT_IMAGE_FILE_NAME;
280 void Popup::OnInitialize()
283 self.SetProperty(Dali::Actor::Property::NAME, "popup");
285 // Apply some default resizing rules.
286 self.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
287 self.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
289 self.SetProperty(Actor::Property::SIZE_MODE_FACTOR, DEFAULT_POPUP_PARENT_RELATIVE_SIZE);
290 self.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH);
291 self.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
293 // Create a new layer so all Popup components can appear above all other actors.
294 mLayer = Layer::New();
295 mLayer.SetProperty(Dali::Actor::Property::NAME, "popupLayer");
297 mLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
298 mLayer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
299 mLayer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
301 // Important to set as invisible as otherwise, if the popup is parented,
302 // but not shown yet it will appear statically on the screen.
303 mLayer.SetProperty(Actor::Property::VISIBLE, false);
305 // Add the layer to the hierarchy.
308 // Add Backing (Dimmed effect).
309 mBacking = CreateBacking();
310 mLayer.Add(mBacking);
312 mPopupContainer = Actor::New();
313 mPopupContainer.SetProperty(Dali::Actor::Property::NAME, "popupContainer");
314 mPopupContainer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
315 mPopupContainer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
316 mPopupContainer.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS);
317 mLayer.Add(mPopupContainer);
319 // Create the Popup layout to contain all main content.
320 mPopupLayout = Toolkit::TableView::New(3, 1);
322 // Adds the default background image.
323 const std::string imageDirPath = AssetManager::GetDaliImagePath();
324 SetPopupBackgroundImage(Toolkit::ImageView::New(imageDirPath + DEFAULT_BACKGROUND_IMAGE_FILE_NAME));
326 mPopupLayout.SetProperty(Dali::Actor::Property::NAME, "popupLayoutTable");
327 mPopupLayout.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
328 mPopupLayout.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
330 mPopupLayout.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH);
331 mPopupLayout.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
332 mPopupLayout.SetProperty(Actor::Property::SIZE, Vector2(Stage::GetCurrent().GetSize().x * DEFAULT_RELATIVE_PARENT_WIDTH, 0.0f));
334 mPopupLayout.SetFitHeight(0); // Set row to fit.
335 mPopupLayout.SetFitHeight(1); // Set row to fit.
337 mPopupContainer.Add(mPopupLayout);
339 // Any content after this point which is added to Self() will be re-parented to mContent.
340 mAlterAddedChild = true;
342 SetAsKeyboardFocusGroup(true);
346 DevelControl::AppendAccessibilityAttribute(self, "sub-role", "Alert");
348 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
349 return std::unique_ptr<Dali::Accessibility::Accessible>(new AccessibleImpl(actor, Dali::Accessibility::Role::DIALOG, true));
355 mEntryAnimationData.Clear();
356 mExitAnimationData.Clear();
359 void Popup::LayoutAnimation()
361 // Perform setup based on the currently selected animation.
362 switch(mAnimationMode)
364 case Toolkit::Popup::ZOOM:
366 // Zoom animations start fully zoomed out.
367 mPopupContainer.SetProperty(Actor::Property::SCALE, Vector3::ZERO);
371 case Toolkit::Popup::FADE:
373 // Fade animations start transparent.
374 mPopupContainer.SetProperty(Actor::Property::OPACITY, 0.0f);
378 case Toolkit::Popup::CUSTOM:
380 // Initialise the custom animation by playing to the end of it's exit animation instantly.
381 // EG. If it was zooming in, then we zoom out fully instantly so the zoom in works.
382 StartTransitionAnimation(false, true);
386 case Toolkit::Popup::NONE:
393 void Popup::StartTransitionAnimation(bool transitionIn, bool instantaneous /* false */)
395 // Stop and recreate animation.
402 float duration = GetAnimationDuration();
404 // Setup variables ready to start the animations.
405 // If we are performing the animation instantaneously, we do not want to emit a signal.
410 // Setup variables and signal that we are starting the transition.
411 // Note: We signal even if the transition is instant so signal order is consistent.
412 mShowingSignal.Emit();
416 mHidingSignal.Emit();
420 // Perform chosen animation for the Popup.
421 switch(mAnimationMode)
423 case Toolkit::Popup::NONE:
425 mAnimation = Animation::New(0.0f);
429 case Toolkit::Popup::ZOOM:
431 mAnimation = Animation::New(duration);
432 if(duration > Math::MACHINE_EPSILON_0)
436 mAnimation.AnimateTo(Property(mPopupContainer, Actor::Property::SCALE), Vector3::ONE, AlphaFunction::EASE_IN_OUT, TimePeriod(duration * 0.25f, duration * 0.75f));
440 // Zoom out animation is twice the speed. Modify the duration variable so the backing animation speed is modified also.
442 mAnimation.SetDuration(duration);
443 mAnimation.AnimateTo(Property(mPopupContainer, Actor::Property::SCALE), Vector3::ZERO, AlphaFunction::EASE_IN_OUT, TimePeriod(0.0f, duration));
448 mPopupContainer.SetProperty(Actor::Property::SCALE, transitionIn ? Vector3::ONE : Vector3::ZERO);
453 case Toolkit::Popup::FADE:
455 mAnimation = Animation::New(duration);
456 if(duration > Math::MACHINE_EPSILON_0)
460 mAnimation.AnimateTo(Property(mPopupContainer, Actor::Property::COLOR_ALPHA), 1.0f, AlphaFunction::EASE_IN_OUT, TimePeriod(0.30f, duration * 0.70f));
464 mAnimation.AnimateTo(Property(mPopupContainer, Actor::Property::COLOR_ALPHA), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod(0.0f, duration * 0.70f));
469 mPopupContainer.SetProperty(Actor::Property::OPACITY, transitionIn ? 1.0f : 0.0f);
474 case Toolkit::Popup::CUSTOM:
476 // Use a user specified animation for in and out.
477 // Read the correct animation depending on entry or exit.
478 // Attempt to use animation data defined from script data.
479 Dali::AnimationData* animationData = transitionIn ? &mEntryAnimationData : &mExitAnimationData;
481 // Create a new animation from the pre-defined data in the AnimationData class.
482 // If there is no data, mAnimation is invalidated.
483 mAnimation = animationData->CreateAnimation(mPopupContainer, duration);
485 // If we don't have a valid animation, provide a blank one so play() can still function generically.
488 // No animation was configured (even though custom mode was specified). Create a dummy animation to avoid an exception.
489 mAnimation = Animation::New(0.0f);
496 // Animate the backing, if enabled.
497 // This is set up last so that different animation modes can have an effect on the backing animation speed.
500 // Use the alpha from the user-specified color.
501 float targetAlpha = mBackingColor.a;
502 if(duration > Math::MACHINE_EPSILON_0)
506 mAnimation.AnimateTo(Property(mBacking, Actor::Property::COLOR_ALPHA), targetAlpha, AlphaFunction::EASE_IN_OUT, TimePeriod(0.0f, duration * 0.70f));
510 mAnimation.AnimateTo(Property(mBacking, Actor::Property::COLOR_ALPHA), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod(0.30f, duration * 0.70f));
515 mBacking.SetProperty(Actor::Property::COLOR_ALPHA, transitionIn ? targetAlpha : 0.0f);
519 // If we are performing the animation instantaneously, jump to the position directly and do not signal.
522 mAnimation.SetCurrentProgress(1.0f);
525 else if(duration > Math::MACHINE_EPSILON_0)
527 // Run the animation.
528 mAnimation.FinishedSignal().Connect(this, &Popup::OnDisplayChangeAnimationFinished);
533 // We did not use an animation to achive the transition.
534 // Trigger the state change directly.
535 DisplayStateChangeComplete();
539 void Popup::OnDisplayChangeAnimationFinished(Animation& source)
541 DisplayStateChangeComplete();
544 void Popup::DisplayStateChangeComplete()
546 // Remove contents from stage if completely hidden.
547 if(mDisplayState == Toolkit::Popup::HIDING)
549 mDisplayState = Toolkit::Popup::HIDDEN;
551 mLayer.SetProperty(Actor::Property::VISIBLE, false);
552 mPopupLayout.SetProperty(Actor::Property::SENSITIVE, false);
554 // Guard against destruction during signal emission.
555 Toolkit::Popup handle(GetOwner());
556 mHiddenSignal.Emit();
558 else if(mDisplayState == Toolkit::Popup::SHOWING)
560 mDisplayState = Toolkit::Popup::SHOWN;
561 Toolkit::Popup handle(GetOwner());
564 // Start a timer to auto-hide if enabled.
565 if(mAutoHideDelay > 0u)
567 mAutoHideTimer = Timer::New(mAutoHideDelay);
568 mAutoHideTimer.TickSignal().Connect(this, &Popup::OnAutoHideTimeReached);
569 mAutoHideTimer.Start();
574 bool Popup::OnAutoHideTimeReached()
576 if(!Dali::Accessibility::IsUp() || true) // TODO: remove 'true' in sync with EFL (UX change)
578 // Display timer has expired, auto hide the popup exactly as if the user had clicked outside.
579 SetDisplayState(Toolkit::Popup::HIDDEN);
584 mAutoHideTimer.Stop();
585 mAutoHideTimer.TickSignal().Disconnect(this, &Popup::OnAutoHideTimeReached);
586 mAutoHideTimer.Reset();
591 void Popup::SetPopupBackgroundImage(Actor image)
593 // Removes any previous background.
594 if(mPopupBackgroundImage)
596 mPopupBackgroundImage.Unparent();
599 mTailImage.Unparent();
603 // Adds new background to the dialog.
604 mPopupBackgroundImage = image;
605 mPopupBackgroundImage.SetProperty(Dali::Actor::Property::NAME, "popupBackgroundImage");
606 mPopupBackgroundImage.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
607 mPopupBackgroundImage.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
609 // Set the popup border to be slightly larger than the layout contents.
610 UpdateBackgroundPositionAndSize();
612 const bool prevAlter = mAlterAddedChild;
613 mAlterAddedChild = false;
614 mPopupContainer.Add(mPopupBackgroundImage);
615 mPopupBackgroundImage.LowerToBottom();
616 mAlterAddedChild = prevAlter;
620 mPopupBackgroundImage.Add(mTailImage);
626 Actor Popup::GetPopupBackgroundImage() const
628 return mPopupBackgroundImage;
631 void Popup::SetTitle(Actor titleActor)
633 // Replaces the current title actor.
641 mPopupLayout.RemoveChildAt(Toolkit::TableView::CellPosition(0, 0));
647 // Set up padding to give sensible default behaviour
648 // (an application developer can later override this if they wish).
649 mTitle.SetProperty(Actor::Property::PADDING, DEFAULT_TITLE_PADDING);
651 mPopupLayout.AddChild(mTitle, Toolkit::TableView::CellPosition(0, 0));
658 Actor Popup::GetTitle() const
663 void Popup::SetContent(Actor content)
665 // Remove previous content actor.
668 mPopupLayout.RemoveChildAt(Toolkit::TableView::CellPosition(1, 0));
670 // Keep a handle to the new content.
675 mContent.SetProperty(Dali::Actor::Property::NAME, "popupContent");
677 mPopupLayout.AddChild(mContent, Toolkit::TableView::CellPosition(1, 0));
684 Actor Popup::GetContent() const
689 void Popup::SetFooter(Actor footer)
691 // Remove previous content actor.
694 mPopupLayout.RemoveChildAt(Toolkit::TableView::CellPosition(2, 0));
697 // Keep a handle to the new content.
702 mFooter.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
704 // The control container has a fixed height.
705 mPopupLayout.SetFitHeight(2u);
706 mPopupLayout.AddChild(footer, Toolkit::TableView::CellPosition(2, 0));
713 Actor Popup::GetFooter() const
718 void Popup::SetDisplayState(Toolkit::Popup::DisplayState displayState)
720 // Convert the 4-way state to a bool, true for show, false for hide.
721 bool display = (displayState == Toolkit::Popup::SHOWING) || (displayState == Toolkit::Popup::SHOWN);
723 // Ignore if we are already at the target display state.
724 if(display == ((mDisplayState == Toolkit::Popup::SHOWING) || (mDisplayState == Toolkit::Popup::SHOWN)))
729 auto* accessible = Dali::Accessibility::Accessible::Get(Self());
732 Dali::Accessibility::Bridge::GetCurrentBridge()->AddPopup(accessible);
733 accessible->EmitStateChanged(Dali::Accessibility::State::SHOWING, 1, 0);
737 accessible->EmitStateChanged(Dali::Accessibility::State::SHOWING, 0, 0);
738 Dali::Accessibility::Bridge::GetCurrentBridge()->RemovePopup(accessible);
741 // Convert the bool state to the actual display state to use.
742 mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
746 // Update the state to indicate the current intent.
747 mDisplayState = Toolkit::Popup::SHOWING;
749 // We want the popup to have key input focus when it is displayed
752 // We are displaying so bring the popup layer to the front, and set it visible so it is rendered.
754 mLayer.SetProperty(Actor::Property::VISIBLE, true);
756 // Set up the layout if this is the first display or the layout has become dirty.
759 // Bake-in any style and layout options to create the Popup layout.
763 // Allow the popup to catch events.
764 mPopupLayout.SetProperty(Actor::Property::SENSITIVE, true);
766 // Handle the keyboard focus when popup is shown.
767 Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
768 if(keyboardFocusManager)
770 mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor();
772 if(Self().GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
774 // Setup the actgor to start focus from.
776 if(mContent && mContent.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
778 // If the content is focusable, move the focus to the content.
779 focusActor = mContent;
781 else if(mFooter && mFooter.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
783 // If the footer is focusable, move the focus to the footer.
784 focusActor = mFooter;
788 DALI_LOG_WARNING("There is no focusable in popup\n");
793 keyboardFocusManager.SetCurrentFocusActor(focusActor);
800 mDisplayState = Toolkit::Popup::HIDING;
801 ClearKeyInputFocus();
803 // Restore the keyboard focus when popup is hidden.
804 if(mPreviousFocusedActor && mPreviousFocusedActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
806 Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
807 if(keyboardFocusManager)
809 keyboardFocusManager.SetCurrentFocusActor(mPreviousFocusedActor);
814 // Perform animation.
815 StartTransitionAnimation(display);
818 Toolkit::Popup::DisplayState Popup::GetDisplayState() const
820 return mDisplayState;
823 void Popup::LayoutPopup()
825 mLayoutDirty = false;
827 /* When animating in, we want to respect the origin applied to Self().
828 * For example, if zooming, not only will the final result be anchored to the
829 * selected point, but the zoom will originate from this point also.
831 * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT :
840 mPopupContainer.SetProperty(Actor::Property::PARENT_ORIGIN, Self().GetCurrentProperty<Vector3>(Actor::Property::PARENT_ORIGIN));
841 mPopupContainer.SetProperty(Actor::Property::ANCHOR_POINT, Self().GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT));
843 // If there is only a title, use less padding.
846 if(!mContent && !mFooter)
848 mTitle.SetProperty(Actor::Property::PADDING, DEFAULT_TITLE_ONLY_PADDING);
852 mTitle.SetProperty(Actor::Property::PADDING, DEFAULT_TITLE_PADDING);
856 // Allow derived classes to perform any layout they may need to do.
859 // Update background visibility.
860 mPopupContainer.SetProperty(Actor::Property::VISIBLE, !(!mFooter && mPopupLayout.GetChildCount() == 0));
862 // Create / destroy / position the tail as needed.
865 // Setup any layout and initialisation required for the selected animation.
871 void Popup::LayoutTail()
873 // Removes the tail actor.
874 if(mTailImage && mTailImage.GetParent())
876 mTailImage.GetParent().Remove(mTailImage);
885 const Vector3& parentOrigin = GetTailPosition();
890 // depending on position of tail around ParentOrigin, a different tail image is used...
891 if(parentOrigin.y < Math::MACHINE_EPSILON_1)
893 image = mTailUpImage;
894 anchorPoint = AnchorPoint::BOTTOM_CENTER;
895 position.y = mBackgroundBorder.top;
897 else if(parentOrigin.y > (1.0f - Math::MACHINE_EPSILON_1))
899 image = mTailDownImage;
900 anchorPoint = AnchorPoint::TOP_CENTER;
901 position.y = -mBackgroundBorder.bottom;
903 else if(parentOrigin.x < Math::MACHINE_EPSILON_1)
905 image = mTailLeftImage;
906 anchorPoint = AnchorPoint::CENTER_RIGHT;
907 position.x = mBackgroundBorder.left;
909 else if(parentOrigin.x > (1.0f - Math::MACHINE_EPSILON_1))
911 image = mTailRightImage;
912 anchorPoint = AnchorPoint::CENTER_LEFT;
913 position.x = -mBackgroundBorder.right;
918 // Adds the tail actor.
919 mTailImage = Toolkit::ImageView::New(image);
920 mTailImage.SetProperty(Dali::Actor::Property::NAME, "tailImage");
921 mTailImage.SetProperty(Actor::Property::PARENT_ORIGIN, parentOrigin);
922 mTailImage.SetProperty(Actor::Property::ANCHOR_POINT, anchorPoint);
923 mTailImage.SetProperty(Actor::Property::POSITION, position);
925 if(mPopupBackgroundImage)
927 mPopupBackgroundImage.Add(mTailImage);
932 void Popup::SetContextualMode(Toolkit::Popup::ContextualMode mode)
934 mContextualMode = mode;
938 Toolkit::Popup::ContextualMode Popup::GetContextualMode() const
940 return mContextualMode;
943 Toolkit::Control Popup::CreateBacking()
945 Toolkit::Control backing = Control::New();
946 backing.SetProperty(Toolkit::Control::Property::BACKGROUND,
947 Property::Map().Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR).Add(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(mBackingColor.r, mBackingColor.g, mBackingColor.b, 1.0f)));
948 backing.SetProperty(Dali::Actor::Property::NAME, "popupBacking");
950 // Must always be positioned top-left of stage, regardless of parent.
951 backing.SetProperty(Actor::Property::INHERIT_POSITION, false);
953 // Always the full size of the stage.
954 backing.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
955 backing.SetProperty(Actor::Property::SIZE, Stage::GetCurrent().GetSize());
958 backing.SetProperty(Actor::Property::SENSITIVE, true);
960 // Default to being transparent.
961 backing.SetProperty(Actor::Property::COLOR_ALPHA, 0.0f);
962 backing.WheelEventSignal().Connect(this, &Popup::OnBackingWheelEvent);
966 Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
968 return mTouchedOutsideSignal;
971 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
973 return mShowingSignal;
976 Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
981 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
983 return mHidingSignal;
986 Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
988 return mHiddenSignal;
991 void Popup::SetTailVisibility(bool visible)
993 mTailVisible = visible;
997 const bool Popup::IsTailVisible() const
1002 void Popup::SetTailPosition(Vector3 position)
1004 mTailPosition = position;
1005 mLayoutDirty = true;
1008 const Vector3& Popup::GetTailPosition() const
1010 return mTailPosition;
1013 void Popup::SetAnimationDuration(float duration)
1015 mAnimationDuration = duration;
1016 mLayoutDirty = true;
1019 float Popup::GetAnimationDuration() const
1021 return mAnimationDuration;
1024 void Popup::SetAnimationMode(Toolkit::Popup::AnimationMode animationMode)
1026 mAnimationMode = animationMode;
1027 mLayoutDirty = true;
1030 Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const
1032 return mAnimationMode;
1035 void Popup::SetEntryAnimationData(const Property::Map& map)
1037 mEntryAnimationData.Clear();
1038 Scripting::NewAnimation(map, mEntryAnimationData);
1041 void Popup::SetExitAnimationData(const Property::Map& map)
1043 mExitAnimationData.Clear();
1044 Scripting::NewAnimation(map, mExitAnimationData);
1047 void Popup::UpdateBackgroundPositionAndSize()
1049 if(mPopupBackgroundImage)
1051 mPopupBackgroundImage.SetResizePolicy(ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS);
1052 mPopupBackgroundImage.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(mBackgroundBorder.left + mBackgroundBorder.right, mBackgroundBorder.top + mBackgroundBorder.bottom, 0.0f));
1054 // Adjust the position of the background so the transparent areas are set appropriately
1055 mPopupBackgroundImage.SetProperty(Actor::Property::POSITION, Vector2((mBackgroundBorder.right - mBackgroundBorder.left) * 0.5f, (mBackgroundBorder.bottom - mBackgroundBorder.top) * 0.5f));
1059 void Popup::SetAutoHideDelay(int delay)
1061 mAutoHideDelay = delay;
1064 int Popup::GetAutoHideDelay() const
1066 return mAutoHideDelay;
1069 void Popup::SetBackingEnabled(bool enabled)
1071 mBackingEnabled = enabled;
1072 mLayoutDirty = true;
1075 const bool Popup::IsBackingEnabled() const
1077 return mBackingEnabled;
1080 void Popup::SetBackingColor(Vector4 color)
1082 mBackingColor = color;
1083 mBacking.SetBackgroundColor(Vector4(color.r, color.g, color.b, 1.0f));
1084 mLayoutDirty = true;
1087 const Vector4& Popup::GetBackingColor() const
1089 return mBackingColor;
1092 void Popup::SetTailUpImage(std::string image)
1094 mTailUpImage = image;
1095 mLayoutDirty = true;
1099 const std::string& Popup::GetTailUpImage() const
1101 return mTailUpImage;
1104 void Popup::SetTailDownImage(std::string image)
1106 mTailDownImage = image;
1107 mLayoutDirty = true;
1111 const std::string& Popup::GetTailDownImage() const
1113 return mTailDownImage;
1116 void Popup::SetTailLeftImage(std::string image)
1118 mTailLeftImage = image;
1119 mLayoutDirty = true;
1123 const std::string& Popup::GetTailLeftImage() const
1125 return mTailLeftImage;
1128 void Popup::SetTailRightImage(std::string image)
1130 mTailRightImage = image;
1131 mLayoutDirty = true;
1135 const std::string& Popup::GetTailRightImage() const
1137 return mTailRightImage;
1140 void Popup::SetTouchTransparent(bool enabled)
1142 if(mTouchTransparent != enabled)
1144 mTouchTransparent = enabled;
1149 const bool Popup::IsTouchTransparent() const
1151 return mTouchTransparent;
1154 void Popup::SetProperty(BaseObject* object, Property::Index propertyIndex, const Property::Value& value)
1156 Toolkit::Popup popup = Toolkit::Popup::DownCast(Dali::BaseHandle(object));
1160 Popup& popupImpl(GetImpl(popup));
1162 switch(propertyIndex)
1164 case Toolkit::Popup::Property::TITLE:
1166 Property::Map valueMap;
1167 if(value.Get(valueMap))
1169 popupImpl.SetTitle(Scripting::NewActor(valueMap));
1173 case Toolkit::Popup::Property::CONTENT:
1175 Property::Map valueMap;
1176 if(value.Get(valueMap))
1178 popupImpl.SetContent(Scripting::NewActor(valueMap));
1182 case Toolkit::Popup::Property::FOOTER:
1184 Property::Map valueMap;
1185 if(value.Get(valueMap))
1187 popupImpl.SetFooter(Scripting::NewActor(valueMap));
1191 case Toolkit::Popup::Property::DISPLAY_STATE:
1193 std::string valueString;
1194 if(value.Get(valueString))
1196 Toolkit::Popup::DisplayState displayState(Toolkit::Popup::HIDDEN);
1197 if(Scripting::GetEnumeration<Toolkit::Popup::DisplayState>(valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState))
1199 popupImpl.SetDisplayState(displayState);
1204 case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1207 if(value.Get(valueBool))
1209 popupImpl.SetTouchTransparent(valueBool);
1213 case Toolkit::Popup::Property::TAIL_VISIBILITY:
1216 if(value.Get(valueBool))
1218 popupImpl.SetTailVisibility(valueBool);
1222 case Toolkit::Popup::Property::TAIL_POSITION:
1224 Vector3 valueVector3;
1225 if(value.Get(valueVector3))
1227 popupImpl.SetTailPosition(valueVector3);
1231 case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1233 std::string valueString;
1234 if(value.Get(valueString))
1236 Toolkit::Popup::ContextualMode contextualMode(Toolkit::Popup::BELOW);
1237 if(Scripting::GetEnumeration<Toolkit::Popup::ContextualMode>(valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode))
1239 popupImpl.SetContextualMode(contextualMode);
1244 case Toolkit::Popup::Property::ANIMATION_DURATION:
1247 if(value.Get(valueFloat))
1249 popupImpl.SetAnimationDuration(valueFloat);
1253 case Toolkit::Popup::Property::ANIMATION_MODE:
1255 std::string valueString;
1256 if(value.Get(valueString))
1258 Toolkit::Popup::AnimationMode animationMode(Toolkit::Popup::FADE);
1259 if(Scripting::GetEnumeration<Toolkit::Popup::AnimationMode>(valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode))
1261 popupImpl.SetAnimationMode(animationMode);
1266 case Toolkit::Popup::Property::ENTRY_ANIMATION:
1268 Property::Map valueMap;
1269 if(value.Get(valueMap))
1271 popupImpl.SetEntryAnimationData(valueMap);
1275 case Toolkit::Popup::Property::EXIT_ANIMATION:
1277 Property::Map valueMap;
1278 if(value.Get(valueMap))
1280 popupImpl.SetExitAnimationData(valueMap);
1284 case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1287 if(value.Get(valueInt))
1289 popupImpl.SetAutoHideDelay(valueInt);
1293 case Toolkit::Popup::Property::BACKING_ENABLED:
1296 if(value.Get(valueBool))
1298 popupImpl.SetBackingEnabled(valueBool);
1302 case Toolkit::Popup::Property::BACKING_COLOR:
1304 Vector4 valueVector4;
1305 if(value.Get(valueVector4))
1307 popupImpl.SetBackingColor(valueVector4);
1311 case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1313 std::string valueString;
1314 if(value.Get(valueString))
1316 Toolkit::ImageView actor = Toolkit::ImageView::New(valueString);
1317 popupImpl.SetPopupBackgroundImage(actor);
1321 case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1323 bool valueUpdated = false;
1325 Vector4 valueVector4;
1326 if(value.Get(popupImpl.mBackgroundBorder))
1328 valueUpdated = true;
1330 else if(value.Get(valueVector4))
1332 popupImpl.mBackgroundBorder.left = valueVector4.x;
1333 popupImpl.mBackgroundBorder.right = valueVector4.y;
1334 popupImpl.mBackgroundBorder.bottom = valueVector4.z;
1335 popupImpl.mBackgroundBorder.top = valueVector4.w;
1336 valueUpdated = true;
1341 popupImpl.LayoutTail(); // Update the tail if required
1342 popupImpl.UpdateBackgroundPositionAndSize(); // Update the background's size and position
1346 case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1348 std::string valueString;
1349 if(value.Get(valueString))
1351 popupImpl.SetTailUpImage(valueString);
1355 case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1357 std::string valueString;
1358 if(value.Get(valueString))
1360 popupImpl.SetTailDownImage(valueString);
1364 case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1366 std::string valueString;
1367 if(value.Get(valueString))
1369 popupImpl.SetTailLeftImage(valueString);
1373 case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1375 std::string valueString;
1376 if(value.Get(valueString))
1378 popupImpl.SetTailRightImage(valueString);
1386 Property::Value Popup::GetProperty(BaseObject* object, Property::Index propertyIndex)
1388 Property::Value value;
1390 Toolkit::Popup popup = Toolkit::Popup::DownCast(Dali::BaseHandle(object));
1394 Popup& popupImpl(GetImpl(popup));
1396 switch(propertyIndex)
1398 case Toolkit::Popup::Property::TITLE:
1401 Scripting::CreatePropertyMap(popupImpl.GetTitle(), map);
1405 case Toolkit::Popup::Property::CONTENT:
1408 Scripting::CreatePropertyMap(popupImpl.GetContent(), map);
1412 case Toolkit::Popup::Property::FOOTER:
1415 Scripting::CreatePropertyMap(popupImpl.GetFooter(), map);
1419 case Toolkit::Popup::Property::DISPLAY_STATE:
1421 value = Scripting::GetLinearEnumerationName<Toolkit::Popup::DisplayState>(popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount);
1424 case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
1426 value = popupImpl.IsTouchTransparent();
1429 case Toolkit::Popup::Property::TAIL_VISIBILITY:
1431 value = popupImpl.IsTailVisible();
1434 case Toolkit::Popup::Property::TAIL_POSITION:
1436 value = popupImpl.GetTailPosition();
1439 case Toolkit::Popup::Property::CONTEXTUAL_MODE:
1441 value = Scripting::GetLinearEnumerationName<Toolkit::Popup::ContextualMode>(popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount);
1444 case Toolkit::Popup::Property::ANIMATION_DURATION:
1446 value = popupImpl.GetAnimationDuration();
1449 case Toolkit::Popup::Property::ANIMATION_MODE:
1451 value = Scripting::GetLinearEnumerationName<Toolkit::Popup::AnimationMode>(popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount);
1454 case Toolkit::Popup::Property::ENTRY_ANIMATION:
1456 // Note: Cannot retrieve property map from animation.
1461 case Toolkit::Popup::Property::EXIT_ANIMATION:
1463 // Note: Cannot retrieve property map from animation.
1468 case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
1470 value = popupImpl.GetAutoHideDelay();
1473 case Toolkit::Popup::Property::BACKING_ENABLED:
1475 value = popupImpl.IsBackingEnabled();
1478 case Toolkit::Popup::Property::BACKING_COLOR:
1480 value = popupImpl.GetBackingColor();
1483 case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
1485 Toolkit::ImageView imageView = Toolkit::ImageView::DownCast(popupImpl.GetPopupBackgroundImage());
1488 value = imageView.GetProperty(Toolkit::ImageView::Property::IMAGE);
1492 case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
1494 value = popupImpl.mBackgroundBorder;
1497 case Toolkit::Popup::Property::TAIL_UP_IMAGE:
1499 value = popupImpl.GetTailUpImage();
1502 case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
1504 value = popupImpl.GetTailDownImage();
1507 case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
1509 value = popupImpl.GetTailLeftImage();
1512 case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
1514 value = popupImpl.GetTailRightImage();
1523 bool Popup::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
1525 Dali::BaseHandle handle(object);
1527 bool connected(true);
1528 Toolkit::Popup popup = Toolkit::Popup::DownCast(handle);
1530 if(0 == strcmp(signalName.c_str(), SIGNAL_TOUCHED_OUTSIDE))
1532 popup.OutsideTouchedSignal().Connect(tracker, functor);
1534 else if(0 == strcmp(signalName.c_str(), SIGNAL_SHOWING))
1536 popup.ShowingSignal().Connect(tracker, functor);
1538 else if(0 == strcmp(signalName.c_str(), SIGNAL_SHOWN))
1540 popup.ShownSignal().Connect(tracker, functor);
1542 else if(0 == strcmp(signalName.c_str(), SIGNAL_HIDING))
1544 popup.HidingSignal().Connect(tracker, functor);
1546 else if(0 == strcmp(signalName.c_str(), SIGNAL_HIDDEN))
1548 popup.HiddenSignal().Connect(tracker, functor);
1552 // signalName does not match any signal
1559 bool Popup::OnBackingTouched(Actor actor, const TouchEvent& touch)
1561 // Allow events to pass through if the backing isn't the hit-actor
1562 if((touch.GetHitActor(0) == actor) &&
1563 (touch.GetPointCount() > 0) &&
1564 (touch.GetState(0) == PointState::DOWN))
1566 // Guard against destruction during signal emission.
1567 Toolkit::Popup handle(GetOwner());
1569 mTouchedOutsideSignal.Emit();
1575 bool Popup::OnBackingWheelEvent(Actor actor, const WheelEvent& event)
1577 // Allow events to pass through if touch transparency is enabled.
1578 if(mTouchTransparent)
1586 bool Popup::OnDialogTouched(Actor actor, const TouchEvent& touch)
1588 // Only connecting this so the backing does not become the default hit-actor and inadvertently closes the popup
1592 void Popup::OnSceneConnection(int depth)
1594 mLayoutDirty = true;
1597 Control::OnSceneConnection(depth);
1600 void Popup::OnChildAdd(Actor& child)
1602 // Re-parent any children added by user to the body layer.
1603 if(mAlterAddedChild)
1609 mLayoutDirty = true;
1613 Control::OnChildAdd(child);
1616 void Popup::LayoutContext(const Vector2& size)
1618 // Do nothing if not in a contextual mode (or there is no parent context).
1619 Actor self = Self();
1620 Actor parent = self.GetParent();
1621 if((mContextualMode == Toolkit::Popup::NON_CONTEXTUAL) || !parent)
1626 mPopupContainer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
1627 // We always anchor to the CENTER, rather than a different anchor point for each contextual
1628 // mode to allow code-reuse of the bound checking code (for maintainability).
1629 mPopupContainer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
1631 // Setup with some pre-calculations for speed.
1632 Vector3 halfStageSize(Stage().GetCurrent().GetSize() / 2.0f);
1633 Vector3 parentPosition(parent.GetCurrentProperty<Vector3>(Actor::Property::POSITION));
1634 Vector2 halfSize(size / 2.0f);
1635 Vector2 halfParentSize(parent.GetRelayoutSize(Dimension::WIDTH) / 2.0f, parent.GetRelayoutSize(Dimension::HEIGHT) / 2.0f);
1636 Vector3 newPosition(Vector3::ZERO);
1638 // Perform different positioning based on the specified contextual layout mode.
1639 switch(mContextualMode)
1641 case Toolkit::Popup::BELOW:
1643 newPosition.x += halfSize.x - halfParentSize.x;
1644 newPosition.y += halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1647 case Toolkit::Popup::ABOVE:
1649 newPosition.x += halfSize.x - halfParentSize.x;
1650 newPosition.y -= halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
1653 case Toolkit::Popup::RIGHT:
1655 newPosition.x += halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1656 newPosition.y += halfSize.y - halfParentSize.y;
1659 case Toolkit::Popup::LEFT:
1661 newPosition.x -= halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
1662 newPosition.y += halfSize.y - halfParentSize.y;
1665 case Toolkit::Popup::NON_CONTEXTUAL:
1667 // Code won't reach here (caught earlier).
1672 // On-screen position checking.
1673 // Check new position is not too far right. If so, correct it.
1674 // Note: Check for right rather than left first, so if popup is too wide, the left check overrides
1675 // the right check and we at least see the left portion of the popup (as this is more useful).
1676 if(newPosition.x >= (halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x))
1678 newPosition.x = halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x;
1680 // Check new position is not too far left. If so, correct it.
1681 if(newPosition.x < halfSize.x - (parentPosition.x + halfStageSize.x) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x)
1683 newPosition.x = halfSize.x - (parentPosition.x + halfStageSize.x) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x; // - parentSize.x;
1685 // Check new position is not too far down. If so, correct it.
1686 if(newPosition.y >= (halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y))
1688 newPosition.y = halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1690 // Check new position is not too far up. If so, correct it.
1691 if(newPosition.y < halfSize.y - (parentPosition.y + halfStageSize.y) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y)
1693 newPosition.y = halfSize.y - (parentPosition.y + halfStageSize.y) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
1696 // Set the final position.
1697 mPopupContainer.SetProperty(Actor::Property::POSITION, newPosition);
1700 void Popup::OnRelayout(const Vector2& size, RelayoutContainer& container)
1702 Vector2 useSize(size);
1704 // Use the Popup layouts size, unless requested to use a fixed size.
1705 // In which case take the size set for the Popup itself.
1706 ResizePolicy::Type widthPolicy = Self().GetResizePolicy(Dimension::WIDTH);
1707 ResizePolicy::Type heightPolicy = Self().GetResizePolicy(Dimension::HEIGHT);
1709 // Width calculations:
1710 if(widthPolicy == ResizePolicy::USE_NATURAL_SIZE || widthPolicy == ResizePolicy::FIT_TO_CHILDREN)
1712 // If we using a child-based policy, take the size from the popup layout.
1713 mPopupLayout.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH);
1714 useSize.width = mPopupLayout.GetRelayoutSize(Dimension::WIDTH);
1716 mPopupLayout.SetFitWidth(0u);
1720 // If we using a parent-based policy, take the size from the popup object itself (self).
1721 mPopupLayout.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH);
1723 mPopupLayout.SetFixedWidth(0u, useSize.width);
1726 // Height calculations:
1727 // Title: Let the title be as high as it needs to be.
1728 mPopupLayout.SetFitHeight(0u);
1730 // Footer: Convert the footer's resize policy to a TableView row policy.
1733 ResizePolicy::Type footerHeightPolicy = mFooter.GetResizePolicy(Dimension::HEIGHT);
1734 if((footerHeightPolicy == ResizePolicy::USE_NATURAL_SIZE) ||
1735 (footerHeightPolicy == ResizePolicy::FIT_TO_CHILDREN))
1737 mPopupLayout.SetFitHeight(2u);
1739 else if(footerHeightPolicy == ResizePolicy::FIXED)
1741 mPopupLayout.SetFixedHeight(2u, mFooter.GetRelayoutSize(Dimension::HEIGHT));
1745 mPopupLayout.SetRelativeHeight(2u, 1.0f);
1750 mPopupLayout.SetFixedHeight(2u, 0.0f);
1753 // Popup contents: Adjust the tableview's policies based on the popup's policies.
1754 if(heightPolicy == ResizePolicy::USE_NATURAL_SIZE || heightPolicy == ResizePolicy::FIT_TO_CHILDREN)
1756 mPopupLayout.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
1758 // Let both the contents expand as necessary.
1759 mPopupLayout.SetFitHeight(1u);
1760 useSize.height = mPopupLayout.GetRelayoutSize(Dimension::HEIGHT);
1764 mPopupLayout.SetResizePolicy(heightPolicy, Dimension::HEIGHT);
1766 // Let the content expand to fill the remaining space.
1767 mPopupLayout.SetRelativeHeight(1u, 1.0f);
1768 mPopupLayout.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT);
1771 // Relayout the popup-layout to give it it's new size this frame.
1772 container.Add(mPopupLayout, useSize);
1776 container.Add(mContent, Vector2(mContent.GetRelayoutSize(Dimension::WIDTH), mContent.GetRelayoutSize(Dimension::HEIGHT)));
1779 // Perform contextual layout setup if required.
1780 // This is done each time in case the parent moves.
1781 // This will have no effect if no contextual mode is selected.
1782 LayoutContext(useSize);
1785 void Popup::OnSetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension)
1787 // To get the popup to emulate fit-to-children, we need to actually set use-natural-size.
1788 if((dimension & Dimension::HEIGHT) && (policy == ResizePolicy::FIT_TO_CHILDREN))
1790 Self().SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
1793 mLayoutDirty = true;
1797 Vector3 Popup::GetNaturalSize()
1799 return mPopupLayout.GetNaturalSize();
1802 float Popup::GetHeightForWidth(float width)
1804 return mPopupLayout.GetHeightForWidth(width);
1807 float Popup::GetWidthForHeight(float height)
1809 return mPopupLayout.GetWidthForHeight(height);
1812 bool Popup::OnKeyEvent(const KeyEvent& event)
1814 // Allow events to pass through if touch transparency is enabled.
1815 if(mTouchTransparent)
1820 bool consumed = false;
1822 if(event.GetState() == KeyEvent::DOWN)
1824 if(event.GetKeyCode() == Dali::DALI_KEY_ESCAPE || event.GetKeyCode() == Dali::DALI_KEY_BACK)
1826 SetDisplayState(Toolkit::Popup::HIDDEN);
1834 void Popup::AddFocusableChildrenRecursive(Actor parent, std::vector<Actor>& focusableActors)
1838 Toolkit::Control control = Toolkit::Control::DownCast(parent);
1839 bool layoutControl = control && GetImplementation(control).IsKeyboardNavigationSupported();
1841 if(parent.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) || layoutControl)
1843 focusableActors.push_back(parent);
1847 for(unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i)
1849 Actor child(parent.GetChildAt(i));
1850 AddFocusableChildrenRecursive(child, focusableActors);
1857 void Popup::AddFocusableChildren(Actor parent, std::vector<Actor>& focusableActors)
1861 Toolkit::Control control = Toolkit::Control::DownCast(parent);
1862 if(!GetImplementation(control).IsKeyboardNavigationSupported())
1864 for(unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i)
1866 Actor child(parent.GetChildAt(i));
1867 AddFocusableChildrenRecursive(child, focusableActors);
1872 focusableActors.push_back(parent);
1877 Actor Popup::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
1879 std::string currentStr;
1880 if(currentFocusedActor)
1882 currentStr = currentFocusedActor.GetProperty<std::string>(Dali::Actor::Property::NAME);
1885 Actor nextFocusableActor(currentFocusedActor);
1886 Actor currentFocusGroup;
1887 if(currentFocusedActor)
1889 currentFocusGroup = KeyboardFocusManager::Get().GetFocusGroup(currentFocusedActor);
1892 // TODO: Needs to be optimised
1893 // The following statement checks that if we have a current focused actor, then the current focus group is not the popup content or footer.
1894 // This is to detect if the focus is currently outside the popup, and if so, move it inside.
1895 if(!currentFocusedActor ||
1896 (currentFocusedActor && ((!mContent || (currentFocusGroup != mContent)) && (!mFooter || (currentFocusGroup != mFooter)))))
1898 // The current focused actor is not within popup.
1899 if(mContent && mContent.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
1901 // If the content is focusable, move the focus to the content.
1902 nextFocusableActor = mContent;
1904 else if(mFooter && mFooter.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
1906 // If the footer is focusable, move the focus to the footer.
1907 nextFocusableActor = mFooter;
1912 // Rebuild the focus chain because controls or content can be added or removed dynamically
1913 std::vector<Actor> focusableActors;
1915 AddFocusableChildren(mContent, focusableActors);
1916 AddFocusableChildren(mFooter, focusableActors);
1918 std::vector<Actor>::iterator endIterator = focusableActors.end();
1919 std::vector<Actor>::iterator currentIterator = focusableActors.begin();
1920 for(std::vector<Actor>::iterator iterator = focusableActors.begin(); iterator != endIterator; ++iterator)
1922 if(currentFocusedActor == *iterator)
1924 currentIterator = iterator;
1928 if(currentIterator != endIterator)
1932 case Toolkit::Control::KeyboardFocus::LEFT:
1934 if(currentIterator == focusableActors.begin())
1936 nextFocusableActor = *(endIterator - 1);
1940 nextFocusableActor = *(currentIterator - 1);
1944 case Toolkit::Control::KeyboardFocus::RIGHT:
1946 if(currentIterator == endIterator - 1)
1948 nextFocusableActor = *(focusableActors.begin());
1952 nextFocusableActor = *(currentIterator + 1);
1957 case Toolkit::Control::KeyboardFocus::UP:
1959 nextFocusableActor = *(focusableActors.begin());
1963 case Toolkit::Control::KeyboardFocus::DOWN:
1965 nextFocusableActor = *(endIterator - 1);
1975 if(!nextFocusableActor)
1977 DALI_LOG_WARNING("Can not decide next focusable actor\n");
1982 return nextFocusableActor;
1985 void Popup::SetupTouch()
1987 if(!mTouchTransparent)
1989 // Connect all the signals and set us up to consume all touch events
1990 mBacking.TouchedSignal().Connect(this, &Popup::OnBackingTouched);
1991 mPopupBackgroundImage.TouchedSignal().Connect(this, &Popup::OnDialogTouched);
1992 mPopupLayout.TouchedSignal().Connect(this, &Popup::OnDialogTouched);
1993 mLayer.SetProperty(Layer::Property::CONSUMES_TOUCH, true);
1997 // We are touch transparent so disconnect all signals and ensure our layer does not consumed all touch events
1998 mBacking.TouchedSignal().Disconnect(this, &Popup::OnBackingTouched);
1999 mPopupBackgroundImage.TouchedSignal().Disconnect(this, &Popup::OnDialogTouched);
2000 mPopupLayout.TouchedSignal().Disconnect(this, &Popup::OnDialogTouched);
2001 mLayer.SetProperty(Layer::Property::CONSUMES_TOUCH, false);
2005 std::string Popup::AccessibleImpl::GetNameRaw()
2007 auto popup = Toolkit::Popup::DownCast(Self());
2009 Actor popupTitle = popup.GetTitle();
2012 std::string titleText = popupTitle.GetProperty<std::string>(Toolkit::TextLabel::Property::TEXT);
2017 Actor popupContent = popup.GetContent();
2020 std::string contentText = popupContent.GetProperty<std::string>(Toolkit::TextLabel::Property::TEXT);
2021 title = contentText;
2027 Dali::Accessibility::States Popup::AccessibleImpl::CalculateStates()
2029 auto states = DevelControl::AccessibleImpl::CalculateStates();
2030 auto popup = Toolkit::Popup::DownCast(Self());
2031 auto displayState = popup.GetProperty<std::string>(Toolkit::Popup::Property::DISPLAY_STATE);
2033 states[Dali::Accessibility::State::SHOWING] = (displayState == "SHOWN" || displayState == "SHOWING");
2038 } // namespace Internal
2040 } // namespace Toolkit