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