2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "visual-base-impl.h"
22 #include <dali-toolkit/public-api/dali-toolkit-common.h>
23 #include <dali/devel-api/rendering/renderer-devel.h>
24 #include <dali/devel-api/scripting/enum-helper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/rendering/decorated-visual-renderer.h>
27 #include <dali/public-api/rendering/visual-renderer.h>
30 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
31 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
32 #include <dali-toolkit/internal/helpers/property-helper.h>
33 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
34 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
35 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
36 #include <dali-toolkit/public-api/visuals/primitive-visual-properties.h>
37 #include <dali-toolkit/public-api/visuals/visual-properties.h>
41 #if defined(DEBUG_ENABLED)
42 Debug::Filter* gVisualBaseLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VISUAL_BASE");
45 // visual string constants contains OFFSET_SIZE_MODE instead
46 const char* const OFFSET_POLICY("offsetPolicy");
47 const char* const SIZE_POLICY("sizePolicy");
59 DALI_ENUM_TO_STRING_TABLE_BEGIN(VISUAL_FITTING_MODE)
60 DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_KEEP_ASPECT_RATIO)
61 DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FILL)
62 DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, OVER_FIT_KEEP_ASPECT_RATIO)
63 DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, CENTER)
64 DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_WIDTH)
65 DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_HEIGHT)
66 DALI_ENUM_TO_STRING_TABLE_END(VISUAL_FITTING_MODE)
69 * @brief Check whether this visual type can use corner radius feature or not.
70 * @param type VisualType that want to checkup
71 * @return true if type can use corner radius feature.
73 static bool IsTypeAvailableForCornerRadius(Toolkit::Visual::Type type)
75 switch(static_cast<Toolkit::DevelVisual::Type>(type))
77 case Toolkit::Visual::Type::COLOR:
78 case Toolkit::Visual::Type::GRADIENT:
79 case Toolkit::Visual::Type::IMAGE:
80 case Toolkit::Visual::Type::SVG:
81 case Toolkit::Visual::Type::ANIMATED_IMAGE:
82 case Toolkit::DevelVisual::Type::ANIMATED_VECTOR_IMAGE:
94 * @brief Check whether this visual type can use borderline feature or not.
95 * @param type VisualType that want to checkup
96 * @return true if type can use borderline feature.
98 static bool IsTypeAvailableForBorderline(Toolkit::Visual::Type type)
100 switch(static_cast<Toolkit::DevelVisual::Type>(type))
102 case Toolkit::Visual::Type::COLOR:
103 case Toolkit::Visual::Type::GRADIENT:
104 case Toolkit::Visual::Type::IMAGE:
105 case Toolkit::Visual::Type::SVG:
106 case Toolkit::Visual::Type::ANIMATED_IMAGE:
107 case Toolkit::DevelVisual::Type::ANIMATED_VECTOR_IMAGE:
120 Visual::Base::Base(VisualFactoryCache& factoryCache, FittingMode fittingMode, Toolkit::Visual::Type type)
121 : mImpl(new Impl(fittingMode, type)),
122 mFactoryCache(factoryCache)
126 Visual::Base::~Base()
131 void Visual::Base::Initialize()
133 // The Renderer should be created inside derived class here.
139 RegisterDecoration();
141 if(IsBorderlineRequired())
143 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON_WITHOUT_CULL);
145 else if(IsRoundedCornerRequired())
147 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
152 void Visual::Base::SetCustomShader(const Property::Map& shaderMap)
154 if(mImpl->mCustomShader)
156 mImpl->mCustomShader->SetPropertyMap(shaderMap);
160 mImpl->mCustomShader = new Impl::CustomShader(shaderMap);
163 // Let derived class know
167 void Visual::Base::SetProperties(const Property::Map& propertyMap)
169 bool needUpdateShader = false;
170 for(size_t i = 0; i < propertyMap.Count(); ++i)
172 const KeyValuePair& pair = propertyMap.GetKeyValue(i);
173 const Property::Key& key = pair.first;
174 const Property::Value& value = pair.second;
176 Property::Key matchKey = key;
177 if(matchKey.type == Property::Key::STRING)
179 if(matchKey == CUSTOM_SHADER)
181 matchKey = Property::Key(Toolkit::Visual::Property::SHADER);
183 else if(matchKey == TRANSFORM)
185 matchKey = Property::Key(Toolkit::Visual::Property::TRANSFORM);
187 else if(matchKey == PREMULTIPLIED_ALPHA)
189 matchKey = Property::Key(Toolkit::Visual::Property::PREMULTIPLIED_ALPHA);
191 else if(matchKey == MIX_COLOR)
193 matchKey = Property::Key(Toolkit::Visual::Property::MIX_COLOR);
195 else if(matchKey == OPACITY)
197 matchKey = Property::Key(Toolkit::Visual::Property::OPACITY);
199 else if(matchKey == VISUAL_FITTING_MODE)
201 matchKey = Property::Key(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE);
203 else if(matchKey == BORDERLINE_WIDTH)
205 matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH);
207 else if(matchKey == BORDERLINE_COLOR)
209 matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_COLOR);
211 else if(matchKey == BORDERLINE_OFFSET)
213 matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET);
215 else if(matchKey == CORNER_RADIUS)
217 matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS);
219 else if(matchKey == CORNER_RADIUS_POLICY)
221 matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY);
225 switch(matchKey.indexKey)
227 case Toolkit::Visual::Property::SHADER:
229 Property::Map shaderMap;
230 if(value.Get(shaderMap))
232 SetCustomShader(shaderMap);
237 case Toolkit::Visual::Property::TRANSFORM:
242 mImpl->mTransform.SetPropertyMap(map);
247 case Toolkit::Visual::Property::PREMULTIPLIED_ALPHA:
249 bool premultipliedAlpha = false;
250 if(value.Get(premultipliedAlpha))
252 EnablePreMultipliedAlpha(premultipliedAlpha);
257 case Toolkit::Visual::Property::MIX_COLOR:
260 if(value.Get(mixColor))
262 if(value.GetType() == Property::VECTOR4)
264 SetMixColor(mixColor);
268 Vector3 mixColor3(mixColor);
269 SetMixColor(mixColor3);
274 case Toolkit::Visual::Property::OPACITY:
277 if(value.Get(opacity))
279 mImpl->mMixColor.a = opacity;
280 SetMixColor(mImpl->mMixColor);
284 case Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE:
286 Scripting::GetEnumerationProperty<Visual::FittingMode>(
287 value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode);
290 case Toolkit::DevelVisual::Property::BORDERLINE_WIDTH:
295 mImpl->mBorderlineWidth = width;
298 if(DALI_UNLIKELY(mImpl->mRenderer))
300 // Unusual case. SetProperty called after OnInitialize().
301 // Assume that DoAction call UPDATE_PROPERTY.
302 DownCast<DecoratedVisualRenderer>(mImpl->mRenderer).RegisterBorderlineUniform();
303 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
305 // Check whether we must update shader.
306 if(!mImpl->mAlwaysUsingBorderline && IsBorderlineRequired())
308 // Make Blend mode ON_WITHOUT_CULL for transparent mix color.
309 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON_WITHOUT_CULL);
311 // Change the shader must not be occured many times. we always have to use borderline feature.
312 mImpl->mAlwaysUsingBorderline = true;
315 if(!mImpl->mCustomShader)
317 needUpdateShader = true;
323 case Toolkit::DevelVisual::Property::BORDERLINE_COLOR:
328 mImpl->mBorderlineColor = color;
331 if(DALI_UNLIKELY(mImpl->mRenderer))
333 // Unusual case. SetProperty called after OnInitialize().
334 // Assume that DoAction call UPDATE_PROPERTY.
335 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_COLOR, mImpl->mBorderlineColor);
339 case Toolkit::DevelVisual::Property::BORDERLINE_OFFSET:
342 if(value.Get(offset))
344 mImpl->mBorderlineOffset = offset;
347 if(DALI_UNLIKELY(mImpl->mRenderer))
349 // Unusual case. SetProperty called after OnInitialize().
350 // Assume that DoAction call UPDATE_PROPERTY.
351 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
355 case Toolkit::DevelVisual::Property::CORNER_RADIUS:
357 if(value.GetType() == Property::VECTOR4)
359 // If CORNER_RADIUS Property is Vector4,
360 // Each values mean the radius of
361 // (top-left, top-right, bottom-right, bottom-left)
363 if(value.Get(radius))
365 mImpl->mCornerRadius = radius;
370 // If CORNER_RADIUS Property is float,
371 // Every corner radius have same value
373 if(value.Get(radius))
375 mImpl->mCornerRadius = Vector4(radius, radius, radius, radius);
379 if(DALI_UNLIKELY(mImpl->mRenderer))
381 // Unusual case. SetProperty called after OnInitialize().
382 // Assume that DoAction call UPDATE_PROPERTY.
383 DownCast<DecoratedVisualRenderer>(mImpl->mRenderer).RegisterCornerRadiusUniform();
384 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS, mImpl->mCornerRadius);
386 // Check whether we must update shader.
387 if(!mImpl->mAlwaysUsingCornerRadius && IsRoundedCornerRequired())
389 // Change the shader must not be occured many times. we always have to use corner radius feature.
390 mImpl->mAlwaysUsingCornerRadius = true;
392 if(!IsBorderlineRequired())
394 // If IsBorderlineRequired is true, BLEND_MODE is already BlendMode::ON_WITHOUT_CULL. So we don't overwrite it.
395 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
399 if(!mImpl->mCustomShader)
401 needUpdateShader = true;
408 case Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY:
411 if(value.Get(policy))
415 case Toolkit::Visual::Transform::Policy::RELATIVE:
416 case Toolkit::Visual::Transform::Policy::ABSOLUTE:
418 mImpl->mCornerRadiusPolicy = policy;
419 if(DALI_UNLIKELY(mImpl->mRenderer))
421 // Unusual case. SetProperty called after OnInitialize().
422 // Assume that DoAction call UPDATE_PROPERTY.
423 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
429 DALI_LOG_ERROR("Unsupported policy: %d\n", policy);
439 DoSetProperties(propertyMap);
441 if(DALI_UNLIKELY(needUpdateShader))
447 void Visual::Base::SetTransformAndSize(const Property::Map& transform, Size controlSize)
449 mImpl->mControlSize = controlSize;
450 mImpl->mTransform.UpdatePropertyMap(transform);
452 #if defined(DEBUG_ENABLED)
453 std::ostringstream oss;
455 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);
461 void Visual::Base::SetName(const std::string& name)
466 const std::string& Visual::Base::GetName() const
471 float Visual::Base::GetHeightForWidth(float width)
473 float aspectCorrectedHeight = 0.f;
475 GetNaturalSize(naturalSize);
476 if(naturalSize.width)
478 aspectCorrectedHeight = naturalSize.height * width / naturalSize.width;
480 return aspectCorrectedHeight;
483 float Visual::Base::GetWidthForHeight(float height)
485 float aspectCorrectedWidth = 0.f;
487 GetNaturalSize(naturalSize);
488 if(naturalSize.height > 0.0f)
490 aspectCorrectedWidth = naturalSize.width * height / naturalSize.height;
492 return aspectCorrectedWidth;
495 void Visual::Base::GetNaturalSize(Vector2& naturalSize)
497 naturalSize = Vector2::ZERO;
500 void Visual::Base::DoAction(const Property::Index actionId, const Property::Value attributes)
502 OnDoAction(actionId, attributes);
504 // Check if action is valid for this visual type and perform action if possible
507 case DevelVisual::Action::UPDATE_PROPERTY:
509 const Property::Map* map = attributes.GetMap();
519 void Visual::Base::SetDepthIndex(int index)
521 mImpl->mDepthIndex = index;
524 mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
528 int Visual::Base::GetDepthIndex() const
530 return mImpl->mDepthIndex;
533 void Visual::Base::SetOnScene(Actor& actor)
537 // To display the actor correctly, renderer should not be added to actor until all required resources are ready.
538 // Thus the calling of actor.AddRenderer() should happen inside derived class as base class does not know the exact timing.
543 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
544 mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
547 mImpl->mFlags |= Impl::IS_ON_SCENE;
551 void Visual::Base::SetOffScene(Actor& actor)
555 DoSetOffScene(actor);
556 mImpl->mFlags &= ~Impl::IS_ON_SCENE;
560 void Visual::Base::CreatePropertyMap(Property::Map& map) const
564 // Update values from Renderer
565 mImpl->mMixColor = mImpl->mRenderer.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR);
566 mImpl->mMixColor.a = mImpl->mRenderer.GetProperty<float>(DevelRenderer::Property::OPACITY);
568 mImpl->mTransform.mOffset = mImpl->mRenderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_OFFSET);
569 mImpl->mTransform.mSize = mImpl->mRenderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE);
571 if(IsTypeAvailableForCornerRadius(mImpl->mType))
573 mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::CORNER_RADIUS);
575 if(IsTypeAvailableForBorderline(mImpl->mType))
577 mImpl->mBorderlineWidth = mImpl->mRenderer.GetProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH);
578 mImpl->mBorderlineColor = mImpl->mRenderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR);
579 mImpl->mBorderlineOffset = mImpl->mRenderer.GetProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET);
583 DoCreatePropertyMap(map);
585 if(mImpl->mCustomShader)
587 mImpl->mCustomShader->CreatePropertyMap(map);
590 Property::Map transform;
591 mImpl->mTransform.GetPropertyMap(transform);
592 map.Insert(Toolkit::Visual::Property::TRANSFORM, transform);
594 bool premultipliedAlpha(IsPreMultipliedAlphaEnabled());
595 map.Insert(Toolkit::Visual::Property::PREMULTIPLIED_ALPHA, premultipliedAlpha);
597 // Note, Color and Primitive will also insert their own mix color into the map
598 // which is ok, because they have a different key value range, but uses same cached value anyway.
599 map.Insert(Toolkit::Visual::Property::MIX_COLOR, mImpl->mMixColor); // vec4
600 map.Insert(Toolkit::Visual::Property::OPACITY, mImpl->mMixColor.a);
602 auto fittingModeString = Scripting::GetLinearEnumerationName<FittingMode>(
603 mImpl->mFittingMode, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT);
604 map.Insert(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE, fittingModeString);
606 if(IsTypeAvailableForBorderline(mImpl->mType))
608 map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
609 map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, mImpl->mBorderlineColor);
610 map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
613 if(IsTypeAvailableForCornerRadius(mImpl->mType))
615 map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius);
616 map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, static_cast<int>(mImpl->mCornerRadiusPolicy));
620 void Visual::Base::CreateInstancePropertyMap(Property::Map& map) const
622 DoCreateInstancePropertyMap(map);
624 if(mImpl->mCustomShader)
626 mImpl->mCustomShader->CreatePropertyMap(map);
630 void Visual::Base::EnablePreMultipliedAlpha(bool preMultiplied)
634 mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
638 mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA;
643 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultiplied);
644 mImpl->mRenderer.SetProperty(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA, preMultiplied);
648 bool Visual::Base::IsPreMultipliedAlphaEnabled() const
650 return mImpl->mFlags & Impl::IS_PREMULTIPLIED_ALPHA;
653 void Visual::Base::DoSetOffScene(Actor& actor)
655 actor.RemoveRenderer(mImpl->mRenderer);
658 bool Visual::Base::IsOnScene() const
660 return mImpl->mFlags & Impl::IS_ON_SCENE;
663 bool Visual::Base::IsRoundedCornerRequired() const
665 // If VisualType doesn't support rounded corner, always return false.
666 if(IsTypeAvailableForCornerRadius(mImpl->mType))
670 // Update values from Renderer
671 Property::Value value = mImpl->mRenderer.GetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS);
672 value.Get(mImpl->mCornerRadius);
674 return mImpl->mAlwaysUsingCornerRadius || !(mImpl->mCornerRadius == Vector4::ZERO);
679 bool Visual::Base::IsBorderlineRequired() const
681 // If VisualType doesn't support borderline, always return false.
682 if(IsTypeAvailableForBorderline(mImpl->mType))
686 // Update values from Renderer
687 Property::Value value = mImpl->mRenderer.GetProperty(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH);
688 value.Get(mImpl->mBorderlineWidth);
690 return mImpl->mAlwaysUsingBorderline || !EqualsZero(mImpl->mBorderlineWidth);
695 void Visual::Base::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
697 // May be overriden by derived class
700 void Visual::Base::RegisterMixColor()
704 // All visual renderers now use same mix color / opacity properties.
705 mImpl->mRenderer.SetProperty(VisualRenderer::Property::VISUAL_MIX_COLOR, Vector3(mImpl->mMixColor));
706 mImpl->mRenderer.SetProperty(DevelRenderer::Property::OPACITY, mImpl->mMixColor.a);
708 float preMultipliedAlpha = 0.0f;
709 if(IsPreMultipliedAlphaEnabled())
711 preMultipliedAlpha = 1.0f;
713 mImpl->mRenderer.SetProperty(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA, preMultipliedAlpha);
717 void Visual::Base::RegisterDecoration()
721 if(IsTypeAvailableForCornerRadius(mImpl->mType))
723 if(mImpl->mAlwaysUsingCornerRadius || !(mImpl->mCornerRadius == Vector4::ZERO))
725 DownCast<DecoratedVisualRenderer>(mImpl->mRenderer).RegisterCornerRadiusUniform();
726 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS, mImpl->mCornerRadius);
727 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
730 if(IsTypeAvailableForBorderline(mImpl->mType))
732 if(mImpl->mAlwaysUsingBorderline || !EqualsZero(mImpl->mBorderlineWidth))
734 DownCast<DecoratedVisualRenderer>(mImpl->mRenderer).RegisterBorderlineUniform();
735 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
736 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_COLOR, mImpl->mBorderlineColor);
737 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
743 void Visual::Base::SetMixColor(const Vector4& color)
745 mImpl->mMixColor = color;
749 mImpl->mRenderer.SetProperty(VisualRenderer::Property::VISUAL_MIX_COLOR, Vector3(color));
750 mImpl->mRenderer.SetProperty(DevelRenderer::Property::OPACITY, color.a);
754 void Visual::Base::SetMixColor(const Vector3& color)
756 mImpl->mMixColor.r = color.r;
757 mImpl->mMixColor.g = color.g;
758 mImpl->mMixColor.b = color.b;
762 mImpl->mRenderer.SetProperty(VisualRenderer::Property::VISUAL_MIX_COLOR, color);
766 void Visual::Base::AddEventObserver(Visual::EventObserver& observer)
768 mImpl->mEventObserver = &observer;
771 void Visual::Base::RemoveEventObserver(Visual::EventObserver& observer)
773 mImpl->mEventObserver = NULL;
776 void Visual::Base::ResourceReady(Toolkit::Visual::ResourceStatus resourceStatus)
778 if(mImpl->mResourceStatus != resourceStatus)
780 mImpl->mResourceStatus = resourceStatus;
782 if(mImpl->mEventObserver)
784 // observer is currently a control impl
785 mImpl->mEventObserver->ResourceReady(*this);
790 bool Visual::Base::IsResourceReady() const
792 return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
793 mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED);
796 bool Visual::Base::IsSynchronousLoadingRequired() const
798 return (mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING);
801 Toolkit::Visual::Type Visual::Base::GetType() const
806 Toolkit::Visual::ResourceStatus Visual::Base::GetResourceStatus() const
808 return mImpl->mResourceStatus;
811 Visual::FittingMode Visual::Base::GetFittingMode() const
813 return mImpl->mFittingMode;
816 Visual::Base& Visual::Base::GetVisualObject()
821 Renderer Visual::Base::GetRenderer()
823 return mImpl->mRenderer;
826 Property::Index Visual::Base::GetIntKey(Property::Key key)
828 if(key.type == Property::Key::INDEX)
833 if(key.stringKey == ANCHOR_POINT)
835 return Toolkit::Visual::Transform::Property::ANCHOR_POINT;
837 else if(key.stringKey == EXTRA_SIZE)
839 return Toolkit::DevelVisual::Transform::Property::EXTRA_SIZE;
841 else if(key.stringKey == MIX_COLOR)
843 return Toolkit::Visual::Property::MIX_COLOR;
845 else if(key.stringKey == OPACITY)
847 return Toolkit::Visual::Property::OPACITY;
849 else if(key.stringKey == OFFSET)
851 return Toolkit::Visual::Transform::Property::OFFSET;
853 else if(key.stringKey == OFFSET_POLICY)
855 return Toolkit::Visual::Transform::Property::OFFSET_POLICY;
857 else if(key.stringKey == ORIGIN)
859 return Toolkit::Visual::Transform::Property::ORIGIN;
861 else if(key.stringKey == PREMULTIPLIED_ALPHA)
863 return Toolkit::Visual::Property::PREMULTIPLIED_ALPHA;
865 else if(key.stringKey == CUSTOM_SHADER)
867 return Toolkit::Visual::Property::SHADER;
869 else if(key.stringKey == SIZE)
871 return Toolkit::Visual::Transform::Property::SIZE;
873 else if(key.stringKey == SIZE_POLICY)
875 return Toolkit::Visual::Transform::Property::SIZE_POLICY;
877 else if(key.stringKey == TRANSFORM)
879 return Toolkit::Visual::Property::TRANSFORM;
881 else if(key.stringKey == VISUAL_FITTING_MODE)
883 return Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE;
885 else if(key.stringKey == CORNER_RADIUS)
887 return Toolkit::DevelVisual::Property::CORNER_RADIUS;
889 else if(key.stringKey == CORNER_RADIUS_POLICY)
891 return Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY;
893 else if(key.stringKey == BORDERLINE_WIDTH)
895 return Toolkit::DevelVisual::Property::BORDERLINE_WIDTH;
897 else if(key.stringKey == BORDERLINE_COLOR)
899 return Toolkit::DevelVisual::Property::BORDERLINE_COLOR;
901 else if(key.stringKey == BORDERLINE_OFFSET)
903 return Toolkit::DevelVisual::Property::BORDERLINE_OFFSET;
906 return Property::INVALID_INDEX;
909 Property::Index Visual::Base::GetPropertyIndex(Property::Key key)
911 switch(GetIntKey(key))
913 case Dali::Toolkit::Visual::Transform::Property::OFFSET:
915 return VisualRenderer::Property::TRANSFORM_OFFSET;
917 case Dali::Toolkit::Visual::Transform::Property::SIZE:
919 return VisualRenderer::Property::TRANSFORM_SIZE;
921 case Dali::Toolkit::Visual::Transform::Property::ORIGIN:
923 return VisualRenderer::Property::TRANSFORM_ORIGIN;
925 case Dali::Toolkit::Visual::Transform::Property::ANCHOR_POINT:
927 return VisualRenderer::Property::TRANSFORM_ANCHOR_POINT;
929 case Dali::Toolkit::Visual::Property::MIX_COLOR:
931 return VisualRenderer::Property::VISUAL_MIX_COLOR;
933 case Dali::Toolkit::Visual::Property::OPACITY:
935 return DevelRenderer::Property::OPACITY;
937 case Dali::Toolkit::Visual::Property::PREMULTIPLIED_ALPHA:
939 return VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA;
941 case Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS:
943 return DecoratedVisualRenderer::Property::CORNER_RADIUS;
945 case Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH:
947 return DecoratedVisualRenderer::Property::BORDERLINE_WIDTH;
949 case Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR:
951 return DecoratedVisualRenderer::Property::BORDERLINE_COLOR;
953 case Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET:
955 return DecoratedVisualRenderer::Property::BORDERLINE_OFFSET;
959 Property::Index index = mImpl->mRenderer.GetPropertyIndex(key);
961 if(index == Property::INVALID_INDEX)
963 // Is it a shader property?
964 Shader shader = mImpl->mRenderer.GetShader();
965 index = shader.GetPropertyIndex(key);
966 if(index != Property::INVALID_INDEX)
968 // Yes - we should register it in the Renderer so it can be set / animated
969 // independently, as shaders are shared across multiple renderers.
971 Property::Index keyIndex(Property::INVALID_KEY);
972 if(key.type == Property::Key::INDEX)
974 keyName = shader.GetPropertyName(index);
975 keyIndex = key.indexKey;
979 keyName = key.stringKey;
980 // Leave keyIndex as INVALID_KEY - it can still be registered against the string key.
982 Property::Value value = shader.GetProperty(index);
984 // We already know that mRenderer didn't have property. So we can assume that it is unique.
985 index = mImpl->mRenderer.RegisterUniqueProperty(keyIndex, keyName, value);
991 void Visual::Base::SetupTransition(
992 Dali::Animation& transition,
993 Internal::TransitionData::Animator& animator,
994 Property::Index index,
995 Property::Value& initialValue,
996 Property::Value& targetValue)
998 if(index != Property::INVALID_INDEX)
1000 if(mImpl->mRenderer)
1002 if(animator.animate == false)
1004 mImpl->mRenderer.SetProperty(index, targetValue);
1008 if(animator.initialValue.GetType() != Property::NONE)
1010 mImpl->mRenderer.SetProperty(index, initialValue);
1015 transition = Dali::Animation::New(0.1f);
1018 transition.AnimateTo(Property(mImpl->mRenderer, index),
1020 animator.alphaFunction,
1021 TimePeriod(animator.timePeriodDelay,
1022 animator.timePeriodDuration));
1028 void Visual::Base::AnimateProperty(
1029 Dali::Animation& transition,
1030 Internal::TransitionData::Animator& animator)
1032 #if defined(DEBUG_ENABLED)
1033 if(gVisualBaseLogFilter->IsEnabledFor(Debug::General))
1035 std::ostringstream oss;
1036 oss << "Visual::Base::AnimateProperty(Visual:" << mImpl->mName << " Property:" << animator.propertyKey << " Target: " << animator.targetValue << std::endl;
1037 DALI_LOG_INFO(gVisualBaseLogFilter, Debug::General, oss.str().c_str());
1041 if(animator.propertyKey == Toolkit::Visual::Property::MIX_COLOR ||
1042 animator.propertyKey == MIX_COLOR ||
1043 (mImpl->mType == Toolkit::Visual::COLOR &&
1044 animator.propertyKey == ColorVisual::Property::MIX_COLOR) ||
1045 (mImpl->mType == Toolkit::Visual::PRIMITIVE &&
1046 animator.propertyKey == PrimitiveVisual::Property::MIX_COLOR))
1048 AnimateMixColorProperty(transition, animator);
1050 else if(animator.propertyKey == Toolkit::Visual::Property::OPACITY ||
1051 animator.propertyKey == OPACITY)
1053 AnimateOpacityProperty(transition, animator);
1055 else if(mImpl->mRenderer)
1057 AnimateRendererProperty(transition, animator);
1061 void Visual::Base::AnimateOpacityProperty(
1062 Dali::Animation& transition,
1063 Internal::TransitionData::Animator& animator)
1065 float targetOpacity;
1066 if(animator.targetValue.Get(targetOpacity))
1068 mImpl->mMixColor.a = targetOpacity;
1071 SetupTransition(transition, animator, DevelRenderer::Property::OPACITY, animator.initialValue, animator.targetValue);
1074 void Visual::Base::AnimateRendererProperty(
1075 Dali::Animation& transition,
1076 Internal::TransitionData::Animator& animator)
1078 // Get actual renderer index (will convert transform keys into visualproperty indices)
1079 Property::Index index = GetPropertyIndex(animator.propertyKey);
1081 if(index != Property::INVALID_INDEX)
1083 if(animator.targetValue.GetType() != Property::NONE)
1085 // Try writing target value into transform property map
1086 // if it's not a valid key, then it won't alter mTransform
1088 if(animator.propertyKey.type == Property::Key::INDEX)
1090 map.Add(animator.propertyKey.indexKey, animator.targetValue);
1094 map.Add(animator.propertyKey.stringKey, animator.targetValue);
1097 mImpl->mTransform.UpdatePropertyMap(map);
1099 SetupTransition(transition, animator, index, animator.initialValue, animator.targetValue);
1103 void Visual::Base::AnimateMixColorProperty(
1104 Dali::Animation& transition,
1105 Internal::TransitionData::Animator& animator)
1107 bool animateOpacity = false;
1109 Property::Value initialOpacity;
1110 Property::Value targetOpacity;
1111 Property::Value initialMixColor;
1112 Property::Value targetMixColor;
1114 Vector4 initialColor;
1115 if(animator.initialValue.Get(initialColor))
1117 if(animator.initialValue.GetType() == Property::VECTOR4)
1119 // if there is an initial color specifying alpha, test it
1120 initialOpacity = initialColor.a;
1122 initialMixColor = Vector3(initialColor);
1125 // Set target value into data store
1126 if(animator.targetValue.GetType() != Property::NONE)
1129 animator.targetValue.Get(mixColor);
1130 if(animator.targetValue.GetType() == Property::VECTOR4)
1132 mImpl->mMixColor.a = mixColor.a;
1133 targetOpacity = mixColor.a;
1134 animateOpacity = true;
1137 mImpl->mMixColor.r = mixColor.r;
1138 mImpl->mMixColor.g = mixColor.g;
1139 mImpl->mMixColor.b = mixColor.b;
1140 targetMixColor = Vector3(mixColor);
1143 SetupTransition(transition, animator, VisualRenderer::Property::VISUAL_MIX_COLOR, initialMixColor, targetMixColor);
1147 SetupTransition(transition, animator, DevelRenderer::Property::OPACITY, initialOpacity, targetOpacity);
1151 Dali::Property Visual::Base::GetPropertyObject(Dali::Property::Key key)
1153 if(!mImpl->mRenderer)
1156 return Dali::Property(handle, Property::INVALID_INDEX);
1159 switch(GetIntKey(key))
1161 // Default animatable properties from VisualRenderer
1162 case Toolkit::Visual::Property::MIX_COLOR:
1164 return Dali::Property(mImpl->mRenderer, VisualRenderer::Property::VISUAL_MIX_COLOR);
1166 case Toolkit::Visual::Property::OPACITY:
1168 return Dali::Property(mImpl->mRenderer, DevelRenderer::Property::OPACITY);
1170 case Toolkit::Visual::Transform::Property::OFFSET:
1172 return Dali::Property(mImpl->mRenderer, VisualRenderer::Property::TRANSFORM_OFFSET);
1174 case Toolkit::Visual::Transform::Property::SIZE:
1176 return Dali::Property(mImpl->mRenderer, VisualRenderer::Property::TRANSFORM_SIZE);
1179 // Default animatable properties from DecoratedVisualRenderer
1180 case Toolkit::DevelVisual::Property::CORNER_RADIUS:
1182 if(IsTypeAvailableForCornerRadius(mImpl->mType))
1184 const bool updateShader = !mImpl->mCustomShader && !IsRoundedCornerRequired();
1186 // CornerRadius is animated now. we always have to use corner radius feature.
1187 mImpl->mAlwaysUsingCornerRadius = true;
1191 // Update each values to renderer
1192 DownCast<DecoratedVisualRenderer>(mImpl->mRenderer).RegisterCornerRadiusUniform();
1193 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS, mImpl->mCornerRadius);
1194 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
1199 if(!IsBorderlineRequired())
1201 // If IsBorderlineRequired is true, BLEND_MODE is already BlendMode::ON_WITHOUT_CULL. So we don't overwrite it.
1202 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
1204 return Dali::Property(mImpl->mRenderer, DecoratedVisualRenderer::Property::CORNER_RADIUS);
1208 case Toolkit::DevelVisual::Property::BORDERLINE_WIDTH:
1209 case Toolkit::DevelVisual::Property::BORDERLINE_COLOR:
1210 case Toolkit::DevelVisual::Property::BORDERLINE_OFFSET:
1212 if(IsTypeAvailableForBorderline(mImpl->mType))
1214 const bool updateShader = !mImpl->mCustomShader && !IsBorderlineRequired();
1216 // Borderline is animated now. we always have to use borderline feature.
1217 mImpl->mAlwaysUsingBorderline = true;
1221 // Update each values to renderer
1222 DownCast<DecoratedVisualRenderer>(mImpl->mRenderer).RegisterBorderlineUniform();
1223 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
1224 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_COLOR, mImpl->mBorderlineColor);
1225 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
1230 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON_WITHOUT_CULL);
1232 return Dali::Property(mImpl->mRenderer, GetPropertyIndex(key));
1236 // Special case for MIX_COLOR
1239 if(key.type == Property::Key::INDEX &&
1240 ((mImpl->mType == Toolkit::Visual::COLOR && key.indexKey == ColorVisual::Property::MIX_COLOR) ||
1241 (mImpl->mType == Toolkit::Visual::PRIMITIVE && key.indexKey == PrimitiveVisual::Property::MIX_COLOR)))
1243 return Dali::Property(mImpl->mRenderer, VisualRenderer::Property::VISUAL_MIX_COLOR);
1248 // We can't find the property in the base class.
1249 // Request to child class
1250 return OnGetPropertyObject(key);
1253 } // namespace Internal
1255 } // namespace Toolkit