refactor Object,TypeInfo and PropertyMetaData to use ConstString
[platform/core/uifw/dali-core.git] / dali / internal / event / common / object-impl.cpp
1 /*
2  * Copyright (c) 2020 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 <dali/internal/event/common/object-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/object/handle-devel.h>
27 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
28 #include <dali/internal/update/common/animatable-property.h>
29 #include <dali/internal/update/common/property-owner.h>
30 #include <dali/internal/update/common/property-owner-messages.h>
31 #include <dali/internal/update/common/uniform-map.h>
32 #include <dali/internal/event/animation/constraint-impl.h>
33 #include <dali/internal/event/common/property-helper.h>
34 #include <dali/internal/event/common/property-notification-impl.h>
35 #include <dali/internal/event/common/stage-impl.h>
36 #include <dali/internal/event/common/type-registry-impl.h>
37 #include <dali/internal/common/const-string.h>
38
39 using Dali::Internal::SceneGraph::AnimatableProperty;
40 using Dali::Internal::SceneGraph::PropertyBase;
41
42 namespace Dali
43 {
44
45 namespace Internal
46 {
47
48 namespace // unnamed namespace
49 {
50 const int32_t SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES;  // Object provides this capability
51
52 #if defined(DEBUG_ENABLED)
53 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
54 #endif
55
56 constexpr Property::Index MAX_PER_CLASS_PROPERTY_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX;
57
58 } // unnamed namespace
59
60 IntrusivePtr<Object> Object::New()
61 {
62   return new Object( nullptr ); // no scene object by default
63 }
64
65 void Object::AddObserver(Observer& observer)
66 {
67   // make sure an observer doesn't observe the same object twice
68   // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
69   DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
70
71   mObservers.PushBack( &observer );
72 }
73
74 void Object::RemoveObserver(Observer& observer)
75 {
76   // Find the observer...
77   const auto endIter =  mObservers.End();
78   for( auto iter = mObservers.Begin(); iter != endIter; ++iter)
79   {
80     if( (*iter) == &observer)
81     {
82       mObservers.Erase( iter );
83       break;
84     }
85   }
86   DALI_ASSERT_DEBUG(endIter != mObservers.End());
87 }
88
89 bool Object::Supports( Capability capability ) const
90 {
91   return (capability & SUPPORTED_CAPABILITIES);
92 }
93
94 uint32_t Object::GetPropertyCount() const
95 {
96   uint32_t count = 0u;
97   const TypeInfo* typeInfo( GetTypeInfo() );
98   if ( typeInfo )
99   {
100     count = typeInfo->GetPropertyCount();
101
102     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Registered Properties:  %d\n", count );
103   }
104
105   uint32_t custom = static_cast<uint32_t>( mCustomProperties.Count() );
106   count += custom;
107   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties:  %d\n", custom );
108
109   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties:   %d\n", count );
110
111   return count;
112 }
113
114 std::string_view Object::GetPropertyName(Property::Index index) const
115 {
116   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
117
118   // is this a per class or per instance property
119   if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
120   {
121     const TypeInfo* typeInfo( GetTypeInfo() );
122     if ( typeInfo )
123     {
124       return typeInfo->GetPropertyName( index );
125     }
126   }
127   else // child property or custom property
128   {
129     CustomPropertyMetadata* custom = FindCustomProperty( index );
130     if( custom )
131     {
132       return custom->name.GetStringView();
133     }
134   }
135
136   DALI_LOG_ERROR( "Property index %d not found\n", index );
137   return {};
138 }
139
140 Property::Index Object::GetPropertyIndex(KeyRef key) const
141 {
142   Property::Index index = Property::INVALID_INDEX;
143
144   if(key.mType == Property::Key::STRING)
145   {
146     const TypeInfo* typeInfo( GetTypeInfo() );
147     if ( typeInfo )
148     {
149       index = typeInfo->GetPropertyIndex(key.mString);
150     }
151   }
152
153   if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
154   {
155     Property::Index count = PROPERTY_CUSTOM_START_INDEX;
156     const auto end = mCustomProperties.End();
157     for( auto iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
158     {
159       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
160
161       if((key.mType == Property::Key::STRING && custom->name == key.mString) ||
162          (key.mType == Property::Key::INDEX && custom->key == key.mIndex))
163       {
164         if ( custom->childPropertyIndex != Property::INVALID_INDEX )
165         {
166           // If it is a child property, return the child property index
167           index = custom->childPropertyIndex;
168         }
169         else
170         {
171           index = count;
172         }
173         break;
174       }
175     }
176   }
177
178   return index;
179 }
180
181 bool Object::IsPropertyWritable( Property::Index index ) const
182 {
183   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
184
185   bool writable = false;
186
187   // is this a per class or per instance property
188   if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
189   {
190     const TypeInfo* typeInfo( GetTypeInfo() );
191     if ( typeInfo )
192     {
193       writable = typeInfo->IsPropertyWritable( index );
194     }
195   }
196   else
197   {
198     CustomPropertyMetadata* custom = FindCustomProperty( index );
199     if( custom )
200     {
201       writable = custom->IsWritable();
202     }
203   }
204
205   return writable;
206 }
207
208 bool Object::IsPropertyAnimatable( Property::Index index ) const
209 {
210   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
211
212   bool animatable = false;
213
214   // is this a per class or per instance property
215   if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
216   {
217     const TypeInfo* typeInfo( GetTypeInfo() );
218     if ( typeInfo )
219     {
220       animatable = typeInfo->IsPropertyAnimatable( index );
221     }
222   }
223   else
224   {
225     CustomPropertyMetadata* custom = FindCustomProperty( index );
226     if( custom )
227     {
228       animatable = custom->IsAnimatable();
229     }
230   }
231
232   return animatable;
233 }
234
235 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
236 {
237   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
238
239   bool isConstraintInput = false;
240
241   // is this a per class or per instance property
242   if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
243   {
244     const TypeInfo* typeInfo( GetTypeInfo() );
245     if ( typeInfo )
246     {
247       isConstraintInput = typeInfo->IsPropertyAConstraintInput( index );
248     }
249   }
250   else
251   {
252     CustomPropertyMetadata* custom = FindCustomProperty( index );
253     if( custom )
254     {
255       // ... custom properties can be used as input to a constraint.
256       isConstraintInput = true;
257     }
258   }
259
260   return isConstraintInput;
261 }
262
263 Property::Type Object::GetPropertyType( Property::Index index ) const
264 {
265   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
266
267   // is this a per class or per instance property
268   if ( index < MAX_PER_CLASS_PROPERTY_INDEX )
269   {
270     const TypeInfo* typeInfo( GetTypeInfo() );
271     if ( typeInfo )
272     {
273       return typeInfo->GetPropertyType( index );
274     }
275   }
276
277   CustomPropertyMetadata* custom = FindCustomProperty( index );
278   if( custom )
279   {
280     return custom->GetType();
281   }
282
283   return Property::NONE;
284 }
285
286 void Object::SetProperty(Property::Index index, Property::Value propertyValue)
287 {
288   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
289
290   bool propertySet( true );
291
292   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
293   {
294     SetDefaultProperty( index, propertyValue );
295   }
296   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
297   {
298     const TypeInfo* typeInfo( GetTypeInfo() );
299     if ( typeInfo )
300     {
301       typeInfo->SetProperty( this, index, propertyValue );
302     }
303     else
304     {
305       // cannot register this property as there is no setter for it.
306       // event side properties must have a setter for now so need to be registered
307       DALI_LOG_ERROR( "Property index %d not found\n", index );
308       propertySet = false;
309     }
310   }
311   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
312   {
313     // check whether the animatable property is registered already, if not then register one.
314     AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, &propertyValue );
315     if( !animatableProperty )
316     {
317       DALI_LOG_ERROR( "Property index %d not found\n", index );
318       propertySet = false;
319     }
320     else
321     {
322       // update the cached property value
323       animatableProperty->SetPropertyValue( propertyValue );
324
325       // set the scene graph property value
326       SetSceneGraphProperty( index, *animatableProperty, propertyValue );
327     }
328   }
329   else
330   {
331     CustomPropertyMetadata* custom = FindCustomProperty( index );
332
333     if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
334     {
335       if( !custom )
336       {
337         // If the child property is not registered yet, register it.
338         custom = new CustomPropertyMetadata({}, propertyValue, Property::READ_WRITE);
339         mCustomProperties.PushBack( custom );
340       }
341
342       custom->childPropertyIndex = index;
343
344       // Resolve name for the child property
345       Object* parent = GetParentObject();
346       if( parent )
347       {
348         const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
349         if( parentTypeInfo )
350         {
351           custom->name = ConstString(parentTypeInfo->GetChildPropertyName(index));
352         }
353       }
354     }
355
356     if( custom )
357     {
358       if( custom->IsAnimatable() )
359       {
360         // update the cached property value
361         custom->SetPropertyValue( propertyValue );
362
363         // set the scene graph property value
364         SetSceneGraphProperty( index, *custom, propertyValue );
365       }
366       else if( custom->IsWritable() )
367       {
368         // update the cached property value
369         custom->SetPropertyValue( propertyValue );
370       }
371       else
372       {
373         // trying to set value on read only property is no-op
374         propertySet = false;
375       }
376     }
377     else
378     {
379       DALI_LOG_ERROR( "Property index %d not found\n", index );
380       propertySet = false;
381     }
382   }
383
384   // Let derived classes know that a property has been set
385   // TODO: We should not call this for read-only properties, SetDefaultProperty() && TypeInfo::SetProperty() should return a bool, which would be true if the property is set
386   if ( propertySet )
387   {
388     OnPropertySet( index, propertyValue );
389     if(!mPropertySetSignal.Empty())
390     {
391       Dali::Handle handle(this);
392       mPropertySetSignal.Emit(handle, index, propertyValue);
393     }
394   }
395 }
396
397 Property::Value Object::GetProperty( Property::Index index ) const
398 {
399   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
400
401   Property::Value value;
402
403   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
404   {
405     value = GetDefaultProperty( index );
406   }
407   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
408   {
409     const TypeInfo* typeInfo( GetTypeInfo() );
410     if ( typeInfo )
411     {
412       value = typeInfo->GetProperty( this, index );
413     }
414     else
415     {
416       DALI_LOG_ERROR( "Property index %d not found\n", index );
417     }
418   }
419   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
420   {
421     // check whether the animatable property is registered already, if not then register one.
422     // this is needed because property value may have been set as full property and get as a property component
423     AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
424     if( animatableProperty )
425     {
426       // get the cached animatable property value
427       value = animatableProperty->GetPropertyValue();
428     }
429     else
430     {
431       DALI_LOG_ERROR( "Property index %d not found\n", index );
432     }
433   }
434   else if(mCustomProperties.Count() > 0)
435   {
436     CustomPropertyMetadata* custom = FindCustomProperty( index );
437     if(custom)
438     {
439       // get the cached custom property value
440       value = custom->GetPropertyValue();
441     }
442     else
443     {
444       DALI_LOG_ERROR( "Property index %d not found\n", index );
445     }
446   } // if custom
447
448   return value;
449 }
450
451 Property::Value Object::GetCurrentProperty( Property::Index index ) const
452 {
453   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
454
455   Property::Value value;
456
457   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
458   {
459     value = GetDefaultPropertyCurrentValue( index );
460   }
461   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
462   {
463     const TypeInfo* typeInfo( GetTypeInfo() );
464     if ( typeInfo )
465     {
466       value = typeInfo->GetProperty( this, index );
467     }
468     else
469     {
470       DALI_LOG_ERROR( "Property index %d not found\n", index );
471     }
472   }
473   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
474   {
475     // check whether the animatable property is registered already, if not then register one.
476     // this is needed because property value may have been set as full property and get as a property component
477     AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
478     if( animatableProperty )
479     {
480       // get the animatable property value
481       value = GetCurrentPropertyValue( *animatableProperty );
482     }
483     else
484     {
485       DALI_LOG_ERROR( "Property index %d not found\n", index );
486     }
487   }
488   else if(mCustomProperties.Count() > 0)
489   {
490     CustomPropertyMetadata* custom = FindCustomProperty( index );
491     if(custom)
492     {
493       // get the custom property value
494       value = GetCurrentPropertyValue( *custom );
495     }
496     else
497     {
498       DALI_LOG_ERROR( "Property index %d not found\n", index );
499     }
500   } // if custom
501
502   return value;
503 }
504
505 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
506 {
507   indices.Clear();
508
509   // Manual Properties
510   const TypeInfo* typeInfo( GetTypeInfo() );
511   if ( typeInfo )
512   {
513     typeInfo->GetPropertyIndices( indices );
514   }
515
516   // Custom Properties
517   if ( mCustomProperties.Count() > 0 )
518   {
519     indices.Reserve( indices.Size() + mCustomProperties.Count() );
520
521     auto iter = mCustomProperties.Begin();
522     const auto endIter = mCustomProperties.End();
523     int32_t i = 0;
524     for ( ; iter != endIter; ++iter, ++i )
525     {
526       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
527       if ( custom->childPropertyIndex != Property::INVALID_INDEX )
528       {
529         // If it is a child property, add the child property index
530         indices.PushBack( custom->childPropertyIndex );
531       }
532       else
533       {
534         indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
535       }
536     }
537   }
538 }
539
540 Property::Index Object::RegisterProperty(std::string_view name, Property::Value propertyValue)
541 {
542   return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), Property::ANIMATABLE);
543 }
544
545 Property::Index Object::RegisterProperty(std::string_view name, Property::Index key, Property::Value propertyValue)
546 {
547   return RegisterProperty(name, key, std::move(propertyValue), Property::ANIMATABLE);
548 }
549
550 void Object::SetProperties( const Property::Map& properties )
551 {
552   const auto count = properties.Count();
553   for( auto position = 0u; position < count; ++position )
554   {
555     // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
556     // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
557
558     const auto& key = properties.GetKeyAt( position );
559     const auto propertyIndex = ( key.type == Property::Key::INDEX ) ? key.indexKey : GetPropertyIndex( key );
560
561     if( propertyIndex != Property::INVALID_INDEX )
562     {
563       const auto& value = properties.GetValue( position );
564       SetProperty( propertyIndex, value );
565     }
566   }
567 }
568
569 void Object::GetProperties( Property::Map& properties )
570 {
571   properties.Clear();
572
573   Property::IndexContainer indexContainer;
574   GetPropertyIndices( indexContainer );
575
576   for( auto index : indexContainer )
577   {
578     properties[ index ] = GetProperty( index );
579   }
580 }
581
582 Property::Index Object::RegisterProperty(std::string_view     name,
583                                          Property::Value      propertyValue,
584                                          Property::AccessMode accessMode)
585 {
586   return RegisterProperty(name, Property::INVALID_KEY, std::move(propertyValue), accessMode);
587 }
588
589 Property::Index Object::RegisterProperty(std::string_view     name,
590                                          Property::Index      key,
591                                          Property::Value      propertyValue,
592                                          Property::AccessMode accessMode)
593 {
594   auto constString = ConstString(name);
595   // If property with the required key already exists, then just set it.
596   Property::Index index = Property::INVALID_INDEX;
597   if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
598   {
599     index = GetPropertyIndex( key );
600   }
601   if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
602   {
603     index = GetPropertyIndex(constString);
604   }
605
606   if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
607   {
608     SetProperty(index, std::move(propertyValue));
609   }
610   else
611   {
612     // Otherwise register the property
613     if( Property::ANIMATABLE == accessMode )
614     {
615       index = RegisterSceneGraphProperty(
616         constString,
617         key,
618         PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>(mCustomProperties.Count()),
619         std::move(propertyValue));
620       AddUniformMapping(index, constString);
621     }
622     else
623     {
624       // Add entry to the property lookup
625       index = PROPERTY_CUSTOM_START_INDEX + static_cast<Property::Index>( mCustomProperties.Count() );
626
627       CustomPropertyMetadata* customProperty =
628         new CustomPropertyMetadata(constString, std::move(propertyValue), accessMode);
629
630       // Resolve index for the child property
631       Object* parent = GetParentObject();
632       if( parent )
633       {
634         const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
635         if( parentTypeInfo )
636         {
637           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
638           if( childPropertyIndex != Property::INVALID_INDEX )
639           {
640             customProperty->childPropertyIndex = childPropertyIndex;
641             index = childPropertyIndex;
642           }
643         }
644       }
645
646       mCustomProperties.PushBack( customProperty );
647     }
648   }
649
650   return index;
651 }
652
653 bool Object::DoesCustomPropertyExist( Property::Index index )
654 {
655   auto metadata = FindCustomProperty( index );
656   return metadata != nullptr;
657 }
658
659 Dali::PropertyNotification Object::AddPropertyNotification( Property::Index index,
660                                                             int32_t componentIndex,
661                                                             const Dali::PropertyCondition& condition)
662 {
663   if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
664   {
665     if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
666     {
667       DALI_ABORT( "Property notification added to event side only property." );
668     }
669     else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
670     {
671       // check whether the animatable property is registered already, if not then register one.
672       AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
673       DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
674     }
675     else if ( mCustomProperties.Count() > 0 )
676     {
677       CustomPropertyMetadata* custom = FindCustomProperty( index );
678       DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
679       DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
680     }
681   }
682
683   Dali::Handle self(this);
684   Property target( self, index );
685
686   PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
687   Dali::PropertyNotification propertyNotification(internal.Get());
688
689   if( !mPropertyNotifications )
690   {
691     mPropertyNotifications = new PropertyNotificationContainer;
692   }
693   mPropertyNotifications->push_back(propertyNotification);
694
695   return propertyNotification;
696 }
697
698 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
699 {
700   if( mPropertyNotifications )
701   {
702     auto iter = mPropertyNotifications->begin();
703     while(iter != mPropertyNotifications->end() )
704     {
705       if(*iter == propertyNotification)
706       {
707         mPropertyNotifications->erase(iter);
708         // As we can't ensure all references are removed, we can just disable
709         // the notification.
710         GetImplementation(propertyNotification).Disable();
711         return;
712       }
713       ++iter;
714     }
715   }
716 }
717
718 void Object::RemovePropertyNotifications()
719 {
720   if( mPropertyNotifications )
721   {
722     auto iter = mPropertyNotifications->begin();
723     while(iter != mPropertyNotifications->end() )
724     {
725       // As we can't ensure all references are removed, we can just disable
726       // the notification.
727       GetImplementation(*iter).Disable();
728       ++iter;
729     }
730
731     mPropertyNotifications->clear();
732   }
733 }
734
735 void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType )
736 {
737   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
738   {
739     OnNotifyDefaultPropertyAnimation( animation, index, value, animationType );
740   }
741   else
742   {
743     PropertyMetadata* propertyMetadata = nullptr;
744     if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
745     {
746       propertyMetadata = FindAnimatableProperty( index );
747     }
748     else
749     {
750       CustomPropertyMetadata* custom = FindCustomProperty( index );
751       if( custom && custom->IsAnimatable() )
752       {
753         propertyMetadata = custom;
754       }
755     }
756
757     if( propertyMetadata )
758     {
759       switch( animationType )
760       {
761         case Animation::TO:
762         case Animation::BETWEEN:
763         {
764           // Update the cached property value
765           propertyMetadata->SetPropertyValue( value );
766           break;
767         }
768         case Animation::BY:
769         {
770           // Adjust the cached property value
771           propertyMetadata->AdjustPropertyValueBy( value );
772           break;
773         }
774       }
775     }
776   }
777 }
778
779 void Object::AddUniformMapping(Property::Index propertyIndex, ConstString uniformName) const
780 {
781   // Get the address of the property if it's a scene property
782   const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
783
784   // Check instead for newly registered properties
785   if( propertyPtr == nullptr )
786   {
787     PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
788     if( animatable )
789     {
790       propertyPtr = animatable->GetSceneGraphProperty();
791     }
792   }
793
794   if( propertyPtr == nullptr )
795   {
796     PropertyMetadata* custom = FindCustomProperty( propertyIndex );
797     if( custom )
798     {
799       propertyPtr = custom->GetSceneGraphProperty();
800     }
801   }
802
803   if( propertyPtr )
804   {
805     const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
806
807     SceneGraph::UniformPropertyMapping map(uniformName, propertyPtr);
808     // Message takes ownership of Uniform map (and will delete it after copy)
809     AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, map );
810   }
811 }
812
813 void Object::RemoveUniformMapping( const std::string& uniformName ) const
814 {
815   const SceneGraph::PropertyOwner& sceneObject = GetSceneObject();
816   RemoveUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), sceneObject, ConstString(uniformName));
817 }
818
819 void Object::ApplyConstraint( ConstraintBase& constraint )
820 {
821   if( !mConstraints )
822   {
823     mConstraints = new ConstraintContainer;
824   }
825   mConstraints->push_back( Dali::Constraint( &constraint ) );
826 }
827
828 void Object::RemoveConstraint( ConstraintBase& constraint )
829 {
830   // nullptr if the Constraint sources are destroyed before Constraint::Apply()
831   if( mConstraints )
832   {
833     ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
834     if( it != mConstraints->end() )
835     {
836       mConstraints->erase( it );
837     }
838   }
839 }
840
841 void Object::RemoveConstraints()
842 {
843   // guard against constraint sending messages during core destruction
844   if( mConstraints && Stage::IsInstalled() )
845   {
846     for ( auto&& item : *mConstraints )
847     {
848       GetImplementation( item ).RemoveInternal();
849     }
850
851     delete mConstraints;
852     mConstraints = nullptr;
853   }
854 }
855
856 void Object::RemoveConstraints( uint32_t tag )
857 {
858   // guard against constraint sending messages during core destruction
859   if( mConstraints && Stage::IsInstalled() )
860   {
861     auto iter( mConstraints->begin() );
862     while(iter != mConstraints->end() )
863     {
864       ConstraintBase& constraint = GetImplementation( *iter );
865       if( constraint.GetTag() == tag )
866       {
867         GetImplementation( *iter ).RemoveInternal();
868         iter = mConstraints->erase( iter );
869       }
870       else
871       {
872         ++iter;
873       }
874     }
875
876     if ( mConstraints->empty() )
877     {
878       delete mConstraints;
879       mConstraints = nullptr;
880     }
881   }
882 }
883
884 void Object::SetTypeInfo( const TypeInfo* typeInfo )
885 {
886   mTypeInfo = typeInfo;
887 }
888
889 const SceneGraph::PropertyOwner& Object::GetSceneObject() const
890 {
891   if( !mUpdateObject )
892   {
893     auto sceneObject = SceneGraph::PropertyOwner::New();
894     OwnerPointer< SceneGraph::PropertyOwner > transferOwnership( sceneObject );
895     mUpdateObject = sceneObject;
896     AddObjectMessage( const_cast<EventThreadServices&>( GetEventThreadServices() ).GetUpdateManager(), transferOwnership );
897   }
898   DALI_ASSERT_DEBUG( mUpdateObject && "there must always be a scene object" );
899   return *mUpdateObject;
900 }
901
902 const PropertyBase* Object::GetSceneObjectAnimatableProperty( Property::Index index ) const
903 {
904   const SceneGraph::PropertyBase* property = nullptr;
905   if ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX && index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX )
906   {
907     AnimatablePropertyMetadata* animatable = GetSceneAnimatableProperty( index, nullptr );
908     DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
909
910     property = animatable->GetSceneGraphProperty();
911   }
912   else if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && // Child properties are also stored as custom properties
913             ( index <= PROPERTY_CUSTOM_MAX_INDEX ) )
914   {
915     CustomPropertyMetadata* custom = FindCustomProperty( index );
916     DALI_ASSERT_ALWAYS( custom && "Property index is invalid" );
917
918     property = custom->GetSceneGraphProperty();
919   }
920   return property;
921 }
922
923 const PropertyInputImpl* Object::GetSceneObjectInputProperty( Property::Index index ) const
924 {
925   // reuse animatable version as they are inputs as well
926   return GetSceneObjectAnimatableProperty( index );
927 }
928
929 int32_t Object::GetPropertyComponentIndex( Property::Index index ) const
930 {
931   int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
932
933   if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
934   {
935     // check whether the animatable property is registered already, if not then register one.
936     AnimatablePropertyMetadata* animatableProperty = GetSceneAnimatableProperty( index, nullptr );
937     if( animatableProperty )
938     {
939       componentIndex = animatableProperty->componentIndex;
940     }
941   }
942   if( Property::INVALID_COMPONENT_INDEX == componentIndex )
943   {
944     const TypeInfo* typeInfo( GetTypeInfo() );
945     if ( typeInfo )
946     {
947       componentIndex = typeInfo->GetComponentIndex(index);
948     }
949   }
950
951   return componentIndex;
952 }
953
954 Handle::PropertySetSignalType& Object::PropertySetSignal()
955 {
956   return mPropertySetSignal;
957 }
958
959 Object::Object( const SceneGraph::PropertyOwner* sceneObject )
960 : mEventThreadServices( EventThreadServices::Get() ),
961   mUpdateObject( sceneObject ),
962   mTypeInfo( nullptr ),
963   mConstraints( nullptr ),
964   mPropertyNotifications( nullptr )
965 {
966 }
967
968 Object::~Object()
969 {
970   // Notification for observers
971   for( auto&& item : mObservers )
972   {
973     item->ObjectDestroyed( *this );
974   }
975   delete mConstraints;
976   delete mPropertyNotifications;
977
978   // Guard to allow handle destruction after Core has been destroyed
979   if( Stage::IsInstalled() )
980   {
981     if( nullptr != mUpdateObject )
982     {
983       RemoveObjectMessage( GetEventThreadServices().GetUpdateManager(), mUpdateObject );
984     }
985   }
986 }
987
988 void Object::OnSceneObjectAdd()
989 {
990   // Notification for observers
991   for( auto&& item : mObservers )
992   {
993     item->SceneObjectAdded(*this);
994   }
995
996   // enable property notifications in scene graph
997   EnablePropertyNotifications();
998 }
999
1000 void Object::OnSceneObjectRemove()
1001 {
1002   // Notification for observers
1003   for( auto&& item : mObservers )
1004   {
1005     item->SceneObjectRemoved(*this);
1006   }
1007
1008   // disable property notifications in scene graph
1009   DisablePropertyNotifications();
1010 }
1011
1012 const TypeInfo* Object::GetTypeInfo() const
1013 {
1014   if ( !mTypeInfo )
1015   {
1016     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1017     // especially as the type-info does not change during the life-time of an application
1018
1019     TypeRegistry::TypeInfoPointer typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1020     if ( typeInfoHandle )
1021     {
1022       mTypeInfo = typeInfoHandle.Get(); // just a raw pointer to use, ownership is kept
1023     }
1024   }
1025
1026   return mTypeInfo;
1027 }
1028
1029 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1030 {
1031   CustomPropertyMetadata* property = nullptr;
1032   if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1033   {
1034     for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1035     {
1036       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1037       if( custom->childPropertyIndex == index )
1038       {
1039         property = custom;
1040       }
1041     }
1042   }
1043   else
1044   {
1045     int32_t arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1046     if( arrayIndex >= 0 )
1047     {
1048       if( arrayIndex < static_cast<int32_t>( mCustomProperties.Count() ) ) // we can only access the first 2 billion custom properties
1049       {
1050         property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1051       }
1052     }
1053   }
1054   return property;
1055 }
1056
1057 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1058 {
1059   for( auto&& entry : mAnimatableProperties )
1060   {
1061     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( entry );
1062     if( property->index == index )
1063     {
1064       return property;
1065     }
1066   }
1067   return nullptr;
1068 }
1069
1070 Property::Index Object::RegisterSceneGraphProperty(ConstString name, Property::Index key, Property::Index index, Property::Value propertyValue) const
1071 {
1072   // Create a new property
1073   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
1074
1075   switch ( propertyValue.GetType() )
1076   {
1077     case Property::BOOLEAN:
1078     {
1079       newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
1080       break;
1081     }
1082
1083     case Property::INTEGER:
1084     {
1085       newProperty = new AnimatableProperty<int32_t>( propertyValue.Get<int32_t>() );
1086       break;
1087     }
1088
1089     case Property::FLOAT:
1090     {
1091       newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
1092       break;
1093     }
1094
1095     case Property::VECTOR2:
1096     {
1097       newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
1098       break;
1099     }
1100
1101     case Property::VECTOR3:
1102     {
1103       newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
1104       break;
1105     }
1106
1107     case Property::VECTOR4:
1108     {
1109       newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
1110       break;
1111     }
1112
1113     case Property::MATRIX:
1114     {
1115       newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
1116       break;
1117     }
1118
1119     case Property::MATRIX3:
1120     {
1121       newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
1122       break;
1123     }
1124
1125     case Property::ROTATION:
1126     {
1127       newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
1128       break;
1129     }
1130
1131     case Property::RECTANGLE:
1132     case Property::STRING:
1133     case Property::ARRAY:
1134     case Property::MAP:
1135     case Property::EXTENTS:
1136     case Property::NONE:
1137     {
1138       DALI_ASSERT_ALWAYS( !"Property type is not animatable" );
1139       break;
1140     }
1141   }
1142
1143   // get the scene property owner
1144   const SceneGraph::PropertyOwner& scenePropertyOwner = GetSceneObject();
1145   // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
1146   const PropertyBase* property = newProperty.Get();
1147   if(index >= PROPERTY_CUSTOM_START_INDEX)
1148   {
1149     DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
1150
1151     mCustomProperties.PushBack(new CustomPropertyMetadata(name, key, std::move(propertyValue), property));
1152   }
1153   else
1154   {
1155     mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, std::move(propertyValue), property ) );
1156   }
1157
1158   // queue a message to add the property
1159   InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), scenePropertyOwner, newProperty ); // Message takes ownership
1160
1161   return index;
1162 }
1163
1164 void Object::RegisterAnimatableProperty( const TypeInfo& typeInfo,
1165                                           Property::Index index,
1166                                           const Property::Value* value ) const
1167 {
1168   // If the property is not a component of a base property, register the whole property itself.
1169   auto            propertyName = ConstString(typeInfo.GetPropertyName(index));
1170   Property::Value initialValue;
1171   if( value )
1172   {
1173     initialValue = *value;
1174   }
1175   else
1176   {
1177     initialValue = typeInfo.GetPropertyDefaultValue( index ); // recurses type hierarchy
1178     if( Property::NONE == initialValue.GetType() )
1179     {
1180       initialValue = Property::Value( typeInfo.GetPropertyType( index ) ); // recurses type hierarchy
1181     }
1182   }
1183   RegisterSceneGraphProperty( propertyName, Property::INVALID_KEY, index, initialValue );
1184   AddUniformMapping( index, propertyName );
1185 }
1186
1187 AnimatablePropertyMetadata* Object::GetSceneAnimatableProperty( Property::Index index, const Property::Value* value ) const
1188 {
1189   // property range already checked by calling methods
1190   // check whether the animatable property is registered already, if not then register one.
1191   AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1192   if( !animatableProperty )
1193   {
1194     const TypeInfo* typeInfo( GetTypeInfo() );
1195     if( typeInfo )
1196     {
1197       Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex( index );
1198       if( basePropertyIndex == Property::INVALID_INDEX )
1199       {
1200         // If the property is not a component of a base property, register the whole property itself.
1201         RegisterAnimatableProperty( *typeInfo, index, value );
1202       }
1203       else
1204       {
1205         // Since the property is a component of a base property, check whether the base property is registered.
1206         animatableProperty = FindAnimatableProperty( basePropertyIndex );
1207         if( !animatableProperty )
1208         {
1209           // If the base property is not registered yet, register the base property first.
1210           RegisterAnimatableProperty( *typeInfo, basePropertyIndex, value );
1211           animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1212         }
1213
1214         // Create the metadata for the property component.
1215         mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
1216       }
1217
1218       // The metadata has just been added and therefore should be in the end of the vector.
1219       animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1220     }
1221   }
1222
1223   return animatableProperty;
1224 }
1225
1226 void Object::ResolveChildProperties()
1227 {
1228   // Resolve index for the child property
1229   Object* parent = GetParentObject();
1230   if( parent )
1231   {
1232     const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1233     if( parentTypeInfo )
1234     {
1235       // Go through each custom property
1236       for( auto&& entry : mCustomProperties )
1237       {
1238         CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( entry );
1239
1240         if(customProperty->name.IsEmpty())
1241         {
1242           if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1243           {
1244             // Resolve name for any child property with no name
1245             customProperty->name = ConstString(parentTypeInfo->GetChildPropertyName(customProperty->childPropertyIndex));
1246           }
1247         }
1248         else
1249         {
1250           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex(customProperty->name);
1251           if( childPropertyIndex != Property::INVALID_INDEX )
1252           {
1253             // Resolve index for any property with a name that matches the parent's child property name
1254             customProperty->childPropertyIndex = childPropertyIndex;
1255           }
1256         }
1257       }
1258     }
1259   }
1260 }
1261
1262 void Object::SetDefaultProperty( Property::Index index, const Property::Value& property )
1263 {
1264   // do nothing
1265 }
1266
1267 Property::Value Object::GetDefaultProperty(Property::Index index) const
1268 {
1269   return Property::Value();
1270 }
1271
1272 Property::Value Object::GetDefaultPropertyCurrentValue( Property::Index index ) const
1273 {
1274   return GetDefaultProperty( index );
1275 }
1276
1277 void Object::EnablePropertyNotifications()
1278 {
1279   if( mPropertyNotifications )
1280   {
1281     for( auto&& element : *mPropertyNotifications )
1282     {
1283       GetImplementation( element ).Enable();
1284     }
1285   }
1286 }
1287
1288 void Object::DisablePropertyNotifications()
1289 {
1290   if( mPropertyNotifications )
1291   {
1292     for( auto&& element : *mPropertyNotifications )
1293     {
1294       GetImplementation( element ).Disable();
1295     }
1296   }
1297 }
1298
1299 Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata& entry ) const
1300 {
1301   Property::Value value;
1302
1303   if( !entry.IsAnimatable() )
1304   {
1305     value = entry.GetPropertyValue();
1306   }
1307   else
1308   {
1309     BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
1310
1311     switch ( entry.GetType() )
1312     {
1313       case Property::BOOLEAN:
1314       {
1315         const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1316         DALI_ASSERT_DEBUG( property );
1317
1318         value = (*property)[ bufferIndex ];
1319         break;
1320       }
1321
1322       case Property::INTEGER:
1323       {
1324         const AnimatableProperty<int32_t>* property = static_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1325         DALI_ASSERT_DEBUG( property );
1326
1327         value = (*property)[ bufferIndex ];
1328         break;
1329       }
1330
1331       case Property::FLOAT:
1332       {
1333         const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1334         DALI_ASSERT_DEBUG( property );
1335
1336         value = (*property)[ bufferIndex ];
1337         break;
1338       }
1339
1340       case Property::VECTOR2:
1341       {
1342         const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1343         DALI_ASSERT_DEBUG( property );
1344
1345         if(entry.componentIndex == 0)
1346         {
1347           value = (*property)[ bufferIndex ].x;
1348         }
1349         else if(entry.componentIndex == 1)
1350         {
1351           value = (*property)[ bufferIndex ].y;
1352         }
1353         else
1354         {
1355           value = (*property)[ bufferIndex ];
1356         }
1357         break;
1358       }
1359
1360       case Property::VECTOR3:
1361       {
1362         const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1363         DALI_ASSERT_DEBUG( property );
1364
1365         if(entry.componentIndex == 0)
1366         {
1367           value = (*property)[ bufferIndex ].x;
1368         }
1369         else if(entry.componentIndex == 1)
1370         {
1371           value = (*property)[ bufferIndex ].y;
1372         }
1373         else if(entry.componentIndex == 2)
1374         {
1375           value = (*property)[ bufferIndex ].z;
1376         }
1377         else
1378         {
1379           value = (*property)[ bufferIndex ];
1380         }
1381         break;
1382       }
1383
1384       case Property::VECTOR4:
1385       {
1386         const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1387         DALI_ASSERT_DEBUG( property );
1388
1389         if(entry.componentIndex == 0)
1390         {
1391           value = (*property)[ bufferIndex ].x;
1392         }
1393         else if(entry.componentIndex == 1)
1394         {
1395           value = (*property)[ bufferIndex ].y;
1396         }
1397         else if(entry.componentIndex == 2)
1398         {
1399           value = (*property)[ bufferIndex ].z;
1400         }
1401         else if(entry.componentIndex == 3)
1402         {
1403           value = (*property)[ bufferIndex ].w;
1404         }
1405         else
1406         {
1407           value = (*property)[ bufferIndex ];
1408         }
1409         break;
1410       }
1411
1412       case Property::MATRIX:
1413       {
1414         const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1415         DALI_ASSERT_DEBUG( property );
1416
1417         value = (*property)[ bufferIndex ];
1418         break;
1419       }
1420
1421       case Property::MATRIX3:
1422       {
1423         const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1424         DALI_ASSERT_DEBUG( property );
1425
1426         value = (*property)[ bufferIndex ];
1427         break;
1428       }
1429
1430       case Property::ROTATION:
1431       {
1432         const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1433         DALI_ASSERT_DEBUG( property );
1434
1435         value = (*property)[ bufferIndex ];
1436         break;
1437       }
1438
1439       default:
1440       {
1441         // unreachable code due to higher level logic
1442       }
1443     } // switch(type)
1444   } // if animatable
1445
1446   return value;
1447 }
1448
1449 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1450 {
1451   switch ( entry.GetType() )
1452   {
1453     case Property::BOOLEAN:
1454     {
1455       const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1456       DALI_ASSERT_DEBUG( property );
1457
1458       // property is being used in a separate thread; queue a message to set the property
1459       BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1460       break;
1461     }
1462
1463     case Property::INTEGER:
1464     {
1465       const AnimatableProperty<int32_t>* property = dynamic_cast< const AnimatableProperty<int32_t>* >( entry.GetSceneGraphProperty() );
1466       DALI_ASSERT_DEBUG( property );
1467
1468       // property is being used in a separate thread; queue a message to set the property
1469       BakeMessage<int32_t>( GetEventThreadServices(), *property, value.Get<int32_t>() );
1470       break;
1471     }
1472
1473     case Property::FLOAT:
1474     {
1475       const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1476       DALI_ASSERT_DEBUG( property );
1477
1478       // property is being used in a separate thread; queue a message to set the property
1479       BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1480       break;
1481     }
1482
1483     case Property::VECTOR2:
1484     {
1485       const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1486       DALI_ASSERT_DEBUG( property );
1487
1488       // property is being used in a separate thread; queue a message to set the property
1489       if(entry.componentIndex == 0)
1490       {
1491         SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1492       }
1493       else if(entry.componentIndex == 1)
1494       {
1495         SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1496       }
1497       else
1498       {
1499         BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1500       }
1501       break;
1502     }
1503
1504     case Property::VECTOR3:
1505     {
1506       const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1507       DALI_ASSERT_DEBUG( property );
1508
1509       // property is being used in a separate thread; queue a message to set the property
1510       if(entry.componentIndex == 0)
1511       {
1512         SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1513       }
1514       else if(entry.componentIndex == 1)
1515       {
1516         SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1517       }
1518       else if(entry.componentIndex == 2)
1519       {
1520         SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1521       }
1522       else
1523       {
1524         BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1525       }
1526
1527       break;
1528     }
1529
1530     case Property::VECTOR4:
1531     {
1532       const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1533       DALI_ASSERT_DEBUG( property );
1534
1535       // property is being used in a separate thread; queue a message to set the property
1536       if(entry.componentIndex == 0)
1537       {
1538         SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1539       }
1540       else if(entry.componentIndex == 1)
1541       {
1542         SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1543       }
1544       else if(entry.componentIndex == 2)
1545       {
1546         SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1547       }
1548       else if(entry.componentIndex == 3)
1549       {
1550         SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1551       }
1552       else
1553       {
1554         BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1555       }
1556       break;
1557     }
1558
1559     case Property::ROTATION:
1560     {
1561       const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1562       DALI_ASSERT_DEBUG( property );
1563
1564       // property is being used in a separate thread; queue a message to set the property
1565       BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1566       break;
1567     }
1568
1569     case Property::MATRIX:
1570     {
1571       const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1572       DALI_ASSERT_DEBUG( property );
1573
1574       // property is being used in a separate thread; queue a message to set the property
1575       BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1576       break;
1577     }
1578
1579     case Property::MATRIX3:
1580     {
1581       const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1582       DALI_ASSERT_DEBUG( property );
1583
1584       // property is being used in a separate thread; queue a message to set the property
1585       BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1586       break;
1587     }
1588
1589     default:
1590     {
1591       // non-animatable scene graph property, do nothing
1592     }
1593   }
1594 }
1595
1596 } // namespace Internal
1597
1598 } // namespace Dali