X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fvisual-base-impl.cpp;h=331eaf5661c26cac3a03413a8c81057119881e32;hb=77cfccf524aa92099d786a8ee13528b597593d48;hp=1b9cec710b5e05fc951cee1cb95f6f431629b716;hpb=babef00662186629afb90e87a37834ff9b5d997f;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/visuals/visual-base-impl.cpp b/dali-toolkit/internal/visuals/visual-base-impl.cpp index 1b9cec7..331eaf5 100644 --- a/dali-toolkit/internal/visuals/visual-base-impl.cpp +++ b/dali-toolkit/internal/visuals/visual-base-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 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,26 +19,52 @@ #include "visual-base-impl.h" // EXTERNAL HEADER -#include +#include +#include +#include #include //INTERNAL HEARDER -#include +#include +#include #include #include +#include +#include +#include -namespace Dali +namespace { +#if defined(DEBUG_ENABLED) +Debug::Filter* gVisualBaseLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VISUAL_BASE"); +#endif + +const char* const PRE_MULTIPLIED_ALPHA_PROPERTY("preMultipliedAlpha"); +} // namespace + +namespace Dali +{ namespace Toolkit { - namespace Internal { - -Visual::Base::Base( VisualFactoryCache& factoryCache ) -: mImpl( new Impl() ), - mFactoryCache( factoryCache ) +namespace +{ +DALI_ENUM_TO_STRING_TABLE_BEGIN(VISUAL_FITTING_MODE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_KEEP_ASPECT_RATIO) + DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FILL) + DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, OVER_FIT_KEEP_ASPECT_RATIO) + DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, CENTER) + DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_WIDTH) + DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_HEIGHT) +DALI_ENUM_TO_STRING_TABLE_END(VISUAL_FITTING_MODE) + +} // namespace + +Visual::Base::Base(VisualFactoryCache& factoryCache, FittingMode fittingMode, Toolkit::Visual::Type type) +: mImpl(new Impl(fittingMode, type)), + mFactoryCache(factoryCache) { } @@ -47,128 +73,347 @@ Visual::Base::~Base() delete mImpl; } -void Visual::Base::SetCustomShader( const Property::Map& shaderMap ) +void Visual::Base::Initialize() +{ + // The Renderer should be created inside derived class here. + OnInitialize(); + + if(mImpl->mRenderer) + { + RegisterMixColor(); + + if(IsRoundedCornerRequired()) + { + mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius); + mImpl->mRenderer.RegisterProperty(CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy); + + mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON); + } + } +} + +void Visual::Base::SetCustomShader(const Property::Map& shaderMap) { - if( mImpl->mCustomShader ) + if(mImpl->mCustomShader) { - mImpl->mCustomShader->SetPropertyMap( shaderMap ); + mImpl->mCustomShader->SetPropertyMap(shaderMap); } else { - mImpl->mCustomShader = new Impl::CustomShader( shaderMap ); + mImpl->mCustomShader = new Impl::CustomShader(shaderMap); } + + // Let derived class know + UpdateShader(); } -void Visual::Base::SetProperties( const Property::Map& propertyMap ) +void Visual::Base::SetProperties(const Property::Map& propertyMap) { - Property::Value* customShaderValue = propertyMap.Find( VisualProperty::SHADER, CUSTOM_SHADER ); - if( customShaderValue ) + for(size_t i = 0; i < propertyMap.Count(); ++i) { - Property::Map shaderMap; - if( customShaderValue->Get( shaderMap ) ) + const KeyValuePair& pair = propertyMap.GetKeyValue(i); + const Property::Key& key = pair.first; + const Property::Value& value = pair.second; + + Property::Key matchKey = key; + if(matchKey.type == Property::Key::STRING) { - SetCustomShader( shaderMap ); + if(matchKey == CUSTOM_SHADER) + { + matchKey = Property::Key(Toolkit::Visual::Property::SHADER); + } + else if(matchKey == TRANSFORM) + { + matchKey = Property::Key(Toolkit::Visual::Property::TRANSFORM); + } + else if(matchKey == PREMULTIPLIED_ALPHA) + { + matchKey = Property::Key(Toolkit::Visual::Property::PREMULTIPLIED_ALPHA); + } + else if(matchKey == MIX_COLOR) + { + matchKey = Property::Key(Toolkit::Visual::Property::MIX_COLOR); + } + else if(matchKey == OPACITY) + { + matchKey = Property::Key(Toolkit::Visual::Property::OPACITY); + } + else if(matchKey == VISUAL_FITTING_MODE) + { + matchKey = Property::Key(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE); + } + else if(matchKey == CORNER_RADIUS) + { + matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS); + } + else if(matchKey == CORNER_RADIUS_POLICY) + { + matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY); + } } - } - Property::Value* transform = propertyMap.Find( Toolkit::Visual::DevelProperty::TRANSFORM, TRANSFORM ); - if( transform ) - { - Property::Map map; - if( transform->Get( map ) ) + switch(matchKey.indexKey) { - mImpl->mTransform.SetPropertyMap( map ); + case Toolkit::Visual::Property::SHADER: + { + Property::Map shaderMap; + if(value.Get(shaderMap)) + { + SetCustomShader(shaderMap); + } + break; + } + + case Toolkit::Visual::Property::TRANSFORM: + { + Property::Map map; + if(value.Get(map)) + { + mImpl->mTransform.SetPropertyMap(map); + } + break; + } + + case Toolkit::Visual::Property::PREMULTIPLIED_ALPHA: + { + bool premultipliedAlpha = false; + if(value.Get(premultipliedAlpha)) + { + EnablePreMultipliedAlpha(premultipliedAlpha); + } + break; + } + + case Toolkit::Visual::Property::MIX_COLOR: + { + Vector4 mixColor; + if(value.Get(mixColor)) + { + if(value.GetType() == Property::VECTOR4) + { + SetMixColor(mixColor); + } + else + { + Vector3 mixColor3(mixColor); + SetMixColor(mixColor3); + } + } + break; + } + case Toolkit::Visual::Property::OPACITY: + { + float opacity; + if(value.Get(opacity)) + { + mImpl->mMixColor.a = opacity; + SetMixColor(mImpl->mMixColor); + } + break; + } + case Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE: + { + Scripting::GetEnumerationProperty( + value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode); + break; + } + case Toolkit::DevelVisual::Property::CORNER_RADIUS: + { + float radius; + if(value.Get(radius)) + { + mImpl->mCornerRadius = radius; + } + break; + } + case Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY: + { + int policy; + if(value.Get(policy)) + { + switch(policy) + { + case Toolkit::Visual::Transform::Policy::RELATIVE: + case Toolkit::Visual::Transform::Policy::ABSOLUTE: + { + mImpl->mCornerRadiusPolicy = policy; + break; + } + default: + { + DALI_LOG_ERROR("Unsupported policy: %d\n", policy); + break; + } + } + } + break; + } } } - DoSetProperties( propertyMap ); + DoSetProperties(propertyMap); +} + +void Visual::Base::SetTransformAndSize(const Property::Map& transform, Size controlSize) +{ + mImpl->mControlSize = controlSize; + mImpl->mTransform.UpdatePropertyMap(transform); + +#if defined(DEBUG_ENABLED) + std::ostringstream oss; + oss << transform; + DALI_LOG_INFO(gVisualBaseLogFilter, Debug::General, "Visual::Base::SetTransformAndSize(%s) - [\e[1;32mtransform: %s controlSize: (%3.1f, %3.1f)]\e[0m\n", GetName().c_str(), oss.str().c_str(), controlSize.x, controlSize.y); +#endif + + OnSetTransform(); } -void Visual::Base::SetName( const std::string& name ) +void Visual::Base::SetName(const std::string& name) { mImpl->mName = name; } -const std::string& Visual::Base::GetName() +const std::string& Visual::Base::GetName() const { return mImpl->mName; } -void Visual::Base::SetSize( const Vector2& size ) +float Visual::Base::GetHeightForWidth(float width) { - mImpl->mSize = size; + float aspectCorrectedHeight = 0.f; + Vector2 naturalSize; + GetNaturalSize(naturalSize); + if(naturalSize.width) + { + aspectCorrectedHeight = naturalSize.height * width / naturalSize.width; + } + return aspectCorrectedHeight; } -const Vector2& Visual::Base::GetSize() const +float Visual::Base::GetWidthForHeight(float height) { - return mImpl->mSize; + float aspectCorrectedWidth = 0.f; + Vector2 naturalSize; + GetNaturalSize(naturalSize); + if(naturalSize.height > 0.0f) + { + aspectCorrectedWidth = naturalSize.width * height / naturalSize.height; + } + return aspectCorrectedWidth; } -float Visual::Base::GetHeightForWidth( float width ) const +void Visual::Base::GetNaturalSize(Vector2& naturalSize) { - return 0.f; + naturalSize = Vector2::ZERO; } -void Visual::Base::GetNaturalSize( Vector2& naturalSize ) const +void Visual::Base::DoAction(const Property::Index actionId, const Property::Value attributes) { - naturalSize = Vector2::ZERO; + OnDoAction(actionId, attributes); } -void Visual::Base::SetDepthIndex( float index ) +void Visual::Base::SetDepthIndex(int index) { mImpl->mDepthIndex = index; - if( mImpl->mRenderer ) + if(mImpl->mRenderer) { - mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex ); + mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex); } } -float Visual::Base::GetDepthIndex() const +int Visual::Base::GetDepthIndex() const { return mImpl->mDepthIndex; } -void Visual::Base::SetOnStage( Actor& actor ) +void Visual::Base::SetOnScene(Actor& actor) { - // To display the actor correctly, renderer should not be added to actor until all required resources are ready. - // Thus the calling of actor.AddRenderer() should happen inside derived class as base class does not know the exact timing. - DoSetOnStage( actor ); - - if( mImpl->mRenderer ) + if(!IsOnScene()) { - mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled()); - mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex ); - mImpl->mFlags |= Impl::IS_ON_STAGE; // Only sets the flag if renderer exists + // To display the actor correctly, renderer should not be added to actor until all required resources are ready. + // Thus the calling of actor.AddRenderer() should happen inside derived class as base class does not know the exact timing. + DoSetOnScene(actor); + + if(mImpl->mRenderer) + { + mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled()); + mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex); + } + + mImpl->mFlags |= Impl::IS_ON_SCENE; } } -void Visual::Base::SetOffStage( Actor& actor ) +void Visual::Base::SetOffScene(Actor& actor) { - if( IsOnStage() ) + if(IsOnScene()) { - DoSetOffStage( actor ); - - mImpl->mFlags &= ~Impl::IS_ON_STAGE; + DoSetOffScene(actor); + mImpl->mFlags &= ~Impl::IS_ON_SCENE; } } -void Visual::Base::CreatePropertyMap( Property::Map& map ) const +void Visual::Base::CreatePropertyMap(Property::Map& map) const { - DoCreatePropertyMap( map ); + if(mImpl->mRenderer) + { + // Update values from Renderer + mImpl->mMixColor = mImpl->mRenderer.GetProperty(mImpl->mMixColorIndex); + mImpl->mMixColor.a = mImpl->mRenderer.GetProperty(DevelRenderer::Property::OPACITY); + if(mImpl->mTransform.mOffsetIndex != Property::INVALID_INDEX) + { + mImpl->mTransform.mOffset = mImpl->mRenderer.GetProperty(mImpl->mTransform.mOffsetIndex); + } + if(mImpl->mTransform.mSizeIndex != Property::INVALID_INDEX) + { + mImpl->mTransform.mSize = mImpl->mRenderer.GetProperty(mImpl->mTransform.mSizeIndex); + } + if(mImpl->mCornerRadiusIndex != Property::INVALID_INDEX) + { + mImpl->mCornerRadius = mImpl->mRenderer.GetProperty(mImpl->mCornerRadiusIndex); + } + } + + DoCreatePropertyMap(map); - if( mImpl->mCustomShader ) + if(mImpl->mCustomShader) { - mImpl->mCustomShader->CreatePropertyMap( map ); + mImpl->mCustomShader->CreatePropertyMap(map); } Property::Map transform; - mImpl->mTransform.GetPropertyMap( transform ); - map.Insert( Toolkit::Visual::DevelProperty::TRANSFORM, transform ); + mImpl->mTransform.GetPropertyMap(transform); + map.Insert(Toolkit::Visual::Property::TRANSFORM, transform); + + bool premultipliedAlpha(IsPreMultipliedAlphaEnabled()); + map.Insert(Toolkit::Visual::Property::PREMULTIPLIED_ALPHA, premultipliedAlpha); + + // Note, Color and Primitive will also insert their own mix color into the map + // which is ok, because they have a different key value range. + map.Insert(Toolkit::Visual::Property::MIX_COLOR, mImpl->mMixColor); // vec4 + map.Insert(Toolkit::Visual::Property::OPACITY, mImpl->mMixColor.a); + + auto fittingModeString = Scripting::GetLinearEnumerationName( + mImpl->mFittingMode, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT); + map.Insert(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE, fittingModeString); + + map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius); + map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, static_cast(mImpl->mCornerRadiusPolicy)); +} + +void Visual::Base::CreateInstancePropertyMap(Property::Map& map) const +{ + DoCreateInstancePropertyMap(map); + + if(mImpl->mCustomShader) + { + mImpl->mCustomShader->CreatePropertyMap(map); + } } -void Visual::Base::EnablePreMultipliedAlpha( bool preMultipled ) +void Visual::Base::EnablePreMultipliedAlpha(bool preMultiplied) { - if(preMultipled) + if(preMultiplied) { mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA; } @@ -177,9 +422,10 @@ void Visual::Base::EnablePreMultipliedAlpha( bool preMultipled ) mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA; } - if( mImpl->mRenderer ) + if(mImpl->mRenderer) { - mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultipled); + mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultiplied); + mImpl->mRenderer.RegisterProperty(PRE_MULTIPLIED_ALPHA_PROPERTY, static_cast(preMultiplied)); } } @@ -188,72 +434,403 @@ bool Visual::Base::IsPreMultipliedAlphaEnabled() const return mImpl->mFlags & Impl::IS_PREMULTIPLIED_ALPHA; } -void Visual::Base::DoSetOffStage( Actor& actor ) +void Visual::Base::DoSetOffScene(Actor& actor) +{ + actor.RemoveRenderer(mImpl->mRenderer); +} + +bool Visual::Base::IsOnScene() const +{ + return mImpl->mFlags & Impl::IS_ON_SCENE; +} + +bool Visual::Base::IsRoundedCornerRequired() const +{ + if(mImpl->mRenderer && mImpl->mCornerRadiusIndex != Property::INVALID_INDEX) + { + // Update values from Renderer + mImpl->mCornerRadius = mImpl->mRenderer.GetProperty(mImpl->mCornerRadiusIndex); + } + return !EqualsZero(mImpl->mCornerRadius) || mImpl->mNeedCornerRadius; +} + +void Visual::Base::OnDoAction(const Property::Index actionId, const Property::Value& attributes) +{ + // May be overriden by derived class +} + +void Visual::Base::RegisterMixColor() +{ + // Only register if not already registered. + // (Color and Primitive visuals will register their own and save to this index) + if(mImpl->mMixColorIndex == Property::INVALID_INDEX) + { + mImpl->mMixColorIndex = mImpl->mRenderer.RegisterProperty( + Toolkit::Visual::Property::MIX_COLOR, + MIX_COLOR, + Vector3(mImpl->mMixColor)); + } + + mImpl->mRenderer.SetProperty(DevelRenderer::Property::OPACITY, mImpl->mMixColor.a); + + float preMultipliedAlpha = 0.0f; + if(IsPreMultipliedAlphaEnabled()) + { + preMultipliedAlpha = 1.0f; + } + mImpl->mRenderer.RegisterProperty(PRE_MULTIPLIED_ALPHA_PROPERTY, preMultipliedAlpha); +} + +void Visual::Base::SetMixColor(const Vector4& color) +{ + mImpl->mMixColor = color; + + if(mImpl->mRenderer) + { + mImpl->mRenderer.SetProperty(mImpl->mMixColorIndex, Vector3(color)); + mImpl->mRenderer.SetProperty(DevelRenderer::Property::OPACITY, color.a); + } +} + +void Visual::Base::SetMixColor(const Vector3& color) +{ + mImpl->mMixColor.r = color.r; + mImpl->mMixColor.g = color.g; + mImpl->mMixColor.b = color.b; + + if(mImpl->mRenderer) + { + mImpl->mRenderer.SetProperty(mImpl->mMixColorIndex, color); + } +} + +void Visual::Base::AddEventObserver(Visual::EventObserver& observer) +{ + mImpl->mEventObserver = &observer; +} + +void Visual::Base::RemoveEventObserver(Visual::EventObserver& observer) +{ + mImpl->mEventObserver = NULL; +} + +void Visual::Base::ResourceReady(Toolkit::Visual::ResourceStatus resourceStatus) +{ + if(mImpl->mResourceStatus != resourceStatus) + { + mImpl->mResourceStatus = resourceStatus; + + if(mImpl->mEventObserver) + { + // observer is currently a control impl + mImpl->mEventObserver->ResourceReady(*this); + } + } +} + +bool Visual::Base::IsResourceReady() const +{ + return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY); +} + +bool Visual::Base::IsSynchronousLoadingRequired() const +{ + return (mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING); +} + +Toolkit::Visual::Type Visual::Base::GetType() const +{ + return mImpl->mType; +} + +Toolkit::Visual::ResourceStatus Visual::Base::GetResourceStatus() const +{ + return mImpl->mResourceStatus; +} + +Visual::FittingMode Visual::Base::GetFittingMode() const { - actor.RemoveRenderer( mImpl->mRenderer ); - mImpl->mRenderer.Reset(); + return mImpl->mFittingMode; } -bool Visual::Base::IsOnStage() const +Visual::Base& Visual::Base::GetVisualObject() { - return mImpl->mFlags & Impl::IS_ON_STAGE; + return *this; } -bool Visual::Base::IsFromCache() const +Renderer Visual::Base::GetRenderer() { - return mImpl->mFlags & Impl::IS_FROM_CACHE; + return mImpl->mRenderer; } -void Visual::Base::SetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue ) +Property::Index Visual::Base::GetPropertyIndex(Property::Key key) { - DALI_ASSERT_ALWAYS( ( index > Property::INVALID_INDEX ) && - ( index > VISUAL_PROPERTY_BASE_START_INDEX ) && // Change the type of visual is not allowed. - "Property index is out of bounds" ); + Property::Index index = mImpl->mRenderer.GetPropertyIndex(key); - if( index < VISUAL_PROPERTY_START_INDEX ) + if(index == Property::INVALID_INDEX) + { + // Is it a shader property? + Shader shader = mImpl->mRenderer.GetShader(); + index = shader.GetPropertyIndex(key); + if(index != Property::INVALID_INDEX) + { + // Yes - we should register it in the Renderer so it can be set / animated + // independently, as shaders are shared across multiple renderers. + std::string keyName; + Property::Index keyIndex(Property::INVALID_KEY); + if(key.type == Property::Key::INDEX) + { + keyName = shader.GetPropertyName(index); + keyIndex = key.indexKey; + } + else + { + keyName = key.stringKey; + // Leave keyIndex as INVALID_KEY - it can still be registered against the string key. + } + Property::Value value = shader.GetProperty(index); + index = mImpl->mRenderer.RegisterProperty(keyIndex, keyName, value); + } + } + return index; +} + +void Visual::Base::SetupTransition( + Dali::Animation& transition, + Internal::TransitionData::Animator& animator, + Property::Index index, + Property::Value& initialValue, + Property::Value& targetValue) +{ + if(index != Property::INVALID_INDEX) { - if( index == Dali::Toolkit::Visual::DevelProperty::TRANSFORM ) + if(mImpl->mRenderer) { - Property::Map* map = propertyValue.GetMap(); - if( map ) + if(animator.animate == false) { - mImpl->mTransform.SetPropertyMap( *map ); - OnSetTransform(); + mImpl->mRenderer.SetProperty(index, targetValue); + } + else + { + if(animator.initialValue.GetType() != Property::NONE) + { + mImpl->mRenderer.SetProperty(index, initialValue); + } + + if(!transition) + { + transition = Dali::Animation::New(0.1f); + } + + transition.AnimateTo(Property(mImpl->mRenderer, index), + targetValue, + animator.alphaFunction, + TimePeriod(animator.timePeriodDelay, + animator.timePeriodDuration)); } } + } +} - // TODO set the properties of the visual base. +void Visual::Base::AnimateProperty( + Dali::Animation& transition, + Internal::TransitionData::Animator& animator) +{ +#if defined(DEBUG_ENABLED) + { + std::ostringstream oss; + oss << "Visual::Base::AnimateProperty(Visual:" << mImpl->mName << " Property:" << animator.propertyKey << " Target: " << animator.targetValue << std::endl; + DALI_LOG_INFO(gVisualBaseLogFilter, Debug::General, oss.str().c_str()); } - else +#endif + + if(animator.propertyKey == Toolkit::Visual::Property::MIX_COLOR || + animator.propertyKey == MIX_COLOR || + (mImpl->mType == Toolkit::Visual::COLOR && + animator.propertyKey == ColorVisual::Property::MIX_COLOR) || + (mImpl->mType == Toolkit::Visual::PRIMITIVE && + animator.propertyKey == PrimitiveVisual::Property::MIX_COLOR)) { - DoSetProperty( index, propertyValue ); + AnimateMixColorProperty(transition, animator); + } + else if(animator.propertyKey == Toolkit::Visual::Property::OPACITY || + animator.propertyKey == OPACITY) + { + AnimateOpacityProperty(transition, animator); + } + else if(mImpl->mRenderer) + { + AnimateRendererProperty(transition, animator); } } -Dali::Property::Value Visual::Base::GetProperty( Dali::Property::Index index ) +void Visual::Base::AnimateOpacityProperty( + Dali::Animation& transition, + Internal::TransitionData::Animator& animator) { - DALI_ASSERT_ALWAYS( ( index > Property::INVALID_INDEX ) && - ( index >= VISUAL_PROPERTY_BASE_START_INDEX ) && - "Property index is out of bounds" ); + float targetOpacity; + if(animator.targetValue.Get(targetOpacity)) + { + mImpl->mMixColor.a = targetOpacity; + } - Dali::Property::Value value; + SetupTransition(transition, animator, DevelRenderer::Property::OPACITY, animator.initialValue, animator.targetValue); +} - if( index < VISUAL_PROPERTY_START_INDEX ) +void Visual::Base::AnimateRendererProperty( + Dali::Animation& transition, + Internal::TransitionData::Animator& animator) +{ + Property::Index index = GetPropertyIndex(animator.propertyKey); + if(index != Property::INVALID_INDEX) { - if( index == Dali::Toolkit::Visual::DevelProperty::TRANSFORM ) + if(animator.targetValue.GetType() != Property::NONE) { + // Try writing target value into transform property map + // if it's not a valid key, then it won't alter mTransform Property::Map map; - mImpl->mTransform.GetPropertyMap( map ); - return map; + if(animator.propertyKey.type == Property::Key::INDEX) + { + map.Add(animator.propertyKey.indexKey, animator.targetValue); + } + else + { + map.Add(animator.propertyKey.stringKey, animator.targetValue); + } + + mImpl->mTransform.UpdatePropertyMap(map); + } + + SetupTransition(transition, animator, index, animator.initialValue, animator.targetValue); + } +} + +void Visual::Base::AnimateMixColorProperty( + Dali::Animation& transition, + Internal::TransitionData::Animator& animator) +{ + Property::Index index = mImpl->mMixColorIndex; + bool animateOpacity = false; + + Property::Value initialOpacity; + Property::Value targetOpacity; + Property::Value initialMixColor; + Property::Value targetMixColor; + + if(index != Property::INVALID_INDEX) + { + Vector4 initialColor; + if(animator.initialValue.Get(initialColor)) + { + if(animator.initialValue.GetType() == Property::VECTOR4) + { + // if there is an initial color specifying alpha, test it + initialOpacity = initialColor.a; + } + initialMixColor = Vector3(initialColor); + } + + // Set target value into data store + if(animator.targetValue.GetType() != Property::NONE) + { + Vector4 mixColor; + animator.targetValue.Get(mixColor); + if(animator.targetValue.GetType() == Property::VECTOR4) + { + mImpl->mMixColor.a = mixColor.a; + targetOpacity = mixColor.a; + animateOpacity = true; + } + + mImpl->mMixColor.r = mixColor.r; + mImpl->mMixColor.g = mixColor.g; + mImpl->mMixColor.b = mixColor.b; + targetMixColor = Vector3(mixColor); + } + + SetupTransition(transition, animator, index, initialMixColor, targetMixColor); + if(animateOpacity) + { + SetupTransition(transition, animator, DevelRenderer::Property::OPACITY, initialOpacity, targetOpacity); + } + } +} + +Dali::Property Visual::Base::GetPropertyObject(Dali::Property::Key key) +{ + if(!mImpl->mRenderer) + { + Handle handle; + return Dali::Property(handle, Property::INVALID_INDEX); + } + + // Mix color or opacity cases + if(key.type == Property::Key::INDEX) + { + if(key.indexKey == Toolkit::Visual::Property::MIX_COLOR || (mImpl->mType == Toolkit::Visual::COLOR && key.indexKey == ColorVisual::Property::MIX_COLOR) || (mImpl->mType == Toolkit::Visual::PRIMITIVE && key.indexKey == PrimitiveVisual::Property::MIX_COLOR)) + { + return Dali::Property(mImpl->mRenderer, mImpl->mMixColorIndex); + } + else if(key.indexKey == Toolkit::Visual::Property::OPACITY) + { + return Dali::Property(mImpl->mRenderer, DevelRenderer::Property::OPACITY); + } + else if(key.indexKey == Toolkit::Visual::Transform::Property::OFFSET) + { + return Dali::Property(mImpl->mRenderer, OFFSET); + } + else if(key.indexKey == Toolkit::Visual::Transform::Property::SIZE) + { + return Dali::Property(mImpl->mRenderer, SIZE); } - // TODO retrieve the properties of the visual base. } else { - value = DoGetProperty( index ); + if(key.stringKey == MIX_COLOR) + { + return Dali::Property(mImpl->mRenderer, mImpl->mMixColorIndex); + } + else if(key.stringKey == OPACITY) + { + return Dali::Property(mImpl->mRenderer, DevelRenderer::Property::OPACITY); + } + else if(key.stringKey == OFFSET) + { + return Dali::Property(mImpl->mRenderer, OFFSET); + } + else if(key.stringKey == SIZE) + { + return Dali::Property(mImpl->mRenderer, SIZE); + } + } + + // Other cases + Property::Index index = GetPropertyIndex(key); + if(index == Property::INVALID_INDEX) + { + if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS)) + { + // Register CORNER_RADIUS property + mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius); + mImpl->mRenderer.RegisterProperty(CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy); + + mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON); + + index = mImpl->mCornerRadiusIndex; + mImpl->mNeedCornerRadius = true; + + // Change shader + UpdateShader(); + } + else + { + // We can't find the property in the base class. + // Request to child class + return OnGetPropertyObject(key); + } } - return value; + return Dali::Property(mImpl->mRenderer, index); } } // namespace Internal