Merge branch 'devel/master' into devel/graphics
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-base-impl.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "visual-base-impl.h"
20
21 // EXTERNAL HEADER
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
27 //INTERNAL HEARDER
28 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
29 #include <dali-toolkit/internal/helpers/property-helper.h>
30 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
31 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
32 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
33 #include <dali-toolkit/public-api/visuals/primitive-visual-properties.h>
34 #include <dali-toolkit/public-api/visuals/visual-properties.h>
35
36 namespace
37 {
38 #if defined(DEBUG_ENABLED)
39 Debug::Filter* gVisualBaseLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VISUAL_BASE");
40 #endif
41
42 const char* const PRE_MULTIPLIED_ALPHA_PROPERTY("preMultipliedAlpha");
43
44 } // namespace
45
46 namespace Dali
47 {
48 namespace Toolkit
49 {
50 namespace Internal
51 {
52 namespace
53 {
54 DALI_ENUM_TO_STRING_TABLE_BEGIN(VISUAL_FITTING_MODE)
55   DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_KEEP_ASPECT_RATIO)
56   DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FILL)
57   DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, OVER_FIT_KEEP_ASPECT_RATIO)
58   DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, CENTER)
59   DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_WIDTH)
60   DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_HEIGHT)
61 DALI_ENUM_TO_STRING_TABLE_END(VISUAL_FITTING_MODE)
62
63 } // namespace
64
65 Visual::Base::Base(VisualFactoryCache& factoryCache, FittingMode fittingMode, Toolkit::Visual::Type type)
66 : mImpl(new Impl(fittingMode, type)),
67   mFactoryCache(factoryCache)
68 {
69 }
70
71 Visual::Base::~Base()
72 {
73   delete mImpl;
74 }
75
76 void Visual::Base::Initialize()
77 {
78   // The Renderer should be created inside derived class here.
79   OnInitialize();
80
81   if(mImpl->mRenderer)
82   {
83     RegisterMixColor();
84
85     if(IsRoundedCornerRequired())
86     {
87       mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius);
88       mImpl->mRenderer.RegisterProperty(CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
89
90       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
91     }
92   }
93 }
94
95 void Visual::Base::SetCustomShader(const Property::Map& shaderMap)
96 {
97   if(mImpl->mCustomShader)
98   {
99     mImpl->mCustomShader->SetPropertyMap(shaderMap);
100   }
101   else
102   {
103     mImpl->mCustomShader = new Impl::CustomShader(shaderMap);
104   }
105
106   // Let derived class know
107   UpdateShader();
108 }
109
110 void Visual::Base::SetProperties(const Property::Map& propertyMap)
111 {
112   for(size_t i = 0; i < propertyMap.Count(); ++i)
113   {
114     const KeyValuePair&    pair  = propertyMap.GetKeyValue(i);
115     const Property::Key&   key   = pair.first;
116     const Property::Value& value = pair.second;
117
118     Property::Key matchKey = key;
119     if(matchKey.type == Property::Key::STRING)
120     {
121       if(matchKey == CUSTOM_SHADER)
122       {
123         matchKey = Property::Key(Toolkit::Visual::Property::SHADER);
124       }
125       else if(matchKey == TRANSFORM)
126       {
127         matchKey = Property::Key(Toolkit::Visual::Property::TRANSFORM);
128       }
129       else if(matchKey == PREMULTIPLIED_ALPHA)
130       {
131         matchKey = Property::Key(Toolkit::Visual::Property::PREMULTIPLIED_ALPHA);
132       }
133       else if(matchKey == MIX_COLOR)
134       {
135         matchKey = Property::Key(Toolkit::Visual::Property::MIX_COLOR);
136       }
137       else if(matchKey == OPACITY)
138       {
139         matchKey = Property::Key(Toolkit::Visual::Property::OPACITY);
140       }
141       else if(matchKey == VISUAL_FITTING_MODE)
142       {
143         matchKey = Property::Key(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE);
144       }
145       else if(matchKey == CORNER_RADIUS)
146       {
147         matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS);
148       }
149       else if(matchKey == CORNER_RADIUS_POLICY)
150       {
151         matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY);
152       }
153     }
154
155     switch(matchKey.indexKey)
156     {
157       case Toolkit::Visual::Property::SHADER:
158       {
159         Property::Map shaderMap;
160         if(value.Get(shaderMap))
161         {
162           SetCustomShader(shaderMap);
163         }
164         break;
165       }
166
167       case Toolkit::Visual::Property::TRANSFORM:
168       {
169         Property::Map map;
170         if(value.Get(map))
171         {
172           mImpl->mTransform.SetPropertyMap(map);
173         }
174         break;
175       }
176
177       case Toolkit::Visual::Property::PREMULTIPLIED_ALPHA:
178       {
179         bool premultipliedAlpha = false;
180         if(value.Get(premultipliedAlpha))
181         {
182           EnablePreMultipliedAlpha(premultipliedAlpha);
183         }
184         break;
185       }
186
187       case Toolkit::Visual::Property::MIX_COLOR:
188       {
189         Vector4 mixColor;
190         if(value.Get(mixColor))
191         {
192           if(value.GetType() == Property::VECTOR4)
193           {
194             SetMixColor(mixColor);
195           }
196           else
197           {
198             Vector3 mixColor3(mixColor);
199             SetMixColor(mixColor3);
200           }
201         }
202         break;
203       }
204       case Toolkit::Visual::Property::OPACITY:
205       {
206         float opacity;
207         if(value.Get(opacity))
208         {
209           mImpl->mMixColor.a = opacity;
210           SetMixColor(mImpl->mMixColor);
211         }
212         break;
213       }
214       case Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE:
215       {
216         Scripting::GetEnumerationProperty<Visual::FittingMode>(
217           value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode);
218         break;
219       }
220       case Toolkit::DevelVisual::Property::CORNER_RADIUS:
221       {
222         float radius;
223         if(value.Get(radius))
224         {
225           mImpl->mCornerRadius = radius;
226         }
227         break;
228       }
229       case Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY:
230       {
231         int policy;
232         if(value.Get(policy))
233         {
234           switch(policy)
235           {
236             case Toolkit::Visual::Transform::Policy::RELATIVE:
237             case Toolkit::Visual::Transform::Policy::ABSOLUTE:
238             {
239               mImpl->mCornerRadiusPolicy = policy;
240               break;
241             }
242             default:
243             {
244               DALI_LOG_ERROR("Unsupported policy: %d\n", policy);
245               break;
246             }
247           }
248         }
249         break;
250       }
251     }
252   }
253
254   DoSetProperties(propertyMap);
255 }
256
257 void Visual::Base::SetTransformAndSize(const Property::Map& transform, Size controlSize)
258 {
259   mImpl->mControlSize = controlSize;
260   mImpl->mTransform.UpdatePropertyMap(transform);
261
262 #if defined(DEBUG_ENABLED)
263   std::ostringstream oss;
264   oss << transform;
265   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);
266 #endif
267
268   OnSetTransform();
269 }
270
271 void Visual::Base::SetName(const std::string& name)
272 {
273   mImpl->mName = name;
274 }
275
276 const std::string& Visual::Base::GetName() const
277 {
278   return mImpl->mName;
279 }
280
281 float Visual::Base::GetHeightForWidth(float width)
282 {
283   float   aspectCorrectedHeight = 0.f;
284   Vector2 naturalSize;
285   GetNaturalSize(naturalSize);
286   if(naturalSize.width)
287   {
288     aspectCorrectedHeight = naturalSize.height * width / naturalSize.width;
289   }
290   return aspectCorrectedHeight;
291 }
292
293 float Visual::Base::GetWidthForHeight(float height)
294 {
295   float   aspectCorrectedWidth = 0.f;
296   Vector2 naturalSize;
297   GetNaturalSize(naturalSize);
298   if(naturalSize.height > 0.0f)
299   {
300     aspectCorrectedWidth = naturalSize.width * height / naturalSize.height;
301   }
302   return aspectCorrectedWidth;
303 }
304
305 void Visual::Base::GetNaturalSize(Vector2& naturalSize)
306 {
307   naturalSize = Vector2::ZERO;
308 }
309
310 void Visual::Base::DoAction(const Property::Index actionId, const Property::Value attributes)
311 {
312   OnDoAction(actionId, attributes);
313 }
314
315 void Visual::Base::SetDepthIndex(int index)
316 {
317   mImpl->mDepthIndex = index;
318   if(mImpl->mRenderer)
319   {
320     mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
321   }
322 }
323
324 int Visual::Base::GetDepthIndex() const
325 {
326   return mImpl->mDepthIndex;
327 }
328
329 void Visual::Base::SetOnScene(Actor& actor)
330 {
331   if(!IsOnScene())
332   {
333     // To display the actor correctly, renderer should not be added to actor until all required resources are ready.
334     // Thus the calling of actor.AddRenderer() should happen inside derived class as base class does not know the exact timing.
335     DoSetOnScene(actor);
336
337     if(mImpl->mRenderer)
338     {
339       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
340       mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
341     }
342
343     mImpl->mFlags |= Impl::IS_ON_SCENE;
344   }
345 }
346
347 void Visual::Base::SetOffScene(Actor& actor)
348 {
349   if(IsOnScene())
350   {
351     DoSetOffScene(actor);
352     mImpl->mFlags &= ~Impl::IS_ON_SCENE;
353   }
354 }
355
356 void Visual::Base::CreatePropertyMap(Property::Map& map) const
357 {
358   if(mImpl->mRenderer)
359   {
360     // Update values from Renderer
361     mImpl->mMixColor   = mImpl->mRenderer.GetProperty<Vector3>(mImpl->mMixColorIndex);
362     mImpl->mMixColor.a = mImpl->mRenderer.GetProperty<float>(DevelRenderer::Property::OPACITY);
363     if(mImpl->mTransform.mOffsetIndex != Property::INVALID_INDEX)
364     {
365       mImpl->mTransform.mOffset = mImpl->mRenderer.GetProperty<Vector2>(mImpl->mTransform.mOffsetIndex);
366     }
367     if(mImpl->mTransform.mSizeIndex != Property::INVALID_INDEX)
368     {
369       mImpl->mTransform.mSize = mImpl->mRenderer.GetProperty<Vector2>(mImpl->mTransform.mSizeIndex);
370     }
371     if(mImpl->mCornerRadiusIndex != Property::INVALID_INDEX)
372     {
373       mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<float>(mImpl->mCornerRadiusIndex);
374     }
375   }
376
377   DoCreatePropertyMap(map);
378
379   if(mImpl->mCustomShader)
380   {
381     mImpl->mCustomShader->CreatePropertyMap(map);
382   }
383
384   Property::Map transform;
385   mImpl->mTransform.GetPropertyMap(transform);
386   map.Insert(Toolkit::Visual::Property::TRANSFORM, transform);
387
388   bool premultipliedAlpha(IsPreMultipliedAlphaEnabled());
389   map.Insert(Toolkit::Visual::Property::PREMULTIPLIED_ALPHA, premultipliedAlpha);
390
391   // Note, Color and Primitive will also insert their own mix color into the map
392   // which is ok, because they have a different key value range.
393   map.Insert(Toolkit::Visual::Property::MIX_COLOR, mImpl->mMixColor); // vec4
394   map.Insert(Toolkit::Visual::Property::OPACITY, mImpl->mMixColor.a);
395
396   auto fittingModeString = Scripting::GetLinearEnumerationName<FittingMode>(
397     mImpl->mFittingMode, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT);
398   map.Insert(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE, fittingModeString);
399
400   map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius);
401   map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, static_cast<int>(mImpl->mCornerRadiusPolicy));
402 }
403
404 void Visual::Base::CreateInstancePropertyMap(Property::Map& map) const
405 {
406   DoCreateInstancePropertyMap(map);
407
408   if(mImpl->mCustomShader)
409   {
410     mImpl->mCustomShader->CreatePropertyMap(map);
411   }
412 }
413
414 void Visual::Base::EnablePreMultipliedAlpha(bool preMultiplied)
415 {
416   if(preMultiplied)
417   {
418     mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
419   }
420   else
421   {
422     mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA;
423   }
424
425   if(mImpl->mRenderer)
426   {
427     mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultiplied);
428     mImpl->mRenderer.RegisterProperty(PRE_MULTIPLIED_ALPHA_PROPERTY, static_cast<float>(preMultiplied));
429   }
430 }
431
432 bool Visual::Base::IsPreMultipliedAlphaEnabled() const
433 {
434   return mImpl->mFlags & Impl::IS_PREMULTIPLIED_ALPHA;
435 }
436
437 void Visual::Base::DoSetOffScene(Actor& actor)
438 {
439   actor.RemoveRenderer(mImpl->mRenderer);
440 }
441
442 bool Visual::Base::IsOnScene() const
443 {
444   return mImpl->mFlags & Impl::IS_ON_SCENE;
445 }
446
447 bool Visual::Base::IsRoundedCornerRequired() const
448 {
449   if(mImpl->mRenderer && mImpl->mCornerRadiusIndex != Property::INVALID_INDEX)
450   {
451     // Update values from Renderer
452     mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<float>(mImpl->mCornerRadiusIndex);
453   }
454   return !EqualsZero(mImpl->mCornerRadius) || mImpl->mNeedCornerRadius;
455 }
456
457 void Visual::Base::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
458 {
459   // May be overriden by derived class
460 }
461
462 void Visual::Base::RegisterMixColor()
463 {
464   // Only register if not already registered.
465   // (Color and Primitive visuals will register their own and save to this index)
466   if(mImpl->mMixColorIndex == Property::INVALID_INDEX)
467   {
468     mImpl->mMixColorIndex = mImpl->mRenderer.RegisterProperty(
469       Toolkit::Visual::Property::MIX_COLOR,
470       MIX_COLOR,
471       Vector3(mImpl->mMixColor));
472   }
473
474   mImpl->mRenderer.SetProperty(DevelRenderer::Property::OPACITY, mImpl->mMixColor.a);
475
476   float preMultipliedAlpha = 0.0f;
477   if(IsPreMultipliedAlphaEnabled())
478   {
479     preMultipliedAlpha = 1.0f;
480   }
481   mImpl->mRenderer.RegisterProperty(PRE_MULTIPLIED_ALPHA_PROPERTY, preMultipliedAlpha);
482 }
483
484 void Visual::Base::SetMixColor(const Vector4& color)
485 {
486   mImpl->mMixColor = color;
487
488   if(mImpl->mRenderer)
489   {
490     mImpl->mRenderer.SetProperty(mImpl->mMixColorIndex, Vector3(color));
491     mImpl->mRenderer.SetProperty(DevelRenderer::Property::OPACITY, color.a);
492   }
493 }
494
495 void Visual::Base::SetMixColor(const Vector3& color)
496 {
497   mImpl->mMixColor.r = color.r;
498   mImpl->mMixColor.g = color.g;
499   mImpl->mMixColor.b = color.b;
500
501   if(mImpl->mRenderer)
502   {
503     mImpl->mRenderer.SetProperty(mImpl->mMixColorIndex, color);
504   }
505 }
506
507 void Visual::Base::AddEventObserver(Visual::EventObserver& observer)
508 {
509   mImpl->mEventObserver = &observer;
510 }
511
512 void Visual::Base::RemoveEventObserver(Visual::EventObserver& observer)
513 {
514   mImpl->mEventObserver = NULL;
515 }
516
517 void Visual::Base::ResourceReady(Toolkit::Visual::ResourceStatus resourceStatus)
518 {
519   if(mImpl->mResourceStatus != resourceStatus)
520   {
521     mImpl->mResourceStatus = resourceStatus;
522
523     if(mImpl->mEventObserver)
524     {
525       // observer is currently a control impl
526       mImpl->mEventObserver->ResourceReady(*this);
527     }
528   }
529 }
530
531 bool Visual::Base::IsResourceReady() const
532 {
533   return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY);
534 }
535
536 bool Visual::Base::IsSynchronousLoadingRequired() const
537 {
538   return (mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING);
539 }
540
541 Toolkit::Visual::Type Visual::Base::GetType() const
542 {
543   return mImpl->mType;
544 }
545
546 Toolkit::Visual::ResourceStatus Visual::Base::GetResourceStatus() const
547 {
548   return mImpl->mResourceStatus;
549 }
550
551 Visual::FittingMode Visual::Base::GetFittingMode() const
552 {
553   return mImpl->mFittingMode;
554 }
555
556 Visual::Base& Visual::Base::GetVisualObject()
557 {
558   return *this;
559 }
560
561 Renderer Visual::Base::GetRenderer()
562 {
563   return mImpl->mRenderer;
564 }
565
566 Property::Index Visual::Base::GetPropertyIndex(Property::Key key)
567 {
568   Property::Index index = mImpl->mRenderer.GetPropertyIndex(key);
569
570   if(index == Property::INVALID_INDEX)
571   {
572     // Is it a shader property?
573     Shader shader = mImpl->mRenderer.GetShader();
574     index         = shader.GetPropertyIndex(key);
575     if(index != Property::INVALID_INDEX)
576     {
577       // Yes - we should register it in the Renderer so it can be set / animated
578       // independently, as shaders are shared across multiple renderers.
579       std::string     keyName;
580       Property::Index keyIndex(Property::INVALID_KEY);
581       if(key.type == Property::Key::INDEX)
582       {
583         keyName  = shader.GetPropertyName(index);
584         keyIndex = key.indexKey;
585       }
586       else
587       {
588         keyName = key.stringKey;
589         // Leave keyIndex as INVALID_KEY - it can still be registered against the string key.
590       }
591       Property::Value value = shader.GetProperty(index);
592       index                 = mImpl->mRenderer.RegisterProperty(keyIndex, keyName, value);
593     }
594   }
595   return index;
596 }
597
598 void Visual::Base::SetupTransition(
599   Dali::Animation&                    transition,
600   Internal::TransitionData::Animator& animator,
601   Property::Index                     index,
602   Property::Value&                    initialValue,
603   Property::Value&                    targetValue)
604 {
605   if(index != Property::INVALID_INDEX)
606   {
607     if(mImpl->mRenderer)
608     {
609       if(animator.animate == false)
610       {
611         mImpl->mRenderer.SetProperty(index, targetValue);
612       }
613       else
614       {
615         if(animator.initialValue.GetType() != Property::NONE)
616         {
617           mImpl->mRenderer.SetProperty(index, initialValue);
618         }
619
620         if(!transition)
621         {
622           transition = Dali::Animation::New(0.1f);
623         }
624
625         transition.AnimateTo(Property(mImpl->mRenderer, index),
626                              targetValue,
627                              animator.alphaFunction,
628                              TimePeriod(animator.timePeriodDelay,
629                                         animator.timePeriodDuration));
630       }
631     }
632   }
633 }
634
635 void Visual::Base::AnimateProperty(
636   Dali::Animation&                    transition,
637   Internal::TransitionData::Animator& animator)
638 {
639 #if defined(DEBUG_ENABLED)
640   {
641     std::ostringstream oss;
642     oss << "Visual::Base::AnimateProperty(Visual:" << mImpl->mName << " Property:" << animator.propertyKey << " Target: " << animator.targetValue << std::endl;
643     DALI_LOG_INFO(gVisualBaseLogFilter, Debug::General, oss.str().c_str());
644   }
645 #endif
646
647   if(animator.propertyKey == Toolkit::Visual::Property::MIX_COLOR ||
648      animator.propertyKey == MIX_COLOR ||
649      (mImpl->mType == Toolkit::Visual::COLOR &&
650       animator.propertyKey == ColorVisual::Property::MIX_COLOR) ||
651      (mImpl->mType == Toolkit::Visual::PRIMITIVE &&
652       animator.propertyKey == PrimitiveVisual::Property::MIX_COLOR))
653   {
654     AnimateMixColorProperty(transition, animator);
655   }
656   else if(animator.propertyKey == Toolkit::Visual::Property::OPACITY ||
657           animator.propertyKey == OPACITY)
658   {
659     AnimateOpacityProperty(transition, animator);
660   }
661   else if(mImpl->mRenderer)
662   {
663     AnimateRendererProperty(transition, animator);
664   }
665 }
666
667 void Visual::Base::AnimateOpacityProperty(
668   Dali::Animation&                    transition,
669   Internal::TransitionData::Animator& animator)
670 {
671   float targetOpacity;
672   if(animator.targetValue.Get(targetOpacity))
673   {
674     mImpl->mMixColor.a = targetOpacity;
675   }
676
677   SetupTransition(transition, animator, DevelRenderer::Property::OPACITY, animator.initialValue, animator.targetValue);
678 }
679
680 void Visual::Base::AnimateRendererProperty(
681   Dali::Animation&                    transition,
682   Internal::TransitionData::Animator& animator)
683 {
684   Property::Index index = GetPropertyIndex(animator.propertyKey);
685   if(index != Property::INVALID_INDEX)
686   {
687     if(animator.targetValue.GetType() != Property::NONE)
688     {
689       // Try writing target value into transform property map
690       // if it's not a valid key, then it won't alter mTransform
691       Property::Map map;
692       if(animator.propertyKey.type == Property::Key::INDEX)
693       {
694         map.Add(animator.propertyKey.indexKey, animator.targetValue);
695       }
696       else
697       {
698         map.Add(animator.propertyKey.stringKey, animator.targetValue);
699       }
700
701       mImpl->mTransform.UpdatePropertyMap(map);
702     }
703
704     SetupTransition(transition, animator, index, animator.initialValue, animator.targetValue);
705   }
706 }
707
708 void Visual::Base::AnimateMixColorProperty(
709   Dali::Animation&                    transition,
710   Internal::TransitionData::Animator& animator)
711 {
712   Property::Index index          = mImpl->mMixColorIndex;
713   bool            animateOpacity = false;
714
715   Property::Value initialOpacity;
716   Property::Value targetOpacity;
717   Property::Value initialMixColor;
718   Property::Value targetMixColor;
719
720   if(index != Property::INVALID_INDEX)
721   {
722     Vector4 initialColor;
723     if(animator.initialValue.Get(initialColor))
724     {
725       if(animator.initialValue.GetType() == Property::VECTOR4)
726       {
727         // if there is an initial color specifying alpha, test it
728         initialOpacity = initialColor.a;
729       }
730       initialMixColor = Vector3(initialColor);
731     }
732
733     // Set target value into data store
734     if(animator.targetValue.GetType() != Property::NONE)
735     {
736       Vector4 mixColor;
737       animator.targetValue.Get(mixColor);
738       if(animator.targetValue.GetType() == Property::VECTOR4)
739       {
740         mImpl->mMixColor.a = mixColor.a;
741         targetOpacity      = mixColor.a;
742         animateOpacity     = true;
743       }
744
745       mImpl->mMixColor.r = mixColor.r;
746       mImpl->mMixColor.g = mixColor.g;
747       mImpl->mMixColor.b = mixColor.b;
748       targetMixColor     = Vector3(mixColor);
749     }
750
751     SetupTransition(transition, animator, index, initialMixColor, targetMixColor);
752     if(animateOpacity)
753     {
754       SetupTransition(transition, animator, DevelRenderer::Property::OPACITY, initialOpacity, targetOpacity);
755     }
756   }
757 }
758
759 Dali::Property Visual::Base::GetPropertyObject(Dali::Property::Key key)
760 {
761   if(!mImpl->mRenderer)
762   {
763     Handle handle;
764     return Dali::Property(handle, Property::INVALID_INDEX);
765   }
766
767   // Mix color or opacity cases
768   if(key.type == Property::Key::INDEX)
769   {
770     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))
771     {
772       return Dali::Property(mImpl->mRenderer, mImpl->mMixColorIndex);
773     }
774     else if(key.indexKey == Toolkit::Visual::Property::OPACITY)
775     {
776       return Dali::Property(mImpl->mRenderer, DevelRenderer::Property::OPACITY);
777     }
778     else if(key.indexKey == Toolkit::Visual::Transform::Property::OFFSET)
779     {
780       return Dali::Property(mImpl->mRenderer, OFFSET);
781     }
782     else if(key.indexKey == Toolkit::Visual::Transform::Property::SIZE)
783     {
784       return Dali::Property(mImpl->mRenderer, SIZE);
785     }
786   }
787   else
788   {
789     if(key.stringKey == MIX_COLOR)
790     {
791       return Dali::Property(mImpl->mRenderer, mImpl->mMixColorIndex);
792     }
793     else if(key.stringKey == OPACITY)
794     {
795       return Dali::Property(mImpl->mRenderer, DevelRenderer::Property::OPACITY);
796     }
797     else if(key.stringKey == OFFSET)
798     {
799       return Dali::Property(mImpl->mRenderer, OFFSET);
800     }
801     else if(key.stringKey == SIZE)
802     {
803       return Dali::Property(mImpl->mRenderer, SIZE);
804     }
805   }
806
807   // Other cases
808   Property::Index index = GetPropertyIndex(key);
809   if(index == Property::INVALID_INDEX)
810   {
811     if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS))
812     {
813       // Register CORNER_RADIUS property
814       mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius);
815       mImpl->mRenderer.RegisterProperty(CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
816
817       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
818
819       index                    = mImpl->mCornerRadiusIndex;
820       mImpl->mNeedCornerRadius = true;
821
822       // Change shader
823       UpdateShader();
824     }
825     else
826     {
827       // We can't find the property in the base class.
828       // Request to child class
829       return OnGetPropertyObject(key);
830     }
831   }
832
833   return Dali::Property(mImpl->mRenderer, index);
834 }
835
836 } // namespace Internal
837
838 } // namespace Toolkit
839
840 } // namespace Dali