2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/public-api/controls/control-impl.h>
22 #include <cstring> // for strcmp
26 #include <dali/public-api/animation/constraint.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/public-api/object/type-info.h>
29 #include <dali/public-api/size-negotiation/relayout-container.h>
30 #include <dali/public-api/common/stage.h>
31 #include <dali/devel-api/scripting/scripting.h>
32 #include <dali/integration-api/debug.h>
33 #include <dali/devel-api/actors/actor-devel.h>
34 #include <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
37 #include <dali-toolkit/public-api/align-enumerations.h>
38 #include <dali-toolkit/public-api/controls/control.h>
39 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
40 #include <dali-toolkit/public-api/styling/style-manager.h>
41 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
42 #include <dali-toolkit/public-api/visuals/visual-properties.h>
43 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
44 #include <dali-toolkit/devel-api/controls/control-devel.h>
45 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
46 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
47 #include <dali-toolkit/internal/styling/style-manager-impl.h>
48 #include <dali-toolkit/internal/visuals/color/color-visual.h>
49 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
50 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
51 #include <dali/devel-api/actors/actor-devel.h>
65 #if defined(DEBUG_ENABLED)
66 Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
70 * @brief Replace the background visual if it's a color visual with the renderIfTransparent property set as required.
71 * @param[in] controlImpl The control implementation
72 * @param[in] renderIfTransaparent Whether we should render if the color is transparent
74 void ChangeBackgroundColorVisual( Control& controlImpl, bool renderIfTransparent )
76 Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
78 Toolkit::Visual::Base backgroundVisual = controlDataImpl.GetVisual( Toolkit::Control::Property::BACKGROUND );
79 if( backgroundVisual )
82 backgroundVisual.CreatePropertyMap( map );
83 Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE );
84 if( typeValue && typeValue->Get< int >() == Toolkit::Visual::COLOR )
86 // Only change it if it's a color visual
87 map[ Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = renderIfTransparent;
88 controlImpl.SetBackground( map );
94 * @brief Creates a clipping renderer if required.
95 * (EG. If no renders exist and clipping is enabled).
96 * @param[in] controlImpl The control implementation.
98 void CreateClippingRenderer( Control& controlImpl )
100 // We want to add a transparent background if we do not have one for clipping.
101 Actor self( controlImpl.Self() );
102 int clippingMode = ClippingMode::DISABLED;
103 if( self.GetProperty( Actor::Property::CLIPPING_MODE ).Get( clippingMode ) )
105 switch( clippingMode )
107 case ClippingMode::CLIP_CHILDREN:
109 if( self.GetRendererCount() == 0u )
111 Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
112 if( controlDataImpl.mVisuals.Empty() )
114 controlImpl.SetBackgroundColor( Color::TRANSPARENT );
118 // We have visuals, check if we've set the background and re-create it to
119 // render even if transparent (only if it's a color visual)
120 ChangeBackgroundColorVisual( controlImpl, true );
126 case ClippingMode::DISABLED:
127 case ClippingMode::CLIP_TO_BOUNDING_BOX:
129 // If we have a background visual, check if it's a color visual and remove the render if transparent flag
130 ChangeBackgroundColorVisual( controlImpl, false );
138 * @brief Sets Control::Property::BACKGROUND visual
139 * @param[in] controlImpl The control implementation
140 * @param[in] visual The control background visual
141 * @param[in] size The current size
143 void SetBackgroundVisual( Control::Impl& controlImpl, Toolkit::Visual::Base& visual, const Vector2& size )
145 Property::Map transformMap = Property::Map();
147 Vector2 newSize( 0.f, 0.f );
148 newSize.width = size.width + ( controlImpl.mPadding.start + controlImpl.mPadding.end );
149 newSize.height = size.height + ( controlImpl.mPadding.top + controlImpl.mPadding.bottom );
151 if( ( controlImpl.mMargin.start != 0 ) ||
152 ( controlImpl.mMargin.end != 0 ) ||
153 ( controlImpl.mMargin.top != 0 ) ||
154 ( controlImpl.mMargin.bottom != 0 ) )
156 transformMap.Add( Toolkit::Visual::Transform::Property::SIZE, newSize )
157 .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
158 .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( controlImpl.mMargin.start, controlImpl.mMargin.top ) )
159 .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
160 .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
161 .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
163 else if( ( controlImpl.mPadding.start != 0 ) ||
164 ( controlImpl.mPadding.end != 0 ) ||
165 ( controlImpl.mPadding.top != 0 ) ||
166 ( controlImpl.mPadding.bottom != 0 ) )
168 transformMap.Add( Toolkit::Visual::Transform::Property::SIZE, newSize )
169 .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
170 .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
171 .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
174 visual.SetTransformAndSize( transformMap, newSize ); // Send an empty map as we do not want to modify the visual's set transform
177 } // unnamed namespace
180 Toolkit::Control Control::New()
182 // Create the implementation, temporarily owned on stack
183 IntrusivePtr<Control> controlImpl = new Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) );
185 // Pass ownership to handle
186 Toolkit::Control handle( *controlImpl );
188 // Second-phase init of the implementation
189 // This can only be done after the CustomActor connection has been made...
190 controlImpl->Initialize();
195 void Control::SetStyleName( const std::string& styleName )
197 if( styleName != mImpl->mStyleName )
199 mImpl->mStyleName = styleName;
201 // Apply new style, if stylemanager is available
202 Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
205 GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
210 const std::string& Control::GetStyleName() const
212 return mImpl->mStyleName;
215 void Control::SetBackgroundColor( const Vector4& color )
217 mImpl->mBackgroundColor = color;
219 map[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::COLOR;
220 map[ Toolkit::ColorVisual::Property::MIX_COLOR ] = color;
222 int clippingMode = ClippingMode::DISABLED;
223 if( ( Self().GetProperty( Actor::Property::CLIPPING_MODE ).Get( clippingMode ) ) &&
224 ( clippingMode == ClippingMode::CLIP_CHILDREN ) )
226 // If clipping-mode is set to CLIP_CHILDREN, then force visual to add the render even if transparent
227 map[ Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = true;
230 SetBackground( map );
233 Vector4 Control::GetBackgroundColor() const
235 return mImpl->mBackgroundColor;
238 void Control::SetBackground( const Property::Map& map )
240 Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( map );
241 visual.SetName("background");
244 mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND );
246 // Trigger a size negotiation request that may be needed by the new visual to relayout its contents.
251 void Control::SetBackgroundImage( Image image )
253 Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( image );
256 mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND );
260 void Control::ClearBackground()
262 mImpl->UnregisterVisual( Toolkit::Control::Property::BACKGROUND );
263 mImpl->mBackgroundColor = Color::TRANSPARENT;
265 // Trigger a size negotiation request that may be needed when unregistering a visual.
269 void Control::EnableGestureDetection(Gesture::Type type)
271 if ( (type & Gesture::Pinch) && !mImpl->mPinchGestureDetector )
273 mImpl->mPinchGestureDetector = PinchGestureDetector::New();
274 mImpl->mPinchGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PinchDetected);
275 mImpl->mPinchGestureDetector.Attach(Self());
278 if ( (type & Gesture::Pan) && !mImpl->mPanGestureDetector )
280 mImpl->mPanGestureDetector = PanGestureDetector::New();
281 mImpl->mPanGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PanDetected);
282 mImpl->mPanGestureDetector.Attach(Self());
285 if ( (type & Gesture::Tap) && !mImpl->mTapGestureDetector )
287 mImpl->mTapGestureDetector = TapGestureDetector::New();
288 mImpl->mTapGestureDetector.DetectedSignal().Connect(mImpl, &Impl::TapDetected);
289 mImpl->mTapGestureDetector.Attach(Self());
292 if ( (type & Gesture::LongPress) && !mImpl->mLongPressGestureDetector )
294 mImpl->mLongPressGestureDetector = LongPressGestureDetector::New();
295 mImpl->mLongPressGestureDetector.DetectedSignal().Connect(mImpl, &Impl::LongPressDetected);
296 mImpl->mLongPressGestureDetector.Attach(Self());
300 void Control::DisableGestureDetection(Gesture::Type type)
302 if ( (type & Gesture::Pinch) && mImpl->mPinchGestureDetector )
304 mImpl->mPinchGestureDetector.Detach(Self());
305 mImpl->mPinchGestureDetector.Reset();
308 if ( (type & Gesture::Pan) && mImpl->mPanGestureDetector )
310 mImpl->mPanGestureDetector.Detach(Self());
311 mImpl->mPanGestureDetector.Reset();
314 if ( (type & Gesture::Tap) && mImpl->mTapGestureDetector )
316 mImpl->mTapGestureDetector.Detach(Self());
317 mImpl->mTapGestureDetector.Reset();
320 if ( (type & Gesture::LongPress) && mImpl->mLongPressGestureDetector)
322 mImpl->mLongPressGestureDetector.Detach(Self());
323 mImpl->mLongPressGestureDetector.Reset();
327 PinchGestureDetector Control::GetPinchGestureDetector() const
329 return mImpl->mPinchGestureDetector;
332 PanGestureDetector Control::GetPanGestureDetector() const
334 return mImpl->mPanGestureDetector;
337 TapGestureDetector Control::GetTapGestureDetector() const
339 return mImpl->mTapGestureDetector;
342 LongPressGestureDetector Control::GetLongPressGestureDetector() const
344 return mImpl->mLongPressGestureDetector;
347 void Control::SetKeyboardNavigationSupport(bool isSupported)
349 mImpl->mIsKeyboardNavigationSupported = isSupported;
352 bool Control::IsKeyboardNavigationSupported()
354 return mImpl->mIsKeyboardNavigationSupported;
357 void Control::SetKeyInputFocus()
359 if( Self().OnStage() )
361 Toolkit::KeyInputFocusManager::Get().SetFocus(Toolkit::Control::DownCast(Self()));
365 bool Control::HasKeyInputFocus()
368 if( Self().OnStage() )
370 Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
371 if( Self() == control )
379 void Control::ClearKeyInputFocus()
381 if( Self().OnStage() )
383 Toolkit::KeyInputFocusManager::Get().RemoveFocus(Toolkit::Control::DownCast(Self()));
387 void Control::SetAsKeyboardFocusGroup(bool isFocusGroup)
389 mImpl->mIsKeyboardFocusGroup = isFocusGroup;
391 // The following line will be removed when the deprecated API in KeyboardFocusManager is deleted
392 Toolkit::KeyboardFocusManager::Get().SetAsFocusGroup(Self(), isFocusGroup);
395 bool Control::IsKeyboardFocusGroup()
397 return Toolkit::KeyboardFocusManager::Get().IsFocusGroup(Self());
400 void Control::AccessibilityActivate()
402 // Inform deriving classes
403 OnAccessibilityActivated();
406 void Control::KeyboardEnter()
408 // Inform deriving classes
412 bool Control::OnAccessibilityActivated()
414 return false; // Accessibility activation is not handled by default
417 bool Control::OnKeyboardEnter()
419 return false; // Keyboard enter is not handled by default
422 bool Control::OnAccessibilityPan(PanGesture gesture)
424 return false; // Accessibility pan gesture is not handled by default
427 bool Control::OnAccessibilityTouch(const TouchEvent& touchEvent)
429 return false; // Accessibility touch event is not handled by default
432 bool Control::OnAccessibilityValueChange(bool isIncrease)
434 return false; // Accessibility value change action is not handled by default
437 bool Control::OnAccessibilityZoom()
439 return false; // Accessibility zoom action is not handled by default
442 Actor Control::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
447 void Control::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
451 Toolkit::Control::KeyEventSignalType& Control::KeyEventSignal()
453 return mImpl->mKeyEventSignal;
456 Toolkit::Control::KeyInputFocusSignalType& Control::KeyInputFocusGainedSignal()
458 return mImpl->mKeyInputFocusGainedSignal;
461 Toolkit::Control::KeyInputFocusSignalType& Control::KeyInputFocusLostSignal()
463 return mImpl->mKeyInputFocusLostSignal;
466 bool Control::EmitKeyEventSignal( const KeyEvent& event )
468 // Guard against destruction during signal emission
469 Dali::Toolkit::Control handle( GetOwner() );
471 bool consumed = false;
473 // signals are allocated dynamically when someone connects
474 if ( !mImpl->mKeyEventSignal.Empty() )
476 consumed = mImpl->mKeyEventSignal.Emit( handle, event );
481 // Notification for derived classes
482 consumed = OnKeyEvent(event);
488 Control::Control( ControlBehaviour behaviourFlags )
489 : CustomActorImpl( static_cast< ActorFlags >( behaviourFlags ) ),
490 mImpl(new Impl(*this))
492 mImpl->mFlags = behaviourFlags;
493 SetAccessibilityConstructor(
494 []( Dali::Actor actor )
495 -> std::unique_ptr< Dali::Accessibility::Accessible > {
496 return std::unique_ptr< Dali::Accessibility::Accessible >(
497 new AccessibleImpl( actor,
498 Dali::Accessibility::Role::RedundantObject ) );
507 void Control::Initialize()
509 // Call deriving classes so initialised before styling is applied to them.
512 if( (mImpl->mFlags & REQUIRES_STYLE_CHANGE_SIGNALS) ||
513 !(mImpl->mFlags & DISABLE_STYLE_CHANGE_SIGNALS) )
515 Toolkit::StyleManager styleManager = StyleManager::Get();
517 // if stylemanager is available
520 StyleManager& styleManagerImpl = GetImpl( styleManager );
522 // Register for style changes
523 styleManagerImpl.ControlStyleChangeSignal().Connect( this, &Control::OnStyleChange );
525 // Apply the current style
526 styleManagerImpl.ApplyThemeStyleAtInit( Toolkit::Control( GetOwner() ) );
530 if( mImpl->mFlags & REQUIRES_KEYBOARD_NAVIGATION_SUPPORT )
532 SetKeyboardNavigationSupport( true );
536 Self().GetTypeInfo( type );
537 auto type_name = type.GetName();
538 AccessibilitySetAttribute( "t", type_name );
541 void Control::OnInitialize()
545 void Control::OnControlChildAdd( Actor& child )
549 void Control::OnControlChildRemove( Actor& child )
553 void Control::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
555 // By default the control is only interested in theme (not font) changes
556 if( styleManager && change == StyleChange::THEME_CHANGE )
558 GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
563 void Control::OnPinch(const PinchGesture& pinch)
565 if( !( mImpl->mStartingPinchScale ) )
568 mImpl->mStartingPinchScale = new Vector3;
571 if( pinch.state == Gesture::Started )
573 *( mImpl->mStartingPinchScale ) = Self().GetCurrentScale();
576 Self().SetScale( *( mImpl->mStartingPinchScale ) * pinch.scale );
579 void Control::OnPan( const PanGesture& pan )
583 void Control::OnTap(const TapGesture& tap)
587 void Control::OnLongPress( const LongPressGesture& longPress )
591 void Control::EmitKeyInputFocusSignal( bool focusGained )
593 Dali::Toolkit::Control handle( GetOwner() );
597 // signals are allocated dynamically when someone connects
598 if ( !mImpl->mKeyInputFocusGainedSignal.Empty() )
600 mImpl->mKeyInputFocusGainedSignal.Emit( handle );
605 // signals are allocated dynamically when someone connects
606 if ( !mImpl->mKeyInputFocusLostSignal.Empty() )
608 mImpl->mKeyInputFocusLostSignal.Emit( handle );
613 void Control::OnStageConnection( int depth )
615 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageConnection number of registered visuals(%d)\n", mImpl->mVisuals.Size() );
617 Actor self( Self() );
619 for(RegisteredVisualContainer::Iterator iter = mImpl->mVisuals.Begin(); iter!= mImpl->mVisuals.End(); iter++)
621 // Check whether the visual is empty and enabled
622 if( (*iter)->visual && (*iter)->enabled )
624 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageConnection Setting visual(%d) on stage\n", (*iter)->index );
625 Toolkit::GetImplementation((*iter)->visual).SetOnStage( self );
629 // The clipping renderer is only created if required.
630 CreateClippingRenderer( *this );
633 void Control::OnStageDisconnection()
635 mImpl->OnStageDisconnection();
638 void Control::OnKeyInputFocusGained()
640 EmitKeyInputFocusSignal( true );
643 void Control::OnKeyInputFocusLost()
645 EmitKeyInputFocusSignal( false );
648 void Control::OnChildAdd(Actor& child)
650 // Notify derived classes.
651 OnControlChildAdd( child );
654 void Control::OnChildRemove(Actor& child)
656 // Notify derived classes.
657 OnControlChildRemove( child );
660 void Control::OnPropertySet( Property::Index index, Property::Value propertyValue )
662 // If the clipping mode has been set, we may need to create a renderer.
663 // Only do this if we are already on-stage as the OnStageConnection will handle the off-stage clipping controls.
664 if( ( index == Actor::Property::CLIPPING_MODE ) && Self().OnStage() )
666 // Note: This method will handle whether creation of the renderer is required.
667 CreateClippingRenderer( *this );
671 void Control::OnSizeSet(const Vector3& targetSize)
673 Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
676 Vector2 size( targetSize );
677 SetBackgroundVisual( *mImpl, visual, size );
682 void Control::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
684 // @todo size negotiate background to new size, animate as well?
687 bool Control::OnTouchEvent(const TouchEvent& event)
689 return false; // Do not consume
692 bool Control::OnHoverEvent(const HoverEvent& event)
694 return false; // Do not consume
697 bool Control::OnKeyEvent(const KeyEvent& event)
699 return false; // Do not consume
702 bool Control::OnWheelEvent(const WheelEvent& event)
704 return false; // Do not consume
707 void Control::OnRelayout( const Vector2& size, RelayoutContainer& container )
709 for( unsigned int i = 0, numChildren = Self().GetChildCount(); i < numChildren; ++i )
711 Actor child = Self().GetChildAt( i );
712 Vector2 newChildSize( size );
714 // When set the padding or margin on the control, child should be resized and repositioned.
715 if( ( mImpl->mPadding.start != 0 ) || ( mImpl->mPadding.end != 0 ) || ( mImpl->mPadding.top != 0 ) || ( mImpl->mPadding.bottom != 0 ) ||
716 ( mImpl->mMargin.start != 0 ) || ( mImpl->mMargin.end != 0 ) || ( mImpl->mMargin.top != 0 ) || ( mImpl->mMargin.bottom != 0 ) )
718 Extents padding = mImpl->mPadding;
720 Dali::CustomActor ownerActor(GetOwner());
721 Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( ownerActor.GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
723 if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
725 std::swap( padding.start, padding.end );
728 newChildSize.width = size.width - ( padding.start + padding.end );
729 newChildSize.height = size.height - ( padding.top + padding.bottom );
731 // Cannot use childs Position property as it can already have padding and margin applied on it,
732 // so we end up cumulatively applying them over and over again.
733 Vector2 childOffset( 0.f, 0.f );
734 childOffset.x += ( mImpl->mMargin.start + padding.start );
735 childOffset.y += ( mImpl->mMargin.top + padding.top );
737 child.SetPosition( childOffset.x, childOffset.y );
740 container.Add( child, newChildSize );
743 Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
746 SetBackgroundVisual( *mImpl, visual, size );
750 void Control::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
754 Vector3 Control::GetNaturalSize()
756 Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
760 visual.GetNaturalSize( naturalSize );
761 naturalSize.width += ( mImpl->mPadding.start + mImpl->mPadding.end );
762 naturalSize.height += ( mImpl->mPadding.top + mImpl->mPadding.bottom );
763 return Vector3( naturalSize );
765 return Vector3::ZERO;
768 float Control::CalculateChildSize( const Dali::Actor& child, Dimension::Type dimension )
770 return CalculateChildSizeBase( child, dimension );
773 float Control::GetHeightForWidth( float width )
775 return GetHeightForWidthBase( width );
778 float Control::GetWidthForHeight( float height )
780 return GetWidthForHeightBase( height );
783 bool Control::RelayoutDependentOnChildren( Dimension::Type dimension )
785 return RelayoutDependentOnChildrenBase( dimension );
788 void Control::OnCalculateRelayoutSize( Dimension::Type dimension )
792 void Control::OnLayoutNegotiated( float size, Dimension::Type dimension )
796 void Control::SignalConnected( SlotObserver* slotObserver, CallbackBase* callback )
798 mImpl->SignalConnected( slotObserver, callback );
801 void Control::SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback )
803 mImpl->SignalDisconnected( slotObserver, callback );
806 Control& GetImplementation( Dali::Toolkit::Control& handle )
808 CustomActorImpl& customInterface = handle.GetImplementation();
809 // downcast to control
810 Control& impl = dynamic_cast< Internal::Control& >( customInterface );
814 const Control& GetImplementation( const Dali::Toolkit::Control& handle )
816 const CustomActorImpl& customInterface = handle.GetImplementation();
817 // downcast to control
818 const Control& impl = dynamic_cast< const Internal::Control& >( customInterface );
822 Toolkit::Control::AccessibilityActivateSignalType &Control::AccessibilityActivateSignal()
824 return mImpl->mAccessibilityActivateSignal;
827 Dali::Accessibility::Accessible *Control::GetAccessibilityObject(Dali::Actor actor)
831 auto q = Dali::Toolkit::Control::DownCast( actor );
834 auto q2 = static_cast< Internal::Control* >( &q.GetImplementation() );
835 if( !q2->mImpl->accessibilityObject )
836 q2->mImpl->accessibilityObject =
837 q2->mImpl->accessibilityConstructor( actor );
838 return q2->mImpl->accessibilityObject.get();
844 void Control::SetAccessibilityConstructor(
845 std::function< std::unique_ptr< Dali::Accessibility::Accessible >( Dali::Actor ) >
848 mImpl->accessibilityConstructor = constructor;
851 std::string Control::AccessibleImpl::GetName() { return self.GetName(); }
852 std::string Control::AccessibleImpl::GetDescription() { return ""; }
853 Dali::Accessibility::Accessible* Control::AccessibleImpl::GetParent()
855 return Dali::Accessibility::Accessible::Get( self.GetParent() );
857 size_t Control::AccessibleImpl::GetChildCount() { return self.GetChildCount(); }
858 Dali::Accessibility::Accessible*
859 Control::AccessibleImpl::GetChildAtIndex( size_t index )
861 return Dali::Accessibility::Accessible::Get(
862 self.GetChildAt( static_cast< unsigned int >( index ) ) );
864 size_t Control::AccessibleImpl::GetIndexInParent()
867 auto parent = s.GetParent();
869 throw Dali::Accessibility::AccessibleError(
870 "can't call GetIndexInParent on object '" + GetAddress().ToString() +
871 "' without parent" );
872 auto count = parent.GetChildCount();
873 for( auto i = 0u; i < count; ++i )
875 auto c = parent.GetChildAt( i );
879 throw Dali::Accessibility::AccessibleError(
880 "object '" + GetAddress().ToString() + "' isn't child of it's parent" );
883 Dali::Accessibility::Role Control::AccessibleImpl::GetRole() { return role; }
885 void Control::AccessibilitySetAttribute( const std::string& key,
886 const std::string value )
888 return mImpl->AccessibilitySetAttribute( key, value );
891 std::string Control::AccessibilityGetAttribute( const std::string& key )
893 return mImpl->AccessibilityGetAttribute( key );
896 void Control::AccessibilityEraseAttribute( std::string& key )
898 return mImpl->AccessibilityEraseAttribute( key );
901 bool Control::AccessibleImpl::CalculateIsVisible() const
903 auto parent = self.GetParent();
906 auto p = Accessible::Get( parent );
907 auto p2 = dynamic_cast< AccessibleImpl* >( p );
908 if( p2 && !p2->CalculateIsVisible() )
911 auto stage = Stage::GetCurrent();
912 if( stage && self.OnStage() )
915 self.GetProperty( Dali::DevelActor::Property::SCREEN_POSITION )
917 auto size = stage.GetSize();
918 if( position.x >= 0 && position.x < size.x )
924 Dali::Accessibility::States Control::AccessibleImpl::CalculateStates()
926 Dali::Accessibility::States s;
927 s[Dali::Accessibility::State::Highlightable] = true;
928 s[Dali::Accessibility::State::Enabled] = true;
929 s[Dali::Accessibility::State::Sensitive] = true;
930 if( self.IsVisible() )
931 s[Dali::Accessibility::State::Showing] = true;
934 s[Dali::Accessibility::State::Modal] = true;
936 s[Dali::Accessibility::State::Visible] = CalculateIsVisible();
937 auto am = Toolkit::AccessibilityManager::Get();
938 if( self == am.GetCurrentFocusActor() )
939 s[Dali::Accessibility::State::Highlighted] = true;
943 Dali::Accessibility::States Control::AccessibleImpl::GetStates()
945 return CalculateStates();
948 Dali::Accessibility::Attributes Control::AccessibleImpl::GetAttributes()
950 std::unordered_map< std::string, std::string > attribute_map;
951 auto q = Dali::Toolkit::Control::DownCast( self );
953 q.GetProperty( Dali::Toolkit::Control::Property::ACCESSIBILITY_ATTRIBUTES );
958 auto map_size = z->Count();
960 for( unsigned int i = 0; i < map_size; i++ )
962 auto map_key = z->GetKeyAt( i );
963 if( map_key.type == Property::Key::STRING )
965 std::string map_value;
966 if( z->GetValue( i ).Get( map_value ) )
968 attribute_map.emplace( std::move( map_key.stringKey ),
969 std::move( map_value ) );
975 return attribute_map;
978 Dali::Accessibility::ComponentLayer Control::AccessibleImpl::GetLayer()
980 return Dali::Accessibility::ComponentLayer::Window;
983 Dali::Accessibility::Rectangle
984 Control::AccessibleImpl::GetExtents( Dali::Accessibility::CoordType ctype )
986 Vector2 screenPosition =
987 self.GetProperty( Dali::DevelActor::Property::SCREEN_POSITION )
989 Vector3 size = self.GetCurrentSize() * self.GetCurrentWorldScale();
990 bool positionUsesAnchorPoint =
991 self.GetProperty( Dali::DevelActor::Property::POSITION_USES_ANCHOR_POINT )
993 Vector3 anchorPointOffSet =
994 size * ( positionUsesAnchorPoint ? self.GetCurrentAnchorPoint()
995 : AnchorPoint::TOP_LEFT );
996 Vector2 position = Vector2( screenPosition.x - anchorPointOffSet.x,
997 screenPosition.y - anchorPointOffSet.y );
999 return {Dali::Accessibility::Point( (int)position.x, (int)position.y ),
1000 Dali::Accessibility::Size( (int)size.x, (int)size.y )};
1003 int Control::AccessibleImpl::GetMdiZOrder() { return 0; }
1004 bool Control::AccessibleImpl::GrabFocus() { return false; }
1005 double Control::AccessibleImpl::GetAlpha() { return 0; }
1006 bool Control::AccessibleImpl::SetExtents( Dali::Accessibility::Rectangle rect,
1007 Dali::Accessibility::CoordType ctype )
1011 bool Control::AccessibleImpl::GrabHighlight()
1013 auto am = Toolkit::AccessibilityManager::Get();
1014 auto old = am.GetCurrentFocusActor();
1019 auto c = dynamic_cast< Dali::Accessibility::Component* >(
1020 GetAccessibilityObject( old ) );
1022 c->ClearHighlight();
1024 return am.SetCurrentFocusActor( self );
1028 bool Control::AccessibleImpl::ClearHighlight()
1030 auto am = Toolkit::AccessibilityManager::Get();
1031 if( am.GetCurrentFocusActor() == self )
1038 int Control::AccessibleImpl::GetHighlightIndex() { return 0; }
1040 std::string Control::AccessibleImpl::GetActionName( size_t index )
1042 if( index >= GetActionCount() )
1043 throw Dali::Accessibility::AccessibleError(
1044 "index " + std::to_string( index ) + " is too large for action count " +
1045 std::to_string( GetActionCount() ) );
1046 Dali::TypeInfo type;
1047 self.GetTypeInfo( type );
1049 throw Dali::Accessibility::AccessibleError(
1050 "GetActionName failed for object '" + GetAddress().ToString() +
1051 "' due to the lack of TypeInfo." );
1052 return type.GetActionName( index );
1054 std::string Control::AccessibleImpl::GetLocalizedActionName( size_t index )
1056 // TODO: add localization
1057 return GetActionName( index );
1059 std::string Control::AccessibleImpl::GetActionDescription( size_t index )
1061 if( index >= GetActionCount() )
1062 throw Dali::Accessibility::AccessibleError(
1063 "index " + std::to_string( index ) + " is too large for action count " +
1064 std::to_string( GetActionCount() ) );
1067 size_t Control::AccessibleImpl::GetActionCount()
1069 Dali::TypeInfo type;
1070 self.GetTypeInfo( type );
1072 throw Dali::Accessibility::AccessibleError(
1073 "GetActionCount failed for object '" + GetAddress().ToString() +
1074 "' due to the lack of TypeInfo." );
1075 return type.GetActionCount();
1077 std::string Control::AccessibleImpl::GetActionKeyBinding( size_t index )
1079 if( index >= GetActionCount() )
1080 throw Dali::Accessibility::AccessibleError(
1081 "index " + std::to_string( index ) + " is too large for action count " +
1082 std::to_string( GetActionCount() ) );
1085 bool Control::AccessibleImpl::DoAction( size_t index )
1087 std::string actionName = GetActionName( index );
1088 return self.DoAction( actionName, {} );
1091 } // namespace Internal
1093 } // namespace Toolkit