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=9e69f95540e5b0c2e94ccb20c68c94fb384edbca;hp=5e94e8f4a33aee4daf994133241fc462528fd81c;hb=2676a40c6aa784628b20c42052bae09e66284b88;hpb=3ca7994488b0b5e21bbb0d262c5fa2e4c731308b diff --git a/dali-toolkit/internal/controls/control/control-data-impl.cpp b/dali-toolkit/internal/controls/control/control-data-impl.cpp old mode 100755 new mode 100644 index 5e94e8f..9e69f95 --- 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) 2021 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. @@ -19,94 +19,107 @@ #include "control-data-impl.h" // EXTERNAL INCLUDES +#include +#include #include -#include +#include +#include +#include #include #include #include +#include #include +#include #include #include #include // INTERNAL INCLUDES -#include -#include -#include +#include #include #include #include -#include -#include #include +#include #include +#include +#include +#include +#include -namespace Dali +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 +namespace Dali +{ namespace Toolkit { - namespace Internal { - extern const Dali::Scripting::StringEnum ControlStateTable[]; -extern const unsigned int ControlStateTableCount; - +extern const unsigned int ControlStateTableCount; // Not static or anonymous - shared with other translation units const Scripting::StringEnum ControlStateTable[] = { - { "NORMAL", Toolkit::DevelControl::NORMAL }, - { "FOCUSED", Toolkit::DevelControl::FOCUSED }, - { "DISABLED", Toolkit::DevelControl::DISABLED }, + {"NORMAL", Toolkit::DevelControl::NORMAL}, + {"FOCUSED", Toolkit::DevelControl::FOCUSED}, + {"DISABLED", Toolkit::DevelControl::DISABLED}, }; -const unsigned int ControlStateTableCount = sizeof( ControlStateTable ) / sizeof( ControlStateTable[0] ); - - +const unsigned int ControlStateTableCount = sizeof(ControlStateTable) / sizeof(ControlStateTable[0]); 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"); +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_VISUALS"); #endif - template -void Remove( Dictionary& keyValues, const std::string& name ) +void Remove(Dictionary& keyValues, const std::string& name) { keyValues.Remove(name); } -void Remove( DictionaryKeys& keys, const std::string& name ) +void Remove(DictionaryKeys& keys, const std::string& name) { - DictionaryKeys::iterator iter = std::find( keys.begin(), keys.end(), name ); - if( iter != keys.end()) + DictionaryKeys::iterator iter = std::find(keys.begin(), keys.end(), name); + if(iter != keys.end()) { keys.erase(iter); } } -Toolkit::Visual::Type GetVisualTypeFromMap( const Property::Map& map ) +/** + * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter + */ +bool FindVisual(Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter) { - Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE ); - Toolkit::Visual::Type type = Toolkit::Visual::IMAGE; - if( typeValue ) + for(iter = visuals.Begin(); iter != visuals.End(); iter++) { - Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, type ); + if((*iter)->index == targetIndex) + { + return true; + } } - return type; + return false; } /** * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter */ -bool FindVisual( Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter ) +bool FindVisual(std::string visualName, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter) { - for ( iter = visuals.Begin(); iter != visuals.End(); iter++ ) + for(iter = visuals.Begin(); iter != visuals.End(); iter++) { - if ( (*iter)->index == targetIndex ) + Toolkit::Visual::Base visual = (*iter)->visual; + if(visual && visual.GetName() == visualName) { return true; } @@ -114,37 +127,38 @@ bool FindVisual( Property::Index targetIndex, const RegisteredVisualContainer& v return false; } -void FindChangableVisuals( Dictionary& stateVisualsToAdd, - Dictionary& stateVisualsToChange, - DictionaryKeys& stateVisualsToRemove) +void FindChangableVisuals(Dictionary& stateVisualsToAdd, + Dictionary& stateVisualsToChange, + DictionaryKeys& stateVisualsToRemove) { DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove; - for( DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin(); - iter != copyOfStateVisualsToRemove.end(); ++iter ) + for(DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin(); + iter != copyOfStateVisualsToRemove.end(); + ++iter) { const std::string& visualName = (*iter); - Property::Map* toMap = stateVisualsToAdd.Find( visualName ); - if( toMap ) + Property::Map* toMap = stateVisualsToAdd.Find(visualName); + if(toMap) { - stateVisualsToChange.Add( visualName, *toMap ); - stateVisualsToAdd.Remove( visualName ); - Remove( stateVisualsToRemove, visualName ); + stateVisualsToChange.Add(visualName, *toMap); + stateVisualsToAdd.Remove(visualName); + Remove(stateVisualsToRemove, visualName); } } } Toolkit::Visual::Base GetVisualByName( const RegisteredVisualContainer& visuals, - const std::string& visualName ) + const std::string& visualName) { Toolkit::Visual::Base visualHandle; RegisteredVisualContainer::Iterator iter; - for ( iter = visuals.Begin(); iter != visuals.End(); iter++ ) + for(iter = visuals.Begin(); iter != visuals.End(); iter++) { Toolkit::Visual::Base visual = (*iter)->visual; - if( visual && visual.GetName() == visualName ) + if(visual && visual.GetName() == visualName) { visualHandle = visual; break; @@ -153,17 +167,35 @@ Toolkit::Visual::Base GetVisualByName( return visualHandle; } +Toolkit::Visual::Base GetVisualByIndex( + const RegisteredVisualContainer& visuals, + Property::Index index) +{ + Toolkit::Visual::Base visualHandle; + + RegisteredVisualContainer::Iterator iter; + for(iter = visuals.Begin(); iter != visuals.End(); iter++) + { + if((*iter)->index == index) + { + visualHandle = (*iter)->visual; + break; + } + } + return visualHandle; +} + /** * Move visual from source to destination container */ -void MoveVisual( RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination ) +void MoveVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination) { - Toolkit::Visual::Base visual = (*sourceIter)->visual; - if( visual ) - { - RegisteredVisual* rv = source.Release( sourceIter ); - destination.PushBack( rv ); - } + Toolkit::Visual::Base visual = (*sourceIter)->visual; + if(visual) + { + RegisteredVisual* rv = source.Release(sourceIter); + destination.PushBack(rv); + } } /** @@ -173,21 +205,66 @@ 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"; -static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes ) +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); + + Toolkit::Control control = Toolkit::Control::DownCast(handle); - if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) ) + 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; } @@ -200,55 +277,70 @@ static bool DoAction( BaseObject* object, const std::string& actionName, const P * @return True if the signal was connected. * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor. */ -const char* SIGNAL_KEY_EVENT = "keyEvent"; +const char* SIGNAL_KEY_EVENT = "keyEvent"; const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained"; -const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost"; -const char* SIGNAL_TAPPED = "tapped"; -const char* SIGNAL_PANNED = "panned"; -const char* SIGNAL_PINCHED = "pinched"; -const char* SIGNAL_LONG_PRESSED = "longPressed"; -static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) +const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost"; +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 ); + Dali::BaseHandle handle(object); - bool connected( false ); - Toolkit::Control control = Toolkit::Control::DownCast( handle ); - if ( control ) + bool connected(false); + Toolkit::Control control = Toolkit::Control::DownCast(handle); + if(control) { - Internal::Control& controlImpl( Internal::GetImplementation( control ) ); + Internal::Control& controlImpl(Internal::GetImplementation(control)); connected = true; - if ( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) ) + if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_EVENT)) + { + controlImpl.KeyEventSignal().Connect(tracker, functor); + } + else if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED)) + { + controlImpl.KeyInputFocusGainedSignal().Connect(tracker, functor); + } + else if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST)) + { + controlImpl.KeyInputFocusLostSignal().Connect(tracker, functor); + } + else if(0 == strcmp(signalName.c_str(), SIGNAL_TAPPED)) { - controlImpl.KeyEventSignal().Connect( tracker, functor ); + controlImpl.EnableGestureDetection(GestureType::TAP); + controlImpl.GetTapGestureDetector().DetectedSignal().Connect(tracker, functor); } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED ) ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_PANNED)) { - controlImpl.KeyInputFocusGainedSignal().Connect( tracker, functor ); + controlImpl.EnableGestureDetection(GestureType::PAN); + controlImpl.GetPanGestureDetector().DetectedSignal().Connect(tracker, functor); } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST ) ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_PINCHED)) { - controlImpl.KeyInputFocusLostSignal().Connect( tracker, functor ); + controlImpl.EnableGestureDetection(GestureType::PINCH); + controlImpl.GetPinchGestureDetector().DetectedSignal().Connect(tracker, functor); } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_LONG_PRESSED)) { - controlImpl.EnableGestureDetection( Gesture::Tap ); - controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor ); + controlImpl.EnableGestureDetection(GestureType::LONG_PRESS); + controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect(tracker, functor); } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_GET_NAME)) { - controlImpl.EnableGestureDetection( Gesture::Pan ); - controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor ); + DevelControl::AccessibilityGetNameSignal(control).Connect(tracker, functor); } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_GET_DESCRIPTION)) { - controlImpl.EnableGestureDetection( Gesture::Pinch ); - controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor ); + DevelControl::AccessibilityGetDescriptionSignal(control).Connect(tracker, functor); } - else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_DO_GESTURE)) { - controlImpl.EnableGestureDetection( Gesture::LongPress ); - controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor ); + DevelControl::AccessibilityDoGestureSignal(control).Connect(tracker, functor); } } return connected; @@ -262,103 +354,155 @@ BaseHandle Create() return Internal::Control::New(); } // Setup signals and actions using the type-registry. -DALI_TYPE_REGISTRATION_BEGIN( Control, CustomActor, Create ); +DALI_TYPE_REGISTRATION_BEGIN(Control, CustomActor, Create); // Note: Properties are registered separately below. -SignalConnectorType registerSignal1( typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal ); -SignalConnectorType registerSignal2( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal ); -SignalConnectorType registerSignal3( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal ); -SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnectSignal ); -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 registerSignal1(typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal); +SignalConnectorType registerSignal2(typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal); +SignalConnectorType registerSignal3(typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal); +SignalConnectorType registerSignal4(typeRegistration, SIGNAL_TAPPED, &DoConnectSignal); +SignalConnectorType registerSignal5(typeRegistration, SIGNAL_PANNED, &DoConnectSignal); +SignalConnectorType registerSignal6(typeRegistration, SIGNAL_PINCHED, &DoConnectSignal); +SignalConnectorType registerSignal7(typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal); +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++) + for(auto iter = container.Begin(), end = container.End(); iter != end; iter++) { - if( (*iter)->visual ) + 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); } } } } // unnamed namespace - +// clang-format off // 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 ); -const PropertyRegistration Control::Impl::PROPERTY_7( typeRegistration, "padding", Toolkit::Control::Property::PADDING, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); -const PropertyRegistration Control::Impl::PROPERTY_8( typeRegistration, "tooltip", Toolkit::DevelControl::Property::TOOLTIP, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); -const PropertyRegistration Control::Impl::PROPERTY_9( typeRegistration, "state", Toolkit::DevelControl::Property::STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); -const PropertyRegistration Control::Impl::PROPERTY_10( typeRegistration, "subState", Toolkit::DevelControl::Property::SUB_STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); -const PropertyRegistration Control::Impl::PROPERTY_11( typeRegistration, "leftFocusableActorId", Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); -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 ); - - -Control::Impl::Impl( Control& controlImpl ) -: mControlImpl( controlImpl ), - mState( Toolkit::DevelControl::NORMAL ), +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_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); +const PropertyRegistration Control::Impl::PROPERTY_7(typeRegistration, "padding", Toolkit::Control::Property::PADDING, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_8(typeRegistration, "tooltip", Toolkit::DevelControl::Property::TOOLTIP, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_9(typeRegistration, "state", Toolkit::DevelControl::Property::STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_10(typeRegistration, "subState", Toolkit::DevelControl::Property::SUB_STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_11(typeRegistration, "leftFocusableActorId", Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +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); +// clang-format on + +Control::Impl::Impl(Control& controlImpl) +: mControlImpl(controlImpl), + mState(Toolkit::DevelControl::NORMAL), mSubStateName(""), - mLayout( NULL ), - mLeftFocusableActorId( -1 ), - mRightFocusableActorId( -1 ), - mUpFocusableActorId( -1 ), - mDownFocusableActorId( -1 ), + mLeftFocusableActorId(-1), + mRightFocusableActorId(-1), + mUpFocusableActorId(-1), + mDownFocusableActorId(-1), mStyleName(""), mBackgroundColor(Color::TRANSPARENT), - mStartingPinchScale( NULL ), - mMargin( 0, 0, 0, 0 ), - mPadding( 0, 0, 0, 0 ), + 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 ), + mTooltip(NULL), mInputMethodContext(), - mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ), - mIsKeyboardNavigationSupported( false ), - mIsKeyboardFocusGroup( false ), - mIsLayoutingRequired( false ) + mIdleCallback(nullptr), + mFlags(Control::ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)), + mIsKeyboardNavigationSupported(false), + mIsKeyboardFocusGroup(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 { + return std::unique_ptr(new DevelControl::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); + } + // 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 ) +Control::Impl& Control::Impl::Get(Internal::Control& internalControl) { return *internalControl.mImpl; } -const Control::Impl& Control::Impl::Get( const Internal::Control& internalControl ) +const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl) { return *internalControl.mImpl; } @@ -384,86 +528,86 @@ void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longP mControlImpl.OnLongPress(longPress); } -void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual ) +void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual) { - RegisterVisual( index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET ); + RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET); } -void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, int depthIndex ) +void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex) { - RegisterVisual( index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex ); + RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex); } -void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled ) +void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled) { - RegisterVisual( index, visual, ( enabled ? VisualState::ENABLED : VisualState::DISABLED ), DepthIndexValue::NOT_SET ); + RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::NOT_SET); } -void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex ) +void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex) { - RegisterVisual( index, visual, ( enabled ? VisualState::ENABLED : VisualState::DISABLED ), DepthIndexValue::SET, depthIndex ); + RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::SET, depthIndex); } -void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex ) +void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex) { - DALI_LOG_INFO( gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index ); + DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index); - bool visualReplaced ( false ); + bool visualReplaced(false); Actor self = mControlImpl.Self(); // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals // or zero. int requiredDepthIndex = visual.GetDepthIndex(); - if( depthIndexValueSet == DepthIndexValue::SET ) + if(depthIndexValueSet == DepthIndexValue::SET) { requiredDepthIndex = depthIndex; } // Visual replacement, existing visual should only be removed from stage when replacement ready. - if( !mVisuals.Empty() ) + if(!mVisuals.Empty()) { RegisteredVisualContainer::Iterator registeredVisualsiter; // Check if visual (index) is already registered, this is the current visual. - if( FindVisual( index, mVisuals, registeredVisualsiter ) ) + if(FindVisual(index, mVisuals, registeredVisualsiter)) { Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual; - if( currentRegisteredVisual ) + if(currentRegisteredVisual) { // Store current visual depth index as may need to set the replacement visual to same depth const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex(); // No longer required to know if the replaced visual's resources are ready - StopObservingVisual( currentRegisteredVisual ); + StopObservingVisual(currentRegisteredVisual); // If control staged and visual enabled then visuals will be swapped once ready - if( self.OnStage() && enabled ) + if(self.GetProperty(Actor::Property::CONNECTED_TO_SCENE) && enabled) { // Check if visual is currently in the process of being replaced ( is in removal container ) RegisteredVisualContainer::Iterator visualQueuedForRemoval; - if ( FindVisual( index, mRemoveVisuals, visualQueuedForRemoval ) ) + if(FindVisual(index, mRemoveVisuals, visualQueuedForRemoval)) { // 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 ); - mVisuals.Erase( registeredVisualsiter ); + Toolkit::GetImplementation(currentRegisteredVisual).SetOffScene(self); + mVisuals.Erase(registeredVisualsiter); } else { // current visual not already in removal container so add now. - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index ); - MoveVisual( registeredVisualsiter, mVisuals, mRemoveVisuals ); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index); + MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals); } } else { // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later. - mVisuals.Erase( registeredVisualsiter ); + mVisuals.Erase(registeredVisualsiter); } // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index - if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) && - ( visual.GetDepthIndex() == 0 ) ) + if((depthIndexValueSet == DepthIndexValue::NOT_SET) && + (visual.GetDepthIndex() == 0)) { requiredDepthIndex = currentDepthIndex; } @@ -475,100 +619,96 @@ void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base // If not set, set the name of the visual to the same name as the control's property. // ( If the control has been type registered ) - if( visual.GetName().empty() ) + if(visual.GetName().empty()) { // 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 ); + DALI_LOG_INFO(gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", index, visualName.c_str()); + visual.SetName(visualName); } } - if( !visualReplaced ) // New registration entry + if(!visualReplaced) // New registration entry { // If we've not set the depth-index value, we have more than one visual and the visual does not have a depth index, then set it to be the highest - if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) && - ( mVisuals.Size() > 0 ) && - ( visual.GetDepthIndex() == 0 ) ) + if((depthIndexValueSet == DepthIndexValue::NOT_SET) && + (mVisuals.Size() > 0) && + (visual.GetDepthIndex() == 0)) { - int maxDepthIndex = std::numeric_limits< int >::min(); + int maxDepthIndex = std::numeric_limits::min(); - RegisteredVisualContainer::ConstIterator iter; + RegisteredVisualContainer::ConstIterator iter; const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End(); - for ( iter = mVisuals.Begin(); iter != endIter; iter++ ) + for(iter = mVisuals.Begin(); iter != endIter; iter++) { const int visualDepthIndex = (*iter)->visual.GetDepthIndex(); - if ( visualDepthIndex > maxDepthIndex ) + if(visualDepthIndex > maxDepthIndex) { maxDepthIndex = visualDepthIndex; } } - ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top - requiredDepthIndex = std::max( 0, maxDepthIndex ); // Start at zero if maxDepth index belongs to a background + ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top + requiredDepthIndex = std::max(0, maxDepthIndex); // Start at zero if maxDepth index belongs to a background } } - if( visual ) + if(visual) { // Set determined depth index - visual.SetDepthIndex( requiredDepthIndex ); + visual.SetDepthIndex(requiredDepthIndex); // Monitor when the visual resources are ready - StartObservingVisual( visual ); + StartObservingVisual(visual); - DALI_LOG_INFO( gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex ); - RegisteredVisual* newRegisteredVisual = new RegisteredVisual( index, visual, - ( enabled == VisualState::ENABLED ? true : false ), - ( visualReplaced && enabled ) ) ; - mVisuals.PushBack( newRegisteredVisual ); + DALI_LOG_INFO(gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex); + RegisteredVisual* newRegisteredVisual = new RegisteredVisual(index, visual, (enabled == VisualState::ENABLED ? true : false), (visualReplaced && enabled)); + mVisuals.PushBack(newRegisteredVisual); - Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual ); + 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(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 ) + else if(visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already ) { - ResourceReady( visualImpl ); + ResourceReady(visualImpl); } - } - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled?"true":"false" ); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled ? "true" : "false"); } -void Control::Impl::UnregisterVisual( Property::Index index ) +void Control::Impl::UnregisterVisual(Property::Index index) { RegisteredVisualContainer::Iterator iter; - if ( FindVisual( index, mVisuals, iter ) ) + if(FindVisual(index, mVisuals, iter)) { // stop observing visual - StopObservingVisual( (*iter)->visual ); + StopObservingVisual((*iter)->visual); - Actor self( mControlImpl.Self() ); - Toolkit::GetImplementation((*iter)->visual).SetOffStage( self ); + Actor self(mControlImpl.Self()); + Toolkit::GetImplementation((*iter)->visual).SetOffScene(self); (*iter)->visual.Reset(); - mVisuals.Erase( iter ); + mVisuals.Erase(iter); } - if( FindVisual( index, mRemoveVisuals, iter ) ) + if(FindVisual(index, mRemoveVisuals, iter)) { - Actor self( mControlImpl.Self() ); - Toolkit::GetImplementation( (*iter)->visual ).SetOffStage( self ); + Actor self(mControlImpl.Self()); + Toolkit::GetImplementation((*iter)->visual).SetOffScene(self); (*iter)->pending = false; (*iter)->visual.Reset(); - mRemoveVisuals.Erase( iter ); + mRemoveVisuals.Erase(iter); } } -Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const +Toolkit::Visual::Base Control::Impl::GetVisual(Property::Index index) const { RegisteredVisualContainer::Iterator iter; - if ( FindVisual( index, mVisuals, iter ) ) + if(FindVisual(index, mVisuals, iter)) { return (*iter)->visual; } @@ -576,121 +716,138 @@ Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const return Toolkit::Visual::Base(); } -void Control::Impl::EnableVisual( Property::Index index, bool enable ) +void Control::Impl::EnableVisual(Property::Index index, bool enable) { - DALI_LOG_INFO( gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable?"T":"F"); + DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable ? "T" : "F"); RegisteredVisualContainer::Iterator iter; - if ( FindVisual( index, mVisuals, iter ) ) + if(FindVisual(index, mVisuals, iter)) { - if ( (*iter)->enabled == enable ) + if((*iter)->enabled == enable) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable?"enabled":"disabled"); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable ? "enabled" : "disabled"); return; } - (*iter)->enabled = 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(Actor::Property::CONNECTED_TO_SCENE)) // If control not on Scene then Visual will be added when SceneConnection is called. { - if ( enable ) + 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 ); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index); + 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. + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index); + Toolkit::GetImplementation((*iter)->visual).SetOffScene(parentActor); // No need to call if control not staged. } } } else { - DALI_LOG_WARNING( "Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable?"T":"F" ); + DALI_LOG_WARNING("Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable ? "T" : "F"); } } -bool Control::Impl::IsVisualEnabled( Property::Index index ) const +bool Control::Impl::IsVisualEnabled(Property::Index index) const { RegisteredVisualContainer::Iterator iter; - if ( FindVisual( index, mVisuals, iter ) ) + if(FindVisual(index, mVisuals, iter)) { return (*iter)->enabled; } return false; } -void Control::Impl::StopObservingVisual( Toolkit::Visual::Base& visual ) +void Control::Impl::StopObservingVisual(Toolkit::Visual::Base& visual) { - Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( 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) +void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual) { - Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( 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 -void Control::Impl::ResourceReady( Visual::Base& object) +void Control::Impl::ResourceReady(Visual::Base& object) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count() ); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count()); Actor self = mControlImpl.Self(); // A resource is ready, find resource in the registered visuals container and get its index - for( auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter ) + for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter) { - Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation( (*registeredIter)->visual ); + Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual); - if( &object == ®isteredVisualImpl ) + if(&object == ®isteredVisualImpl) { RegisteredVisualContainer::Iterator visualToRemoveIter; // Find visual with the same index in the removal container // Set if off stage as it's replacement is now ready. // Remove if from removal list as now removed from stage. // Set Pending flag on the ready visual to false as now ready. - if( FindVisual( (*registeredIter)->index, mRemoveVisuals, visualToRemoveIter ) ) + if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter)) { (*registeredIter)->pending = false; - Toolkit::GetImplementation( (*visualToRemoveIter)->visual ).SetOffStage( self ); - mRemoveVisuals.Erase( visualToRemoveIter ); + Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self); + mRemoveVisuals.Erase(visualToRemoveIter); } break; } } // A visual is ready so control may need relayouting if staged - if ( self.OnStage() ) + if(self.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) { mControlImpl.RelayoutRequest(); } // Emit signal if all enabled visuals registered by the control are ready. - if( IsResourceReady() ) + 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; + } } } bool Control::Impl::IsResourceReady() const { // Iterate through and check all the enabled visuals are ready - for( auto visualIter = mVisuals.Begin(); - visualIter != mVisuals.End(); ++visualIter ) + for(auto visualIter = mVisuals.Begin(); + visualIter != mVisuals.End(); + ++visualIter) { - const Toolkit::Visual::Base visual = (*visualIter)->visual; - const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual ); + const Toolkit::Visual::Base visual = (*visualIter)->visual; + const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); // one of the enabled visuals is not ready - if( !visualImpl.IsResourceReady() && (*visualIter)->enabled ) + if(!visualImpl.IsResourceReady() && (*visualIter)->enabled) { return false; } @@ -698,85 +855,83 @@ bool Control::Impl::IsResourceReady() const return true; } -Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus( Property::Index index ) const +Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus(Property::Index index) const { RegisteredVisualContainer::Iterator iter; - if ( FindVisual( index, mVisuals, iter ) ) + if(FindVisual(index, mVisuals, iter)) { - const Toolkit::Visual::Base visual = (*iter)->visual; - const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual ); - return visualImpl.GetResourceStatus( ); + const Toolkit::Visual::Base visual = (*iter)->visual; + const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); + return visualImpl.GetResourceStatus(); } return Toolkit::Visual::ResourceStatus::PREPARING; } - - -void Control::Impl::AddTransitions( Dali::Animation& animation, - const Toolkit::TransitionData& handle, - bool createAnimation ) +void Control::Impl::AddTransitions(Dali::Animation& animation, + const Toolkit::TransitionData& handle, + bool createAnimation) { // Setup a Transition from TransitionData. - const Internal::TransitionData& transitionData = Toolkit::GetImplementation( handle ); - TransitionData::Iterator end = transitionData.End(); - for( TransitionData::Iterator iter = transitionData.Begin() ; - iter != end; ++iter ) + const Internal::TransitionData& transitionData = Toolkit::GetImplementation(handle); + TransitionData::Iterator end = transitionData.End(); + for(TransitionData::Iterator iter = transitionData.Begin(); + iter != end; + ++iter) { TransitionData::Animator* animator = (*iter); - Toolkit::Visual::Base visual = GetVisualByName( mVisuals, animator->objectName ); + Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName); - if( visual ) + if(visual) { #if defined(DEBUG_ENABLED) - Dali::TypeInfo typeInfo; + Dali::TypeInfo typeInfo; ControlWrapper* controlWrapperImpl = dynamic_cast(&mControlImpl); - if( controlWrapperImpl ) + if(controlWrapperImpl) { typeInfo = controlWrapperImpl->GetTypeInfo(); } - DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n", - visual.GetName().c_str(), typeInfo?typeInfo.GetName().c_str():"Unknown" ); + DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n", visual.GetName().c_str(), typeInfo ? typeInfo.GetName().c_str() : "Unknown"); #endif - Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual ); - visualImpl.AnimateProperty( animation, *animator ); + Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); + visualImpl.AnimateProperty(animation, *animator); } else { - DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors"); + DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors"); // Otherwise, try any actor children of control (Including the control) - Actor child = mControlImpl.Self().FindChildByName( animator->objectName ); - if( child ) + Actor child = mControlImpl.Self().FindChildByName(animator->objectName); + if(child) { - Property::Index propertyIndex = DevelHandle::GetPropertyIndex( child, animator->propertyKey ); - if( propertyIndex != Property::INVALID_INDEX ) + Property::Index propertyIndex = child.GetPropertyIndex(animator->propertyKey); + if(propertyIndex != Property::INVALID_INDEX) { - if( animator->animate == false ) + if(animator->animate == false) { - if( animator->targetValue.GetType() != Property::NONE ) + if(animator->targetValue.GetType() != Property::NONE) { - child.SetProperty( propertyIndex, animator->targetValue ); + child.SetProperty(propertyIndex, animator->targetValue); } } else // animate the property { - if( animator->initialValue.GetType() != Property::NONE ) + if(animator->initialValue.GetType() != Property::NONE) { - child.SetProperty( propertyIndex, animator->initialValue ); + child.SetProperty(propertyIndex, animator->initialValue); } - if( createAnimation && !animation ) + if(createAnimation && !animation) { - animation = Dali::Animation::New( 0.1f ); + animation = Dali::Animation::New(0.1f); } - animation.AnimateTo( Property( child, propertyIndex ), - animator->targetValue, - animator->alphaFunction, - TimePeriod( animator->timePeriodDelay, - animator->timePeriodDuration ) ); + animation.AnimateTo(Property(child, propertyIndex), + animator->targetValue, + animator->alphaFunction, + TimePeriod(animator->timePeriodDelay, + animator->timePeriodDuration)); } } } @@ -784,53 +939,65 @@ void Control::Impl::AddTransitions( Dali::Animation& animation, } } -Dali::Animation Control::Impl::CreateTransition( const Toolkit::TransitionData& transitionData ) +Dali::Animation Control::Impl::CreateTransition(const Toolkit::TransitionData& transitionData) { Dali::Animation transition; - if( transitionData.Count() > 0 ) + if(transitionData.Count() > 0) { - AddTransitions( transition, transitionData, true ); + AddTransitions(transition, transitionData, true); } return transition; } - - -void Control::Impl::DoAction( Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes ) +void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes) { RegisteredVisualContainer::Iterator iter; - if ( FindVisual( visualIndex, mVisuals, iter ) ) + if(FindVisual(visualIndex, mVisuals, iter)) + { + Toolkit::GetImplementation((*iter)->visual).DoAction(actionId, attributes); + } +} + +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 { - Toolkit::GetImplementation((*iter)->visual).DoAction( actionId, attributes ); + mAccessibilityAttributes.Insert(key, value); } } -void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) +void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value) { - Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) ); + Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object)); - if ( control ) + if(control) { - Control& controlImpl( GetImplementation( control ) ); + Control& controlImpl(GetImplementation(control)); - switch ( index ) + switch(index) { case Toolkit::Control::Property::STYLE_NAME: { - controlImpl.SetStyleName( value.Get< std::string >() ); + controlImpl.SetStyleName(value.Get()); break; } case Toolkit::DevelControl::Property::STATE: { - bool withTransitions=true; - const Property::Value* valuePtr=&value; - Property::Map* map = value.GetMap(); + bool withTransitions = true; + const Property::Value* valuePtr = &value; + const Property::Map* map = value.GetMap(); if(map) { Property::Value* value2 = map->Find("withTransitions"); - if( value2 ) + if(value2) { withTransitions = value2->Get(); } @@ -838,12 +1005,12 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons valuePtr = map->Find("state"); } - if( valuePtr ) + if(valuePtr) { - Toolkit::DevelControl::State state( controlImpl.mImpl->mState ); - if( Scripting::GetEnumerationProperty< Toolkit::DevelControl::State >( *valuePtr, ControlStateTable, ControlStateTableCount, state ) ) + Toolkit::DevelControl::State state(controlImpl.mImpl->mState); + if(Scripting::GetEnumerationProperty(*valuePtr, ControlStateTable, ControlStateTableCount, state)) { - controlImpl.mImpl->SetState( state, withTransitions ); + controlImpl.mImpl->SetState(state, withTransitions); } } } @@ -852,9 +1019,9 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons case Toolkit::DevelControl::Property::SUB_STATE: { std::string subState; - if( value.Get( subState ) ) + if(value.Get(subState)) { - controlImpl.mImpl->SetSubState( subState ); + controlImpl.mImpl->SetSubState(subState); } } break; @@ -862,7 +1029,7 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID: { int focusId; - if( value.Get( focusId ) ) + if(value.Get(focusId)) { controlImpl.mImpl->mLeftFocusableActorId = focusId; } @@ -872,59 +1039,106 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID: { int focusId; - if( value.Get( focusId ) ) + if(value.Get(focusId)) { controlImpl.mImpl->mRightFocusableActorId = focusId; } } 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; + + 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; } + break; case Toolkit::Control::Property::KEY_INPUT_FOCUS: { - if ( value.Get< bool >() ) + if(value.Get()) { controlImpl.SetKeyInputFocus(); } @@ -937,23 +1151,23 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons case Toolkit::Control::Property::BACKGROUND: { - std::string url; - Vector4 color; + std::string url; + Vector4 color; const Property::Map* map = value.GetMap(); - if( map && !map->Empty() ) + if(map && !map->Empty()) { - controlImpl.SetBackground( *map ); + controlImpl.SetBackground(*map); } - else if( value.Get( url ) ) + else if(value.Get(url)) { // don't know the size to load - Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, ImageDimensions() ); - if( visual ) + Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, ImageDimensions()); + if(visual) { - controlImpl.mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND ); + controlImpl.mImpl->RegisterVisual(Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND); } } - else if( value.Get( color ) ) + else if(value.Get(color)) { controlImpl.SetBackgroundColor(color); } @@ -968,9 +1182,9 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons case Toolkit::Control::Property::MARGIN: { Extents margin; - if( value.Get( margin ) ) + if(value.Get(margin)) { - controlImpl.mImpl->SetMargin( margin ); + controlImpl.mImpl->SetMargin(margin); } break; } @@ -978,9 +1192,9 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons case Toolkit::Control::Property::PADDING: { Extents padding; - if( value.Get( padding ) ) + if(value.Get(padding)) { - controlImpl.mImpl->SetPadding( padding ); + controlImpl.mImpl->SetPadding(padding); } break; } @@ -988,29 +1202,63 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons case Toolkit::DevelControl::Property::TOOLTIP: { TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip; - if( ! tooltipPtr ) + if(!tooltipPtr) + { + tooltipPtr = Tooltip::New(control); + } + tooltipPtr->SetProperties(value); + break; + } + + case Toolkit::DevelControl::Property::SHADOW: + { + const Property::Map* map = value.GetMap(); + if(map && !map->Empty()) { - tooltipPtr = Tooltip::New( control ); + controlImpl.mImpl->SetShadow(*map); + } + else + { + // The shadow is an empty property map, so we should clear the shadow + controlImpl.mImpl->ClearShadow(); } - tooltipPtr->SetProperties( value ); 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; + } } } } -Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index index ) +Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index index) { Property::Value value; - Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) ); + Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object)); - if ( control ) + if(control) { - Control& controlImpl( GetImplementation( control ) ); + Control& controlImpl(GetImplementation(control)); - switch ( index ) + switch(index) { case Toolkit::Control::Property::STYLE_NAME: { @@ -1042,35 +1290,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; } @@ -1082,11 +1352,11 @@ Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index case Toolkit::Control::Property::BACKGROUND: { - Property::Map map; - Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND ); - if( visual ) + Property::Map map; + Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND); + if(visual) { - visual.CreatePropertyMap( map ); + visual.CreatePropertyMap(map); } value = map; @@ -1108,193 +1378,294 @@ Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index case Toolkit::DevelControl::Property::TOOLTIP: { Property::Map map; - if( controlImpl.mImpl->mTooltip ) + if(controlImpl.mImpl->mTooltip) { - controlImpl.mImpl->mTooltip->CreatePropertyMap( map ); + controlImpl.mImpl->mTooltip->CreatePropertyMap(map); } 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::CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary& instancedProperties ) +void Control::Impl::ClearAccessibilityAttributes() { - for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter!= visuals.End(); iter++) + 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( (*iter)->visual ) + 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); + } + else + { + Dali::Accessibility::ReadingInfoTypes types; + types[Dali::Accessibility::ReadingInfoType::NAME] = true; + types[Dali::Accessibility::ReadingInfoType::ROLE] = true; + types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true; + types[Dali::Accessibility::ReadingInfoType::STATE] = true; + return types; + } + + 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) +{ + for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter != visuals.End(); iter++) + { + if((*iter)->visual) { Property::Map instanceMap; Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap); - instancedProperties.Add( (*iter)->visual.GetName(), instanceMap ); + instancedProperties.Add((*iter)->visual.GetName(), instanceMap); } } } - -void Control::Impl::RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName ) +void Control::Impl::RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName) { - Actor self( mControlImpl.Self() ); + Actor self(mControlImpl.Self()); - for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin(); - visualIter != visuals.End(); ++visualIter ) + for(RegisteredVisualContainer::Iterator visualIter = visuals.Begin(); + visualIter != visuals.End(); + ++visualIter) { Toolkit::Visual::Base visual = (*visualIter)->visual; - if( visual && visual.GetName() == visualName ) + if(visual && visual.GetName() == visualName) { - Toolkit::GetImplementation(visual).SetOffStage( self ); + Toolkit::GetImplementation(visual).SetOffScene(self); (*visualIter)->visual.Reset(); - visuals.Erase( visualIter ); + visuals.Erase(visualIter); break; } } } -void Control::Impl::RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals ) +void Control::Impl::RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals) { - Actor self( mControlImpl.Self() ); - for( DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter ) + Actor self(mControlImpl.Self()); + for(DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter) { const std::string visualName = *iter; - RemoveVisual( visuals, visualName ); + RemoveVisual(visuals, visualName); } } -void Control::Impl::RecreateChangedVisuals( Dictionary& stateVisualsToChange, - Dictionary& instancedProperties ) +void Control::Impl::RecreateChangedVisuals(Dictionary& stateVisualsToChange, + Dictionary& instancedProperties) { - Dali::CustomActor handle( mControlImpl.GetOwner() ); - for( Dictionary::iterator iter = stateVisualsToChange.Begin(); - iter != stateVisualsToChange.End(); ++iter ) + Dali::CustomActor handle(mControlImpl.GetOwner()); + for(Dictionary::iterator iter = stateVisualsToChange.Begin(); + iter != stateVisualsToChange.End(); + ++iter) { - const std::string& visualName = (*iter).key; - const Property::Map& toMap = (*iter).entry; - - // is it a candidate for re-creation? - bool recreate = false; + const std::string& visualName = (*iter).key; + const Property::Map& toMap = (*iter).entry; - Toolkit::Visual::Base visual = GetVisualByName( mVisuals, visualName ); - if( visual ) + Actor self = mControlImpl.Self(); + RegisteredVisualContainer::Iterator registeredVisualsiter; + // Check if visual (visualName) is already registered, this is the current visual. + if(FindVisual(visualName, mVisuals, registeredVisualsiter)) { - Property::Map fromMap; - visual.CreatePropertyMap( fromMap ); - - Toolkit::Visual::Type fromType = GetVisualTypeFromMap( fromMap ); - Toolkit::Visual::Type toType = GetVisualTypeFromMap( toMap ); - - if( fromType != toType ) + Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual; + if(visual) { - recreate = true; - } - else - { - if( fromType == Toolkit::Visual::IMAGE || fromType == Toolkit::Visual::N_PATCH - || fromType == Toolkit::Visual::SVG || fromType == Toolkit::Visual::ANIMATED_IMAGE ) - { - Property::Value* fromUrl = fromMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME ); - Property::Value* toUrl = toMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME ); + // No longer required to know if the replaced visual's resources are ready + StopObservingVisual(visual); - if( fromUrl && toUrl ) + // If control staged then visuals will be swapped once ready + if(self.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + // Check if visual is currently in the process of being replaced ( is in removal container ) + RegisteredVisualContainer::Iterator visualQueuedForRemoval; + if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval)) { - std::string fromUrlString; - std::string toUrlString; - fromUrl->Get(fromUrlString); - toUrl->Get(toUrlString); - - if( fromUrlString != toUrlString ) - { - recreate = true; - } + // Visual with same visual name 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(visual).SetOffScene(self); + (*registeredVisualsiter)->visual.Reset(); + mVisuals.Erase(registeredVisualsiter); + } + else + { + // current visual not already in removal container so add now. + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str()); + MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals); } } + else + { + // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later. + (*registeredVisualsiter)->visual.Reset(); + mVisuals.Erase(registeredVisualsiter); + } } - const Property::Map* instancedMap = instancedProperties.FindConst( visualName ); - if( recreate || instancedMap ) - { - RemoveVisual( mVisuals, visualName ); - Style::ApplyVisual( handle, visualName, toMap, instancedMap ); - } - else - { - // @todo check to see if we can apply toMap without recreating the visual - // e.g. by setting only animatable properties - // For now, recreate all visuals, but merge in instance data. - RemoveVisual( mVisuals, visualName ); - Style::ApplyVisual( handle, visualName, toMap, instancedMap ); - } + const Property::Map* instancedMap = instancedProperties.FindConst(visualName); + Style::ApplyVisual(handle, visualName, toMap, instancedMap); } } } -void Control::Impl::ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState ) +void Control::Impl::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState) { // Collect all old visual names DictionaryKeys stateVisualsToRemove; - if( oldState ) + if(oldState) { - oldState->visuals.GetKeys( stateVisualsToRemove ); - if( ! subState.empty() ) + oldState->visuals.GetKeys(stateVisualsToRemove); + if(!subState.empty()) { const StylePtr* oldSubState = oldState->subStates.FindConst(subState); - if( oldSubState ) + if(oldSubState) { DictionaryKeys subStateVisualsToRemove; - (*oldSubState)->visuals.GetKeys( subStateVisualsToRemove ); - Merge( stateVisualsToRemove, subStateVisualsToRemove ); + (*oldSubState)->visuals.GetKeys(subStateVisualsToRemove); + Merge(stateVisualsToRemove, subStateVisualsToRemove); } } } // Collect all new visual properties Dictionary stateVisualsToAdd; - if( newState ) + if(newState) { stateVisualsToAdd = newState->visuals; - if( ! subState.empty() ) + if(!subState.empty()) { const StylePtr* newSubState = newState->subStates.FindConst(subState); - if( newSubState ) + if(newSubState) { - stateVisualsToAdd.Merge( (*newSubState)->visuals ); + stateVisualsToAdd.Merge((*newSubState)->visuals); } } } // If a name is in both add/remove, move it to change list. Dictionary stateVisualsToChange; - FindChangableVisuals( stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove); + FindChangableVisuals(stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove); // Copy instanced properties (e.g. text label) of current visuals Dictionary instancedProperties; - CopyInstancedProperties( mVisuals, instancedProperties ); + CopyInstancedProperties(mVisuals, instancedProperties); // For each visual in remove list, remove from mVisuals - RemoveVisuals( mVisuals, stateVisualsToRemove ); + RemoveVisuals(mVisuals, stateVisualsToRemove); // For each visual in add list, create and add to mVisuals - Dali::CustomActor handle( mControlImpl.GetOwner() ); - Style::ApplyVisuals( handle, stateVisualsToAdd, instancedProperties ); + Dali::CustomActor handle(mControlImpl.GetOwner()); + Style::ApplyVisuals(handle, stateVisualsToAdd, instancedProperties); // For each visual in change list, if it requires a new visual, // remove old visual, create and add to mVisuals - RecreateChangedVisuals( stateVisualsToChange, instancedProperties ); + RecreateChangedVisuals(stateVisualsToChange, instancedProperties); } -void Control::Impl::SetState( DevelControl::State newState, bool withTransitions ) +void Control::Impl::SetState(DevelControl::State newState, bool withTransitions) { DevelControl::State oldState = mState; - Dali::CustomActor handle( mControlImpl.GetOwner() ); - DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n", - (mState == DevelControl::NORMAL ? "NORMAL" :( - mState == DevelControl::FOCUSED ?"FOCUSED" : ( - mState == DevelControl::DISABLED?"DISABLED":"NONE" )))); + Dali::CustomActor handle(mControlImpl.GetOwner()); + DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n", (mState == DevelControl::NORMAL ? "NORMAL" : (mState == DevelControl::FOCUSED ? "FOCUSED" : (mState == DevelControl::DISABLED ? "DISABLED" : "NONE")))); - if( mState != newState ) + if(mState != newState) { // If mState was Disabled, and new state is Focused, should probably // store that fact, e.g. in another property that FocusManager can access. @@ -1303,54 +1674,54 @@ void Control::Impl::SetState( DevelControl::State newState, bool withTransitions // Trigger state change and transitions // Apply new style, if stylemanager is available Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get(); - if( styleManager ) + if(styleManager) { - const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) ); + const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner())); - if( stylePtr ) + if(stylePtr) { - std::string oldStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( oldState, ControlStateTable, ControlStateTableCount ); - std::string newStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( newState, ControlStateTable, ControlStateTableCount ); + std::string oldStateName = Scripting::GetEnumerationName(oldState, ControlStateTable, ControlStateTableCount); + std::string newStateName = Scripting::GetEnumerationName(newState, ControlStateTable, ControlStateTableCount); - const StylePtr* newStateStyle = stylePtr->subStates.Find( newStateName ); - const StylePtr* oldStateStyle = stylePtr->subStates.Find( oldStateName ); - if( oldStateStyle && newStateStyle ) + const StylePtr* newStateStyle = stylePtr->subStates.Find(newStateName); + const StylePtr* oldStateStyle = stylePtr->subStates.Find(oldStateName); + if(oldStateStyle && newStateStyle) { // Only change if both state styles exist - ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, mSubStateName ); + ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, mSubStateName); } } } } } -void Control::Impl::SetSubState( const std::string& subStateName, bool withTransitions ) +void Control::Impl::SetSubState(const std::string& subStateName, bool withTransitions) { - if( mSubStateName != subStateName ) + if(mSubStateName != subStateName) { // Get existing sub-state visuals, and unregister them - Dali::CustomActor handle( mControlImpl.GetOwner() ); + Dali::CustomActor handle(mControlImpl.GetOwner()); Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get(); - if( styleManager ) + if(styleManager) { - const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) ); - if( stylePtr ) + const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner())); + if(stylePtr) { // Stringify state - std::string stateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( mState, ControlStateTable, ControlStateTableCount ); + std::string stateName = Scripting::GetEnumerationName(mState, ControlStateTable, ControlStateTableCount); - const StylePtr* state = stylePtr->subStates.Find( stateName ); - if( state ) + const StylePtr* state = stylePtr->subStates.Find(stateName); + if(state) { StylePtr stateStyle(*state); - const StylePtr* newStateStyle = stateStyle->subStates.Find( subStateName ); - const StylePtr* oldStateStyle = stateStyle->subStates.Find( mSubStateName ); - if( oldStateStyle && newStateStyle ) + const StylePtr* newStateStyle = stateStyle->subStates.Find(subStateName); + const StylePtr* oldStateStyle = stateStyle->subStates.Find(mSubStateName); + if(oldStateStyle && newStateStyle) { std::string empty; - ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, empty ); + ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, empty); } } } @@ -1360,25 +1731,25 @@ 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 - for( auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++ ) + // 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++ ) + for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++) { (*replacedIter)->pending = false; } @@ -1386,7 +1757,7 @@ void Control::Impl::OnStageDisconnection() mRemoveVisuals.Clear(); } -void Control::Impl::SetMargin( Extents margin ) +void Control::Impl::SetMargin(Extents margin) { mControlImpl.mImpl->mMargin = margin; @@ -1399,7 +1770,7 @@ Extents Control::Impl::GetMargin() const return mControlImpl.mImpl->mMargin; } -void Control::Impl::SetPadding( Extents padding ) +void Control::Impl::SetPadding(Extents padding) { mControlImpl.mImpl->mPadding = padding; @@ -1412,81 +1783,202 @@ Extents Control::Impl::GetPadding() const return mControlImpl.mImpl->mPadding; } -void Control::Impl::SetInputMethodContext( InputMethodContext& inputMethodContext ) +void Control::Impl::SetInputMethodContext(InputMethodContext& inputMethodContext) { mInputMethodContext = inputMethodContext; } -bool Control::Impl::FilterKeyEvent( const KeyEvent& event ) +bool Control::Impl::FilterKeyEvent(const KeyEvent& event) { - bool consumed ( false ); + bool consumed(false); - if ( mInputMethodContext ) + if(mInputMethodContext) { - consumed = mInputMethodContext.FilterEventKey( event ); + consumed = mInputMethodContext.FilterEventKey(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) { - // 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 ) - { - 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 ) ; - } - else + 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(); +} + +Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey) +{ + Toolkit::Visual::Base visual = GetVisualByIndex(mVisuals, index); + if(visual) + { + Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); + return visualImpl.GetPropertyObject(visualPropertyKey); + } + + Handle handle; + return Dali::Property(handle, Property::INVALID_INDEX); +} + +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) { - return; // layout is already set to this control. + // 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 + { + mNeedToEmitResourceReady = true; + } +} - if( mLayout ) +void Control::Impl::OnIdleCallback() +{ + if(mNeedToEmitResourceReady) { - mLayout->Unparent(); - mLayout.Reset(); + // 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)) + { + mControlImpl.RelayoutRequest(); + } + + EmitResourceReadySignal(); } - mLayout = &layout; + // Set the pointer to null as the callback manager deletes the callback after execute it. + mIdleCallback = nullptr; +} - 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 +Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject() +{ + if(!accessibilityObject) + accessibilityObject = accessibilityConstructor(mControlImpl.Self()); + return accessibilityObject.get(); } -void Control::Impl::RemoveLayout() +Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject(Dali::Actor actor) { - DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::Impl::RemoveLayout\n"); + if(actor) + { + auto q = Dali::Toolkit::Control::DownCast(actor); + if(q) + { + auto q2 = static_cast(&q.GetImplementation()); + return q2->mImpl->GetAccessibilityObject(); + } + } + return nullptr; +} - Toolkit::BinLayout binLayout = Toolkit::BinLayout::New(); +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()) + { + auto extents = DevelActor::CalculateScreenExtents(self); + Dali::Accessibility::Accessible::Get(self)->EmitBoundsChanged(extents); + } +} - mControlImpl.mImpl->SetLayout( GetImplementation( binLayout ) ) ; +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::SetLayoutingRequired( bool layoutingRequired ) +void Control::Impl::AccessibilityRegister() { - mControlImpl.mImpl->mIsLayoutingRequired = layoutingRequired; + 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; + } } -bool Control::Impl::IsLayoutingRequired() +void Control::Impl::AccessibilityDeregister(bool remove) { - return mControlImpl.mImpl->mIsLayoutingRequired; + if(accessibilityNotificationSet) + { + accessibilityNotificationPosition.NotifySignal().Disconnect(&Control::Impl::PositionOrSizeChangedCallback); + if(remove) + { + mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationPosition); + } + accessibilityNotificationPosition.Reset(); + accessibilityNotificationPosition = {}; + + accessibilityNotificationSize.NotifySignal().Disconnect(&Control::Impl::PositionOrSizeChangedCallback); + if(remove) + { + mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationSize); + } + accessibilityNotificationSize.Reset(); + accessibilityNotificationSize = {}; + + accessibilityNotificationCulled.NotifySignal().Disconnect(&Control::Impl::CulledChangedCallback); + if(remove) + { + mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationCulled); + } + accessibilityNotificationCulled.Reset(); + accessibilityNotificationCulled = {}; + accessibilityNotificationSet = false; + } } } // namespace Internal