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)
1034 std::ostringstream oss;
1035 oss << "Visual::Base::AnimateProperty(Visual:" << mImpl->mName << " Property:" << animator.propertyKey << " Target: " << animator.targetValue << std::endl;
1036 DALI_LOG_INFO(gVisualBaseLogFilter, Debug::General, oss.str().c_str());
1040 if(animator.propertyKey == Toolkit::Visual::Property::MIX_COLOR ||
1041 animator.propertyKey == MIX_COLOR ||
1042 (mImpl->mType == Toolkit::Visual::COLOR &&
1043 animator.propertyKey == ColorVisual::Property::MIX_COLOR) ||
1044 (mImpl->mType == Toolkit::Visual::PRIMITIVE &&
1045 animator.propertyKey == PrimitiveVisual::Property::MIX_COLOR))
1047 AnimateMixColorProperty(transition, animator);
1049 else if(animator.propertyKey == Toolkit::Visual::Property::OPACITY ||
1050 animator.propertyKey == OPACITY)
1052 AnimateOpacityProperty(transition, animator);
1054 else if(mImpl->mRenderer)
1056 AnimateRendererProperty(transition, animator);
1060 void Visual::Base::AnimateOpacityProperty(
1061 Dali::Animation& transition,
1062 Internal::TransitionData::Animator& animator)
1064 float targetOpacity;
1065 if(animator.targetValue.Get(targetOpacity))
1067 mImpl->mMixColor.a = targetOpacity;
1070 SetupTransition(transition, animator, DevelRenderer::Property::OPACITY, animator.initialValue, animator.targetValue);
1073 void Visual::Base::AnimateRendererProperty(
1074 Dali::Animation& transition,
1075 Internal::TransitionData::Animator& animator)
1077 // Get actual renderer index (will convert transform keys into visualproperty indices)
1078 Property::Index index = GetPropertyIndex(animator.propertyKey);
1080 if(index != Property::INVALID_INDEX)
1082 if(animator.targetValue.GetType() != Property::NONE)
1084 // Try writing target value into transform property map
1085 // if it's not a valid key, then it won't alter mTransform
1087 if(animator.propertyKey.type == Property::Key::INDEX)
1089 map.Add(animator.propertyKey.indexKey, animator.targetValue);
1093 map.Add(animator.propertyKey.stringKey, animator.targetValue);
1096 mImpl->mTransform.UpdatePropertyMap(map);
1098 SetupTransition(transition, animator, index, animator.initialValue, animator.targetValue);
1102 void Visual::Base::AnimateMixColorProperty(
1103 Dali::Animation& transition,
1104 Internal::TransitionData::Animator& animator)
1106 bool animateOpacity = false;
1108 Property::Value initialOpacity;
1109 Property::Value targetOpacity;
1110 Property::Value initialMixColor;
1111 Property::Value targetMixColor;
1113 Vector4 initialColor;
1114 if(animator.initialValue.Get(initialColor))
1116 if(animator.initialValue.GetType() == Property::VECTOR4)
1118 // if there is an initial color specifying alpha, test it
1119 initialOpacity = initialColor.a;
1121 initialMixColor = Vector3(initialColor);
1124 // Set target value into data store
1125 if(animator.targetValue.GetType() != Property::NONE)
1128 animator.targetValue.Get(mixColor);
1129 if(animator.targetValue.GetType() == Property::VECTOR4)
1131 mImpl->mMixColor.a = mixColor.a;
1132 targetOpacity = mixColor.a;
1133 animateOpacity = true;
1136 mImpl->mMixColor.r = mixColor.r;
1137 mImpl->mMixColor.g = mixColor.g;
1138 mImpl->mMixColor.b = mixColor.b;
1139 targetMixColor = Vector3(mixColor);
1142 SetupTransition(transition, animator, VisualRenderer::Property::VISUAL_MIX_COLOR, initialMixColor, targetMixColor);
1146 SetupTransition(transition, animator, DevelRenderer::Property::OPACITY, initialOpacity, targetOpacity);
1150 Dali::Property Visual::Base::GetPropertyObject(Dali::Property::Key key)
1152 if(!mImpl->mRenderer)
1155 return Dali::Property(handle, Property::INVALID_INDEX);
1158 switch(GetIntKey(key))
1160 // Default animatable properties from VisualRenderer
1161 case Toolkit::Visual::Property::MIX_COLOR:
1163 return Dali::Property(mImpl->mRenderer, VisualRenderer::Property::VISUAL_MIX_COLOR);
1165 case Toolkit::Visual::Property::OPACITY:
1167 return Dali::Property(mImpl->mRenderer, DevelRenderer::Property::OPACITY);
1169 case Toolkit::Visual::Transform::Property::OFFSET:
1171 return Dali::Property(mImpl->mRenderer, VisualRenderer::Property::TRANSFORM_OFFSET);
1173 case Toolkit::Visual::Transform::Property::SIZE:
1175 return Dali::Property(mImpl->mRenderer, VisualRenderer::Property::TRANSFORM_SIZE);
1178 // Default animatable properties from DecoratedVisualRenderer
1179 case Toolkit::DevelVisual::Property::CORNER_RADIUS:
1181 if(IsTypeAvailableForCornerRadius(mImpl->mType))
1183 const bool updateShader = !mImpl->mCustomShader && !IsRoundedCornerRequired();
1185 // CornerRadius is animated now. we always have to use corner radius feature.
1186 mImpl->mAlwaysUsingCornerRadius = true;
1190 // Update each values to renderer
1191 DownCast<DecoratedVisualRenderer>(mImpl->mRenderer).RegisterCornerRadiusUniform();
1192 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS, mImpl->mCornerRadius);
1193 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
1198 if(!IsBorderlineRequired())
1200 // If IsBorderlineRequired is true, BLEND_MODE is already BlendMode::ON_WITHOUT_CULL. So we don't overwrite it.
1201 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
1203 return Dali::Property(mImpl->mRenderer, DecoratedVisualRenderer::Property::CORNER_RADIUS);
1207 case Toolkit::DevelVisual::Property::BORDERLINE_WIDTH:
1208 case Toolkit::DevelVisual::Property::BORDERLINE_COLOR:
1209 case Toolkit::DevelVisual::Property::BORDERLINE_OFFSET:
1211 if(IsTypeAvailableForBorderline(mImpl->mType))
1213 const bool updateShader = !mImpl->mCustomShader && !IsBorderlineRequired();
1215 // Borderline is animated now. we always have to use borderline feature.
1216 mImpl->mAlwaysUsingBorderline = true;
1220 // Update each values to renderer
1221 DownCast<DecoratedVisualRenderer>(mImpl->mRenderer).RegisterBorderlineUniform();
1222 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
1223 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_COLOR, mImpl->mBorderlineColor);
1224 mImpl->mRenderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
1229 mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON_WITHOUT_CULL);
1231 return Dali::Property(mImpl->mRenderer, GetPropertyIndex(key));
1235 // Special case for MIX_COLOR
1238 if(key.type == Property::Key::INDEX &&
1239 ((mImpl->mType == Toolkit::Visual::COLOR && key.indexKey == ColorVisual::Property::MIX_COLOR) ||
1240 (mImpl->mType == Toolkit::Visual::PRIMITIVE && key.indexKey == PrimitiveVisual::Property::MIX_COLOR)))
1242 return Dali::Property(mImpl->mRenderer, VisualRenderer::Property::VISUAL_MIX_COLOR);
1247 // We can't find the property in the base class.
1248 // Request to child class
1249 return OnGetPropertyObject(key);
1252 } // namespace Internal
1254 } // namespace Toolkit