X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Fcontrol%2Fcontrol-data-impl.cpp;h=83cc802e5316dde5a024be07d52777b3c5a4ed7b;hp=a8387ee9c556e54516256975ced90b57b15fa275;hb=ea014e3440f8df4426bd32d76f07150bd0810d30;hpb=141d88c741ff0aef9aa74259f116fc17023e043a diff --git a/dali-toolkit/internal/controls/control/control-data-impl.cpp b/dali-toolkit/internal/controls/control/control-data-impl.cpp index a8387ee..83cc802 100755 --- a/dali-toolkit/internal/controls/control/control-data-impl.cpp +++ b/dali-toolkit/internal/controls/control/control-data-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -36,10 +43,21 @@ #include #include #include -#include -#include #include #include +#include +#include +#include + +namespace +{ + const std::string READING_INFO_TYPE_NAME = "name"; + const std::string READING_INFO_TYPE_ROLE = "role"; + const std::string READING_INFO_TYPE_DESCRIPTION = "description"; + const std::string READING_INFO_TYPE_STATE = "state"; + const std::string READING_INFO_TYPE_ATTRIBUTE_NAME = "reading_info_type"; + const std::string READING_INFO_TYPE_SEPARATOR = "|"; +} namespace Dali { @@ -69,7 +87,6 @@ namespace #if defined(DEBUG_ENABLED) Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS"); -Debug::Filter* gLogFilterLayout = Debug::Filter::New( Debug::NoLogging, false, "LOG_LAYOUT"); #endif @@ -173,21 +190,64 @@ void MoveVisual( RegisteredVisualContainer::Iterator sourceIter, RegisteredVisua * @param[in] attributes The attributes with which to perfrom this action. * @return true if action has been accepted by this control */ -const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated"; +const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated"; +const char* ACTION_ACCESSIBILITY_READING_CANCELLED = "ReadingCancelled"; +const char* ACTION_ACCESSIBILITY_READING_PAUSED = "ReadingPaused"; +const char* ACTION_ACCESSIBILITY_READING_RESUMED = "ReadingResumed"; +const char* ACTION_ACCESSIBILITY_READING_SKIPPED = "ReadingSkipped"; +const char* ACTION_ACCESSIBILITY_READING_STOPPED = "ReadingStopped"; + static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes ) { - bool ret = false; + bool ret = true; + + Dali::BaseHandle handle( object ); - if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) ) + Toolkit::Control control = Toolkit::Control::DownCast( handle ); + + DALI_ASSERT_ALWAYS( control ); + + if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) || + actionName == "activate" ) { - Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) ); - if( control ) - { - // if cast succeeds there is an implementation so no need to check - ret = Internal::GetImplementation( control ).OnAccessibilityActivated(); - } + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityActivateSignal( control ).Empty() ) + DevelControl::AccessibilityActivateSignal( control ).Emit(); + else ret = Internal::GetImplementation( control ).OnAccessibilityActivated(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_SKIPPED ) ) + { + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityReadingSkippedSignal( control ).Empty() ) + DevelControl::AccessibilityReadingSkippedSignal( control ).Emit(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_PAUSED ) ) + { + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityReadingPausedSignal( control ).Empty() ) + DevelControl::AccessibilityReadingPausedSignal( control ).Emit(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_RESUMED ) ) + { + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityReadingResumedSignal( control ).Empty() ) + DevelControl::AccessibilityReadingResumedSignal( control ).Emit(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_CANCELLED ) ) + { + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityReadingCancelledSignal( control ).Empty() ) + DevelControl::AccessibilityReadingCancelledSignal( control ).Emit(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_STOPPED ) ) + { + // if cast succeeds there is an implementation so no need to check + if(!DevelControl::AccessibilityReadingStoppedSignal( control ).Empty()) + DevelControl::AccessibilityReadingStoppedSignal( control ).Emit(); + } else + { + ret = false; } - return ret; } @@ -207,6 +267,9 @@ const char* SIGNAL_TAPPED = "tapped"; const char* SIGNAL_PANNED = "panned"; const char* SIGNAL_PINCHED = "pinched"; const char* SIGNAL_LONG_PRESSED = "longPressed"; +const char* SIGNAL_GET_NAME = "getName"; +const char* SIGNAL_GET_DESCRIPTION = "getDescription"; +const char* SIGNAL_DO_GESTURE = "doGesture"; static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) { Dali::BaseHandle handle( object ); @@ -232,24 +295,37 @@ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tra } else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) ) { - controlImpl.EnableGestureDetection( Gesture::Tap ); + controlImpl.EnableGestureDetection( GestureType::TAP ); controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor ); } else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) ) { - controlImpl.EnableGestureDetection( Gesture::Pan ); + controlImpl.EnableGestureDetection( GestureType::PAN ); controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor ); } else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) ) { - controlImpl.EnableGestureDetection( Gesture::Pinch ); + controlImpl.EnableGestureDetection( GestureType::PINCH ); controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor ); } else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) ) { - controlImpl.EnableGestureDetection( Gesture::LongPress ); + controlImpl.EnableGestureDetection( GestureType::LONG_PRESS ); controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor ); } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_GET_NAME ) ) + { + DevelControl::AccessibilityGetNameSignal( control ).Connect( tracker, functor ); + } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_GET_DESCRIPTION ) ) + { + DevelControl::AccessibilityGetDescriptionSignal( control ).Connect( tracker, functor ); + } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_DO_GESTURE ) ) + { + DevelControl::AccessibilityDoGestureSignal( control ).Connect( tracker, functor ); + } + } return connected; } @@ -273,25 +349,34 @@ SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnect SignalConnectorType registerSignal5( typeRegistration, SIGNAL_PANNED, &DoConnectSignal ); SignalConnectorType registerSignal6( typeRegistration, SIGNAL_PINCHED, &DoConnectSignal ); SignalConnectorType registerSignal7( typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal ); - -TypeAction registerAction( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction ); +SignalConnectorType registerSignal8( typeRegistration, SIGNAL_GET_NAME, &DoConnectSignal ); +SignalConnectorType registerSignal9( typeRegistration, SIGNAL_GET_DESCRIPTION, &DoConnectSignal ); +SignalConnectorType registerSignal10( typeRegistration, SIGNAL_DO_GESTURE, &DoConnectSignal ); + +TypeAction registerAction1( typeRegistration, "activate", &DoAction ); +TypeAction registerAction2( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction ); +TypeAction registerAction3( typeRegistration, ACTION_ACCESSIBILITY_READING_SKIPPED, &DoAction ); +TypeAction registerAction4( typeRegistration, ACTION_ACCESSIBILITY_READING_CANCELLED, &DoAction ); +TypeAction registerAction5( typeRegistration, ACTION_ACCESSIBILITY_READING_STOPPED, &DoAction ); +TypeAction registerAction6( typeRegistration, ACTION_ACCESSIBILITY_READING_PAUSED, &DoAction ); +TypeAction registerAction7( typeRegistration, ACTION_ACCESSIBILITY_READING_RESUMED, &DoAction ); DALI_TYPE_REGISTRATION_END() /** - * @brief Iterate through given container and setOffStage any visual found + * @brief Iterate through given container and setOffScene any visual found * * @param[in] container Container of visuals * @param[in] parent Parent actor to remove visuals from */ -void SetVisualsOffStage( const RegisteredVisualContainer& container, Actor parent ) +void SetVisualsOffScene( const RegisteredVisualContainer& container, Actor parent ) { for( auto iter = container.Begin(), end = container.End() ; iter!= end; iter++) { if( (*iter)->visual ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::SetOffStage Setting visual(%d) off stage\n", (*iter)->index ); - Toolkit::GetImplementation((*iter)->visual).SetOffStage( parent ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::SetOffScene Setting visual(%d) off stage\n", (*iter)->index ); + Toolkit::GetImplementation((*iter)->visual).SetOffScene( parent ); } } } @@ -301,8 +386,6 @@ void SetVisualsOffStage( const RegisteredVisualContainer& container, Actor paren // Properties registered without macro to use specific member variables. const PropertyRegistration Control::Impl::PROPERTY_1( typeRegistration, "styleName", Toolkit::Control::Property::STYLE_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); -const PropertyRegistration Control::Impl::PROPERTY_2( typeRegistration, "backgroundColor", Toolkit::Control::Property::BACKGROUND_COLOR, Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); -const PropertyRegistration Control::Impl::PROPERTY_3( typeRegistration, "backgroundImage", Toolkit::Control::Property::BACKGROUND_IMAGE, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus", Toolkit::Control::Property::KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background", Toolkit::Control::Property::BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); const PropertyRegistration Control::Impl::PROPERTY_6( typeRegistration, "margin", Toolkit::Control::Property::MARGIN, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); @@ -314,43 +397,88 @@ const PropertyRegistration Control::Impl::PROPERTY_11( typeRegistration, "leftFo const PropertyRegistration Control::Impl::PROPERTY_12( typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID,Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); const PropertyRegistration Control::Impl::PROPERTY_13( typeRegistration, "upFocusableActorId", Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); const PropertyRegistration Control::Impl::PROPERTY_14( typeRegistration, "downFocusableActorId", Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); - +const PropertyRegistration Control::Impl::PROPERTY_15( typeRegistration, "shadow", Toolkit::DevelControl::Property::SHADOW, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_16( typeRegistration, "accessibilityAttributes", Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_17( typeRegistration, "accessibilityName", Toolkit::DevelControl::Property::ACCESSIBILITY_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_18( typeRegistration, "accessibilityDescription", Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_19( typeRegistration, "accessibilityTranslationDomain", Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_20( typeRegistration, "accessibilityRole", Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_21( typeRegistration, "accessibilityHighlightable", Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_22( typeRegistration, "accessibilityAnimated", Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); Control::Impl::Impl( Control& controlImpl ) : mControlImpl( controlImpl ), mState( Toolkit::DevelControl::NORMAL ), mSubStateName(""), - mLayout( NULL ), mLeftFocusableActorId( -1 ), mRightFocusableActorId( -1 ), mUpFocusableActorId( -1 ), mDownFocusableActorId( -1 ), mStyleName(""), mBackgroundColor(Color::TRANSPARENT), - mStartingPinchScale( NULL ), + mStartingPinchScale(nullptr), mMargin( 0, 0, 0, 0 ), mPadding( 0, 0, 0, 0 ), mKeyEventSignal(), mKeyInputFocusGainedSignal(), mKeyInputFocusLostSignal(), mResourceReadySignal(), + mVisualEventSignal(), + mAccessibilityGetNameSignal(), + mAccessibilityGetDescriptionSignal(), + mAccessibilityDoGestureSignal(), mPinchGestureDetector(), mPanGestureDetector(), mTapGestureDetector(), mLongPressGestureDetector(), mTooltip( NULL ), mInputMethodContext(), + mIdleCallback(nullptr), mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ), mIsKeyboardNavigationSupported( false ), mIsKeyboardFocusGroup( false ), - mIsLayoutingRequired( false ) + mIsEmittingResourceReadySignal(false), + mNeedToEmitResourceReady(false) { + Dali::Accessibility::Accessible::RegisterControlAccessibilityGetter( + []( Dali::Actor actor ) -> Dali::Accessibility::Accessible* { + return Control::Impl::GetAccessibilityObject( actor ); + } ); + + accessibilityConstructor = []( Dali::Actor actor ) -> std::unique_ptr< Dali::Accessibility::Accessible > { + return std::unique_ptr< Dali::Accessibility::Accessible >( new AccessibleImpl( actor, + Dali::Accessibility::Role::UNKNOWN ) ); + }; + + size_t len = static_cast(Dali::Accessibility::RelationType::MAX_COUNT); + mAccessibilityRelations.reserve(len); + for (auto i = 0u; i < len; ++i) + { + mAccessibilityRelations.push_back({}); + } } Control::Impl::~Impl() { + for( auto&& iter : mVisuals ) + { + StopObservingVisual( iter->visual ); + } + + for( auto&& iter : mRemoveVisuals ) + { + StopObservingVisual( iter->visual ); + } + + AccessibilityDeregister(); // All gesture detectors will be destroyed so no need to disconnect. delete mStartingPinchScale; + + if(mIdleCallback && Adaptor::IsAvailable()) + { + // Removes the callback from the callback manager in case the control is destroyed before the callback is executed. + Adaptor::Get().RemoveIdle(mIdleCallback); + } } Control::Impl& Control::Impl::Get( Internal::Control& internalControl ) @@ -437,7 +565,7 @@ void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base StopObservingVisual( currentRegisteredVisual ); // If control staged and visual enabled then visuals will be swapped once ready - if( self.OnStage() && enabled ) + if( self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) && enabled ) { // Check if visual is currently in the process of being replaced ( is in removal container ) RegisteredVisualContainer::Iterator visualQueuedForRemoval; @@ -445,7 +573,7 @@ void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base { // Visual with same index is already in removal container so current visual pending // Only the the last requested visual will be displayed so remove current visual which is staged but not ready. - Toolkit::GetImplementation( currentRegisteredVisual ).SetOffStage( self ); + Toolkit::GetImplementation( currentRegisteredVisual ).SetOffScene( self ); mVisuals.Erase( registeredVisualsiter ); } else @@ -477,19 +605,13 @@ void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base // ( If the control has been type registered ) if( visual.GetName().empty() ) { - try + // returns empty string if index is not found as long as index is not -1 + std::string visualName = self.GetPropertyName( index ); + if( !visualName.empty() ) { - std::string visualName = self.GetPropertyName( index ); - if( !visualName.empty() ) - { - DALI_LOG_INFO( gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", - index, visualName.c_str() ); - visual.SetName( visualName ); - } - } - catch( Dali::DaliException e ) - { - DALI_LOG_WARNING( "Attempting to register visual without a registered property, index: %d\n", index ); + DALI_LOG_INFO( gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", + index, visualName.c_str() ); + visual.SetName( visualName ); } } @@ -533,9 +655,9 @@ void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual ); // Put on stage if enabled and the control is already on the stage - if( ( enabled == VisualState::ENABLED ) && self.OnStage() ) + if( ( enabled == VisualState::ENABLED ) && self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) ) { - visualImpl.SetOnStage( self ); + visualImpl.SetOnScene( self ); } else if( visualImpl.IsResourceReady() ) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already ) { @@ -556,7 +678,7 @@ void Control::Impl::UnregisterVisual( Property::Index index ) StopObservingVisual( (*iter)->visual ); Actor self( mControlImpl.Self() ); - Toolkit::GetImplementation((*iter)->visual).SetOffStage( self ); + Toolkit::GetImplementation((*iter)->visual).SetOffScene( self ); (*iter)->visual.Reset(); mVisuals.Erase( iter ); } @@ -564,7 +686,7 @@ void Control::Impl::UnregisterVisual( Property::Index index ) if( FindVisual( index, mRemoveVisuals, iter ) ) { Actor self( mControlImpl.Self() ); - Toolkit::GetImplementation( (*iter)->visual ).SetOffStage( self ); + Toolkit::GetImplementation( (*iter)->visual ).SetOffScene( self ); (*iter)->pending = false; (*iter)->visual.Reset(); mRemoveVisuals.Erase( iter ); @@ -597,17 +719,17 @@ void Control::Impl::EnableVisual( Property::Index index, bool enable ) (*iter)->enabled = enable; Actor parentActor = mControlImpl.Self(); - if ( mControlImpl.Self().OnStage() ) // If control not on Stage then Visual will be added when StageConnection is called. + if ( mControlImpl.Self().GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) ) // If control not on Scene then Visual will be added when SceneConnection is called. { if ( enable ) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index ); - Toolkit::GetImplementation((*iter)->visual).SetOnStage( parentActor ); + Toolkit::GetImplementation((*iter)->visual).SetOnScene( parentActor ); } else { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index ); - Toolkit::GetImplementation((*iter)->visual).SetOffStage( parentActor ); // No need to call if control not staged. + Toolkit::GetImplementation((*iter)->visual).SetOffScene( parentActor ); // No need to call if control not staged. } } } @@ -632,15 +754,15 @@ void Control::Impl::StopObservingVisual( Toolkit::Visual::Base& visual ) Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual ); // Stop observing the visual - visualImpl.RemoveResourceObserver( *this ); + visualImpl.RemoveEventObserver( *this ); } void Control::Impl::StartObservingVisual( Toolkit::Visual::Base& visual) { Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual ); - // start observing the visual for resource ready - visualImpl.AddResourceObserver( *this ); + // start observing the visual for events + visualImpl.AddEventObserver( *this ); } // Called by a Visual when it's resource is ready @@ -665,7 +787,7 @@ void Control::Impl::ResourceReady( Visual::Base& object) if( FindVisual( (*registeredIter)->index, mRemoveVisuals, visualToRemoveIter ) ) { (*registeredIter)->pending = false; - Toolkit::GetImplementation( (*visualToRemoveIter)->visual ).SetOffStage( self ); + Toolkit::GetImplementation( (*visualToRemoveIter)->visual ).SetOffScene( self ); mRemoveVisuals.Erase( visualToRemoveIter ); } break; @@ -673,7 +795,7 @@ void Control::Impl::ResourceReady( Visual::Base& object) } // A visual is ready so control may need relayouting if staged - if ( self.OnStage() ) + if ( self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) ) { mControlImpl.RelayoutRequest(); } @@ -681,8 +803,24 @@ void Control::Impl::ResourceReady( Visual::Base& object) // Emit signal if all enabled visuals registered by the control are ready. if( IsResourceReady() ) { - Dali::Toolkit::Control handle( mControlImpl.GetOwner() ); - mResourceReadySignal.Emit( handle ); + // Reset the flag + mNeedToEmitResourceReady = false; + + EmitResourceReadySignal(); + } +} + +void Control::Impl::NotifyVisualEvent( Visual::Base& object, Property::Index signalId ) +{ + for( auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter ) + { + Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation( (*registeredIter)->visual ); + if( &object == ®isteredVisualImpl ) + { + Dali::Toolkit::Control handle( mControlImpl.GetOwner() ); + mVisualEventSignal.Emit( handle, (*registeredIter)->index, signalId ); + break; + } } } @@ -756,7 +894,7 @@ void Control::Impl::AddTransitions( Dali::Animation& animation, Actor child = mControlImpl.Self().FindChildByName( animator->objectName ); if( child ) { - Property::Index propertyIndex = DevelHandle::GetPropertyIndex( child, animator->propertyKey ); + Property::Index propertyIndex = child.GetPropertyIndex( animator->propertyKey ); if( propertyIndex != Property::INVALID_INDEX ) { if( animator->animate == false ) @@ -812,6 +950,20 @@ void Control::Impl::DoAction( Dali::Property::Index visualIndex, Dali::Property: } } +void Control::Impl::AppendAccessibilityAttribute( const std::string& key, + const std::string value ) +{ + Property::Value* val = mAccessibilityAttributes.Find( key ); + if( val ) + { + mAccessibilityAttributes[key] = Property::Value( value ); + } + else + { + mAccessibilityAttributes.Insert( key, value ); + } +} + void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) { Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) ); @@ -832,7 +984,7 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons { bool withTransitions=true; const Property::Value* valuePtr=&value; - Property::Map* map = value.GetMap(); + const Property::Map* map = value.GetMap(); if(map) { Property::Value* value2 = map->Find("withTransitions"); @@ -885,48 +1037,95 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons } break; - case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID: + case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME: { - int focusId; - if( value.Get( focusId ) ) + std::string name; + if( value.Get( name ) ) { - controlImpl.mImpl->mUpFocusableActorId = focusId; + controlImpl.mImpl->mAccessibilityName = name; + controlImpl.mImpl->mAccessibilityNameSet = true; + } + else + { + controlImpl.mImpl->mAccessibilityNameSet = false; } } break; - case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID: + case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION: { - int focusId; - if( value.Get( focusId ) ) + std::string txt; + if( value.Get( txt ) ) { - controlImpl.mImpl->mDownFocusableActorId = focusId; + controlImpl.mImpl->mAccessibilityDescription = txt; + controlImpl.mImpl->mAccessibilityDescriptionSet = true; + } + else + { + controlImpl.mImpl->mAccessibilityDescriptionSet = false; } } break; - case Toolkit::Control::Property::BACKGROUND_COLOR: + case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN: { - DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" ); - controlImpl.SetBackgroundColor( value.Get< Vector4 >() ); - break; + std::string txt; + if( value.Get( txt ) ) + { + controlImpl.mImpl->mAccessibilityTranslationDomain = txt; + controlImpl.mImpl->mAccessibilityTranslationDomainSet = true; + } + else + { + controlImpl.mImpl->mAccessibilityTranslationDomainSet = false; + } } + break; - case Toolkit::Control::Property::BACKGROUND_IMAGE: + case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE: { - DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" ); - Image image = Scripting::NewImage( value ); - if ( image ) + bool highlightable; + if( value.Get( highlightable ) ) { - controlImpl.SetBackgroundImage( image ); + controlImpl.mImpl->mAccessibilityHighlightable = highlightable; + controlImpl.mImpl->mAccessibilityHighlightableSet = true; } else { - // An empty image means the background is no longer required - controlImpl.ClearBackground(); + controlImpl.mImpl->mAccessibilityHighlightableSet = false; + } + } + break; + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE: + { + Dali::Accessibility::Role val; + if( value.Get( val ) ) + { + controlImpl.mImpl->mAccessibilityRole = val; } - break; } + break; + + case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID: + { + int focusId; + if( value.Get( focusId ) ) + { + controlImpl.mImpl->mUpFocusableActorId = focusId; + } + } + break; + + case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID: + { + int focusId; + if( value.Get( focusId ) ) + { + controlImpl.mImpl->mDownFocusableActorId = focusId; + } + } + break; case Toolkit::Control::Property::KEY_INPUT_FOCUS: { @@ -1002,6 +1201,40 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons break; } + case Toolkit::DevelControl::Property::SHADOW: + { + const Property::Map* map = value.GetMap(); + if( map && !map->Empty() ) + { + controlImpl.mImpl->SetShadow( *map ); + } + else + { + // The shadow is an empty property map, so we should clear the shadow + controlImpl.mImpl->ClearShadow(); + } + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES: + { + const Property::Map* map = value.GetMap(); + if( map && !map->Empty() ) + { + controlImpl.mImpl->mAccessibilityAttributes = *map; + } + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED: + { + bool animated; + if( value.Get( animated ) ) + { + controlImpl.mImpl->mAccessibilityAnimated = animated; + } + break; + } } } } @@ -1048,35 +1281,57 @@ Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index break; } - case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID: + case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME: { - value = controlImpl.mImpl->mUpFocusableActorId; + if (controlImpl.mImpl->mAccessibilityNameSet) + { + value = controlImpl.mImpl->mAccessibilityName; + } break; } - case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID: + case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION: { - value = controlImpl.mImpl->mDownFocusableActorId; + if (controlImpl.mImpl->mAccessibilityDescriptionSet) + { + value = controlImpl.mImpl->mAccessibilityDescription; + } break; } - case Toolkit::Control::Property::BACKGROUND_COLOR: + case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN: { - DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" ); - value = controlImpl.GetBackgroundColor(); + if (controlImpl.mImpl->mAccessibilityTranslationDomainSet) + { + value = controlImpl.mImpl->mAccessibilityTranslationDomain; + } break; } - case Toolkit::Control::Property::BACKGROUND_IMAGE: + case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE: { - DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" ); - Property::Map map; - Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND ); - if( visual ) + if (controlImpl.mImpl->mAccessibilityHighlightableSet) { - visual.CreatePropertyMap( map ); + value = controlImpl.mImpl->mAccessibilityHighlightable; } - value = map; + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE: + { + value = Property::Value(controlImpl.mImpl->mAccessibilityRole); + break; + } + + case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID: + { + value = controlImpl.mImpl->mUpFocusableActorId; + break; + } + + case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID: + { + value = controlImpl.mImpl->mDownFocusableActorId; break; } @@ -1121,12 +1376,118 @@ Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index value = map; break; } + + case Toolkit::DevelControl::Property::SHADOW: + { + Property::Map map; + Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::DevelControl::Property::SHADOW ); + if( visual ) + { + visual.CreatePropertyMap( map ); + } + + value = map; + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES: + { + value = controlImpl.mImpl->mAccessibilityAttributes; + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED: + { + value = controlImpl.mImpl->mAccessibilityAnimated; + break; + } } } return value; } +void Control::Impl::RemoveAccessibilityAttribute( const std::string& key ) +{ + Property::Value* val = mAccessibilityAttributes.Find( key ); + if( val ) + mAccessibilityAttributes[key] = Property::Value(); +} + +void Control::Impl::ClearAccessibilityAttributes() +{ + mAccessibilityAttributes.Clear(); +} + +void Control::Impl::SetAccessibilityReadingInfoType( const Dali::Accessibility::ReadingInfoTypes types ) +{ + std::string value; + if ( types[ Dali::Accessibility::ReadingInfoType::NAME ] ) + { + value += READING_INFO_TYPE_NAME; + } + if ( types[ Dali::Accessibility::ReadingInfoType::ROLE ] ) + { + if( !value.empty() ) + { + value += READING_INFO_TYPE_SEPARATOR; + } + value += READING_INFO_TYPE_ROLE; + } + if ( types[ Dali::Accessibility::ReadingInfoType::DESCRIPTION ] ) + { + if( !value.empty() ) + { + value += READING_INFO_TYPE_SEPARATOR; + } + value += READING_INFO_TYPE_DESCRIPTION; + } + if ( types[ Dali::Accessibility::ReadingInfoType::STATE ] ) + { + if( !value.empty() ) + { + value += READING_INFO_TYPE_SEPARATOR; + } + value += READING_INFO_TYPE_STATE; + } + AppendAccessibilityAttribute( READING_INFO_TYPE_ATTRIBUTE_NAME, value ); +} + +Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const +{ + std::string value; + auto place = mAccessibilityAttributes.Find( READING_INFO_TYPE_ATTRIBUTE_NAME ); + if( place ) + { + place->Get( value ); + } + + if ( value.empty() ) + { + return {}; + } + + Dali::Accessibility::ReadingInfoTypes types; + + if ( value.find( READING_INFO_TYPE_NAME ) != std::string::npos ) + { + types[ Dali::Accessibility::ReadingInfoType::NAME ] = true; + } + if ( value.find( READING_INFO_TYPE_ROLE ) != std::string::npos ) + { + types[ Dali::Accessibility::ReadingInfoType::ROLE ] = true; + } + if ( value.find( READING_INFO_TYPE_DESCRIPTION ) != std::string::npos ) + { + types[ Dali::Accessibility::ReadingInfoType::DESCRIPTION ] = true; + } + if ( value.find( READING_INFO_TYPE_STATE ) != std::string::npos ) + { + types[ Dali::Accessibility::ReadingInfoType::STATE ] = true; + } + + return types; +} void Control::Impl::CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary& instancedProperties ) { @@ -1152,7 +1513,7 @@ void Control::Impl::RemoveVisual( RegisteredVisualContainer& visuals, const std: Toolkit::Visual::Base visual = (*visualIter)->visual; if( visual && visual.GetName() == visualName ) { - Toolkit::GetImplementation(visual).SetOffStage( self ); + Toolkit::GetImplementation(visual).SetOffScene( self ); (*visualIter)->visual.Reset(); visuals.Erase( visualIter ); break; @@ -1366,22 +1727,22 @@ void Control::Impl::SetSubState( const std::string& subStateName, bool withTrans } } -void Control::Impl::OnStageDisconnection() +void Control::Impl::OnSceneDisconnection() { Actor self = mControlImpl.Self(); // Any visuals set for replacement but not yet ready should still be registered. - // Reason: If a request was made to register a new visual but the control removed from stage before visual was ready + // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready // then when this control appears back on stage it should use that new visual. - // Iterate through all registered visuals and set off stage - SetVisualsOffStage( mVisuals, self ); + // Iterate through all registered visuals and set off scene + SetVisualsOffScene( mVisuals, self ); - // Visuals pending replacement can now be taken out of the removal list and set off stage - // Iterate through all replacement visuals and add to a move queue then set off stage + // Visuals pending replacement can now be taken out of the removal list and set off scene + // Iterate through all replacement visuals and add to a move queue then set off scene for( auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++ ) { - Toolkit::GetImplementation((*removalIter)->visual).SetOffStage( self ); + Toolkit::GetImplementation((*removalIter)->visual).SetOffScene( self ); } for( auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++ ) @@ -1434,65 +1795,530 @@ bool Control::Impl::FilterKeyEvent( const KeyEvent& event ) return consumed; } -Toolkit::Internal::LayoutItemPtr Control::Impl::GetLayout() const +DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal() { - return mLayout; + return mVisualEventSignal; } -void Control::Impl::SetLayout( Toolkit::Internal::LayoutItem& layout ) +void Control::Impl::SetShadow( const Property::Map& map ) { - DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::SetLayout control:%s replacing existing layout:%s\n", - mControlImpl.Self().GetName().c_str(), - mLayout?"true":"false" ); - // Check if layout already has an owner. - auto control = Toolkit::Control::DownCast( layout.GetOwner() ); - if ( control ) + Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( map ); + visual.SetName("shadow"); + + if( visual ) + { + mControlImpl.mImpl->RegisterVisual( Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT ); + + mControlImpl.RelayoutRequest(); + } +} + +void Control::Impl::ClearShadow() +{ + mControlImpl.mImpl->UnregisterVisual( Toolkit::DevelControl::Property::SHADOW ); + + // Trigger a size negotiation request that may be needed when unregistering a visual. + mControlImpl.RelayoutRequest(); +} + +void Control::Impl::EmitResourceReadySignal() +{ + if(!mIsEmittingResourceReadySignal) + { + // Guard against calls to emit the signal during the callback + mIsEmittingResourceReadySignal = true; + + // If the signal handler changes visual, it may become ready during this call & therefore this method will + // get called again recursively. If so, mNeedToEmitResourceReady is set below, and we act on it after that secondary + // invocation has completed by notifying in an Idle callback to prevent further recursion. + Dali::Toolkit::Control handle(mControlImpl.GetOwner()); + mResourceReadySignal.Emit(handle); + + if(mNeedToEmitResourceReady) + { + // Add idler to emit the signal again + if(!mIdleCallback) + { + // The callback manager takes the ownership of the callback object. + mIdleCallback = MakeCallback( this, &Control::Impl::OnIdleCallback); + Adaptor::Get().AddIdle(mIdleCallback, false); + } + } + + mIsEmittingResourceReadySignal = false; + } + else { - // If the owner is not this control then the owning control can no longer own it. - Dali::Toolkit::Control handle( mControlImpl.GetOwner() ); - if( control != handle ) + mNeedToEmitResourceReady = true; + } +} + +void Control::Impl::OnIdleCallback() +{ + if(mNeedToEmitResourceReady) + { + // Reset the flag + mNeedToEmitResourceReady = false; + + // A visual is ready so control may need relayouting if staged + if(mControlImpl.Self().GetProperty(Actor::Property::CONNECTED_TO_SCENE)) { - DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::SetLayout Layout already in use, %s will now have a BinLayout\n", - control.GetName().c_str() ); - Toolkit::BinLayout binLayout = Toolkit::BinLayout::New(); - // Previous owner of the layout gets a BinLayout instead of the layout. - DevelControl::SetLayout( control, binLayout ) ; + mControlImpl.RelayoutRequest(); } - else + + EmitResourceReadySignal(); + } + + // Set the pointer to null as the callback manager deletes the callback after execute it. + mIdleCallback = nullptr; +} + +Dali::Accessibility::Accessible *Control::Impl::GetAccessibilityObject() +{ + if( !accessibilityObject ) + accessibilityObject = accessibilityConstructor( mControlImpl.Self() ); + return accessibilityObject.get(); +} + +Dali::Accessibility::Accessible *Control::Impl::GetAccessibilityObject(Dali::Actor actor) +{ + if( actor ) + { + auto q = Dali::Toolkit::Control::DownCast( actor ); + if( q ) { - return; // layout is already set to this control. + auto q2 = static_cast< Internal::Control* >( &q.GetImplementation() ); + return q2->mImpl->GetAccessibilityObject(); } } + return nullptr; +} + +Control::Impl::AccessibleImpl::AccessibleImpl(Dali::Actor self, Dali::Accessibility::Role role, bool modal) + : self(self), modal(modal) +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + if( controlImpl.mAccessibilityRole == Dali::Accessibility::Role::UNKNOWN ) + controlImpl.mAccessibilityRole = role; - if( mLayout ) + self.PropertySetSignal().Connect(&controlImpl, [this, &controlImpl](Dali::Handle &handle, Dali::Property::Index index, Dali::Property::Value value) { - mLayout->Unparent(); - mLayout.Reset(); + if (this->self != Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor()) + { + return; + } + + if (index == DevelControl::Property::ACCESSIBILITY_NAME + || (index == GetNamePropertyIndex() && !controlImpl.mAccessibilityNameSet)) + { + if (controlImpl.mAccessibilityGetNameSignal.Empty()) + { + Emit(Dali::Accessibility::ObjectPropertyChangeEvent::NAME); + } + } + + if (index == DevelControl::Property::ACCESSIBILITY_DESCRIPTION + || (index == GetDescriptionPropertyIndex() && !controlImpl.mAccessibilityDescriptionSet)) + { + if (controlImpl.mAccessibilityGetDescriptionSignal.Empty()) + { + Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION); + } + } + }); +} + +std::string Control::Impl::AccessibleImpl::GetName() +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + + if (!controlImpl.mAccessibilityGetNameSignal.Empty()) { + std::string ret; + controlImpl.mAccessibilityGetNameSignal.Emit(ret); + return ret; + } + + if (controlImpl.mAccessibilityNameSet) + return controlImpl.mAccessibilityName; + + if (auto raw = GetNameRaw(); !raw.empty()) + return raw; + + return self.GetProperty< std::string >( Actor::Property::NAME ); +} + +std::string Control::Impl::AccessibleImpl::GetNameRaw() +{ + return {}; +} + +std::string Control::Impl::AccessibleImpl::GetDescription() +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + + if (!controlImpl.mAccessibilityGetDescriptionSignal.Empty()) { + std::string ret; + controlImpl.mAccessibilityGetDescriptionSignal.Emit(ret); + return ret; } - mLayout = &layout; + if (controlImpl.mAccessibilityDescriptionSet) + return controlImpl.mAccessibilityDescription; + + return GetDescriptionRaw(); +} + +std::string Control::Impl::AccessibleImpl::GetDescriptionRaw() +{ + return ""; +} + +Dali::Accessibility::Accessible* Control::Impl::AccessibleImpl::GetParent() +{ + return Dali::Accessibility::Accessible::Get( self.GetParent() ); +} + +size_t Control::Impl::AccessibleImpl::GetChildCount() +{ + return self.GetChildCount(); +} + +Dali::Accessibility::Accessible* Control::Impl::AccessibleImpl::GetChildAtIndex( size_t index ) +{ + return Dali::Accessibility::Accessible::Get( self.GetChildAt( static_cast< unsigned int >( index ) ) ); +} - auto controlHandle = Toolkit::Control::DownCast( mControlImpl.Self() ); // Get a handle of this control implementation without copying internals. - mLayout->Initialize( controlHandle, controlHandle.GetTypeName() ); // LayoutGroup takes ownership of existing children +size_t Control::Impl::AccessibleImpl::GetIndexInParent() +{ + auto s = self; + auto parent = s.GetParent(); + DALI_ASSERT_ALWAYS( parent && "can't call GetIndexInParent on object without parent" ); + auto count = parent.GetChildCount(); + for( auto i = 0u; i < count; ++i ) + { + auto c = parent.GetChildAt( i ); + if( c == s ) + return i; + } + DALI_ASSERT_ALWAYS( false && "object isn't child of it's parent" ); + return static_cast(-1); } -void Control::Impl::RemoveLayout() +Dali::Accessibility::Role Control::Impl::AccessibleImpl::GetRole() { - DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::Impl::RemoveLayout\n"); + return self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE ); +} - Toolkit::BinLayout binLayout = Toolkit::BinLayout::New(); +Dali::Accessibility::States Control::Impl::AccessibleImpl::CalculateStates() +{ + Dali::Accessibility::States s; + s[Dali::Accessibility::State::FOCUSABLE] = self.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ); + s[Dali::Accessibility::State::FOCUSED] = Toolkit::KeyboardFocusManager::Get().GetCurrentFocusActor() == self; + if(self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ).GetType() == Property::NONE ) + s[Dali::Accessibility::State::HIGHLIGHTABLE] = false; + else + s[Dali::Accessibility::State::HIGHLIGHTABLE] = self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ).Get< bool >(); + s[Dali::Accessibility::State::HIGHLIGHTED] = GetCurrentlyHighlightedActor() == self; + s[Dali::Accessibility::State::ENABLED] = true; + s[Dali::Accessibility::State::SENSITIVE] = true; + s[Dali::Accessibility::State::ANIMATED] = self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED ).Get< bool >(); + s[Dali::Accessibility::State::VISIBLE] = true; + if( modal ) + { + s[Dali::Accessibility::State::MODAL] = true; + } + s[Dali::Accessibility::State::SHOWING] = !self.GetProperty( Dali::DevelActor::Property::CULLED ).Get< bool >() + && self.GetCurrentProperty< bool >( Actor::Property::VISIBLE ); - mControlImpl.mImpl->SetLayout( GetImplementation( binLayout ) ) ; + s[Dali::Accessibility::State::DEFUNCT] = !self.GetProperty( Dali::DevelActor::Property::CONNECTED_TO_SCENE ).Get< bool >(); + return s; } -void Control::Impl::SetLayoutingRequired( bool layoutingRequired ) +Dali::Accessibility::States Control::Impl::AccessibleImpl::GetStates() { - mControlImpl.mImpl->mIsLayoutingRequired = layoutingRequired; + return CalculateStates(); } -bool Control::Impl::IsLayoutingRequired() +Dali::Accessibility::Attributes Control::Impl::AccessibleImpl::GetAttributes() { - return mControlImpl.mImpl->mIsLayoutingRequired; + std::unordered_map< std::string, std::string > attribute_map; + auto q = Dali::Toolkit::Control::DownCast( self ); + auto w = + q.GetProperty( Dali::Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + auto z = w.GetMap(); + + if( z ) + { + auto map_size = z->Count(); + + for( unsigned int i = 0; i < map_size; i++ ) + { + auto map_key = z->GetKeyAt( i ); + if( map_key.type == Property::Key::STRING ) + { + std::string map_value; + if( z->GetValue( i ).Get( map_value ) ) + { + attribute_map.emplace( std::move( map_key.stringKey ), + std::move( map_value ) ); + } + } + } + } + + return attribute_map; +} + +Dali::Accessibility::ComponentLayer Control::Impl::AccessibleImpl::GetLayer() +{ + return Dali::Accessibility::ComponentLayer::WINDOW; +} + +Dali::Rect<> Control::Impl::AccessibleImpl::GetExtents( Dali::Accessibility::CoordType ctype ) +{ + Vector2 screenPosition = + self.GetProperty( Dali::DevelActor::Property::SCREEN_POSITION ) + .Get< Vector2 >(); + auto size = self.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) * self.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_SCALE ); + bool positionUsesAnchorPoint = + self.GetProperty( Dali::DevelActor::Property::POSITION_USES_ANCHOR_POINT ) + .Get< bool >(); + Vector3 anchorPointOffSet = + size * ( positionUsesAnchorPoint ? self.GetCurrentProperty< Vector3 >( Actor::Property::ANCHOR_POINT ) + : AnchorPoint::TOP_LEFT ); + Vector2 position = Vector2( screenPosition.x - anchorPointOffSet.x, + screenPosition.y - anchorPointOffSet.y ); + + return { position.x, position.y, size.x, size.y }; +} + +int16_t Control::Impl::AccessibleImpl::GetMdiZOrder() { return 0; } +double Control::Impl::AccessibleImpl::GetAlpha() { return 0; } + +bool Control::Impl::AccessibleImpl::GrabFocus() +{ + return Toolkit::KeyboardFocusManager::Get().SetCurrentFocusActor( self ); +} + +static Dali::Actor CreateHighlightIndicatorActor() +{ + std::string focusBorderImagePath(AssetManager::GetDaliImagePath()); + focusBorderImagePath += "/keyboard_focus.9.png"; + // Create the default if it hasn't been set and one that's shared by all the + // keyboard focusable actors + auto actor = Toolkit::ImageView::New( focusBorderImagePath ); + actor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + DevelControl::AppendAccessibilityAttribute( actor, "highlight", "" ); + actor.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED, true); + actor.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false ); + + return actor; +} + +bool Control::Impl::AccessibleImpl::GrabHighlight() +{ + auto old = GetCurrentlyHighlightedActor(); + + if( !Dali::Accessibility::IsUp() ) + return false; + if( self == old ) + return true; + if( old ) + { + auto c = dynamic_cast< Dali::Accessibility::Component* >( GetAccessibilityObject( old ) ); + if( c ) + c->ClearHighlight(); + } + auto highlight = GetHighlightActor(); + if ( !highlight ) + { + highlight = CreateHighlightIndicatorActor(); + SetHighlightActor( highlight ); + } + highlight.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER ); + highlight.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER ); + highlight.SetProperty( Actor::Property::POSITION_Z, 1.0f ); + highlight.SetProperty( Actor::Property::POSITION, Vector2( 0.0f, 0.0f )); + + EnsureSelfVisible(); + self.Add( highlight ); + SetCurrentlyHighlightedActor( self ); + EmitHighlighted( true ); + + return true; +} + + + +bool Control::Impl::AccessibleImpl::ClearHighlight() +{ + if( !Dali::Accessibility::IsUp() ) + return false; + if( GetCurrentlyHighlightedActor() == self ) + { + self.Remove( GetHighlightActor() ); + SetCurrentlyHighlightedActor( {} ); + EmitHighlighted( false ); + return true; + } + return false; +} + +std::string Control::Impl::AccessibleImpl::GetActionName( size_t index ) +{ + if ( index >= GetActionCount() ) return ""; + Dali::TypeInfo type; + self.GetTypeInfo( type ); + DALI_ASSERT_ALWAYS( type && "no TypeInfo object" ); + return type.GetActionName( index ); +} +std::string Control::Impl::AccessibleImpl::GetLocalizedActionName( size_t index ) +{ + // TODO: add localization + return GetActionName( index ); +} +std::string Control::Impl::AccessibleImpl::GetActionDescription( size_t index ) +{ + return ""; +} +size_t Control::Impl::AccessibleImpl::GetActionCount() +{ + Dali::TypeInfo type; + self.GetTypeInfo( type ); + DALI_ASSERT_ALWAYS( type && "no TypeInfo object" ); + return type.GetActionCount(); +} +std::string Control::Impl::AccessibleImpl::GetActionKeyBinding( size_t index ) +{ + return ""; +} +bool Control::Impl::AccessibleImpl::DoAction( size_t index ) +{ + std::string actionName = GetActionName( index ); + return self.DoAction( actionName, {} ); +} +bool Control::Impl::AccessibleImpl::DoAction(const std::string& name) +{ + return self.DoAction( name, {} ); +} + +bool Control::Impl::AccessibleImpl::DoGesture(const Dali::Accessibility::GestureInfo &gestureInfo) +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + + if (!controlImpl.mAccessibilityDoGestureSignal.Empty()) { + auto ret = std::make_pair(gestureInfo, false); + controlImpl.mAccessibilityDoGestureSignal.Emit(ret); + return ret.second; + } + + return false; +} + +std::vector Control::Impl::AccessibleImpl::GetRelationSet() +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + + std::vector ret; + + auto &v = controlImpl.mAccessibilityRelations; + for (auto i = 0u; i < v.size(); ++i) + { + if ( v[i].empty() ) + continue; + + ret.emplace_back( Accessibility::Relation{ static_cast(i), v[i] } ); + } + + return ret; +} + +void Control::Impl::AccessibleImpl::EnsureChildVisible(Actor child) +{ +} + +void Control::Impl::AccessibleImpl::EnsureSelfVisible() +{ + auto parent = dynamic_cast(GetParent()); + if (parent) + { + parent->EnsureChildVisible(self); + } +} + +Property::Index Control::Impl::AccessibleImpl::GetNamePropertyIndex() +{ + return Actor::Property::NAME; +} + +Property::Index Control::Impl::AccessibleImpl::GetDescriptionPropertyIndex() +{ + return Property::INVALID_INDEX; +} + +void Control::Impl::PositionOrSizeChangedCallback( PropertyNotification &p ) +{ + auto self = Dali::Actor::DownCast(p.GetTarget()); + if (Dali::Accessibility::IsUp() && !self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED ).Get< bool >()) + { + auto extents = DevelActor::CalculateScreenExtents( self ); + Dali::Accessibility::Accessible::Get( self )->EmitBoundsChanged( extents ); + } +} + +void Control::Impl::CulledChangedCallback( PropertyNotification &p) +{ + if (Dali::Accessibility::IsUp()) + { + auto self = Dali::Actor::DownCast(p.GetTarget()); + Dali::Accessibility::Accessible::Get(self)->EmitShowing( !self.GetProperty( DevelActor::Property::CULLED ).Get() ); + } +} + +void Control::Impl::AccessibilityRegister() +{ + if (!accessibilityNotificationSet) + { + accessibilityNotificationPosition = mControlImpl.Self().AddPropertyNotification( Actor::Property::POSITION, StepCondition( 0.01f ) ); + accessibilityNotificationPosition.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED ); + accessibilityNotificationPosition.NotifySignal().Connect( &Control::Impl::PositionOrSizeChangedCallback ); + + accessibilityNotificationSize = mControlImpl.Self().AddPropertyNotification( Actor::Property::SIZE, StepCondition( 0.01f ) ); + accessibilityNotificationSize.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED ); + accessibilityNotificationSize.NotifySignal().Connect( &Control::Impl::PositionOrSizeChangedCallback ); + + accessibilityNotificationCulled = mControlImpl.Self().AddPropertyNotification( DevelActor::Property::CULLED, LessThanCondition( 0.5f ) ); + accessibilityNotificationCulled.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED ); + accessibilityNotificationCulled.NotifySignal().Connect( &Control::Impl::CulledChangedCallback ); + + accessibilityNotificationSet = true; + } +} + +void Control::Impl::AccessibilityDeregister() +{ + if (accessibilityNotificationSet) + { + accessibilityNotificationPosition = {}; + accessibilityNotificationSize = {}; + accessibilityNotificationCulled = {}; + accessibilityNotificationSet = false; + } } } // namespace Internal