Clean up the code to build successfully on macOS
[platform/core/uifw/dali-core.git] / dali / internal / event / common / type-info-impl.cpp
1 /*
2  * Copyright (c) 2018 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/type-info-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm> // std::find_if
23 #include <string>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/debug.h>
27 #include <dali/internal/event/common/type-registry-impl.h>
28 #include <dali/internal/event/common/object-impl.h>
29
30 using std::find_if;
31
32 namespace Dali
33 {
34
35 namespace Internal
36 {
37
38 namespace
39 {
40
41 /*
42  * Functor to find by given type for vector of pairs
43  */
44 template <typename S, typename T>
45 struct PairFinder
46 {
47   PairFinder(const S& find)
48   : mFind(find)
49   {
50   }
51
52   bool operator()(const T& p) const
53   {
54     return p.first == mFind;
55   }
56
57 private:
58
59   const S& mFind;
60 };
61
62 /**
63  * Functor to find a matching property name
64  */
65 template <typename T>
66 struct PropertyNameFinder
67 {
68   PropertyNameFinder( const std::string& find )
69   : mFind( find )
70   {
71   }
72
73   bool operator()(const T &p) const
74   {
75     return p.second.name == mFind;
76   }
77
78 private:
79
80   const std::string& mFind;
81 };
82
83 /**
84  * Functor to find a matching property component index
85  */
86 template <typename T>
87 struct PropertyComponentFinder
88 {
89   PropertyComponentFinder( Property::Index basePropertyIndex, const int find )
90   : mBasePropertyIndex( basePropertyIndex ),
91     mFind( find )
92   {
93   }
94
95   bool operator()(const T &p) const
96   {
97     return ( p.second.basePropertyIndex == mBasePropertyIndex && p.second.componentIndex == mFind );
98   }
99
100 private:
101
102   Property::Index mBasePropertyIndex;
103   const int mFind;
104 };
105
106 /**
107  * Helper function to find the right default property with given index and return the desired detail of it
108  */
109 template< typename Parameter, typename Member >
110 inline bool GetDefaultPropertyField( const Dali::PropertyDetails* propertyTable, Property::Index count, Property::Index index, Member member, Parameter& parameter )
111 {
112   bool found = false;
113   // is index inside this table (bigger than first index but smaller than first + count)
114   if( ( index >= propertyTable->enumIndex ) && ( index < ( propertyTable->enumIndex + count ) ) )
115   {
116     // return the match. we're assuming here that there is no gaps between the indices in a table
117     parameter = propertyTable[ index - propertyTable->enumIndex ].*member;
118     found = true;
119   }
120   // should never really get here
121   return found;
122 }
123
124 // static pointer value to mark that a base class address has not been resolved
125 // 0x01 is not a valid pointer but used here to differentiate from nullptr
126 // unfortunately it cannot be constexpr as C++ does not allow them to be initialised with reinterpret_cast
127 Internal::TypeInfo* const UNRESOLVED = reinterpret_cast<Internal::TypeInfo*>( 0x1 );
128
129 /**
130  * Helper function to resolve and return the pointer to the base type info
131  * Not a member function to avoid having to #include additional headers and to make sure this gets inlined inside this cpp
132  * @param[in/out] baseType pointer to resolve and set
133  * @param[in] typeRegistry reference to the type registry
134  * @param[in] baseTypeName string name of the base type
135  * @return true is base type exists
136  */
137 inline bool GetBaseType( Internal::TypeInfo*& baseType, TypeRegistry& typeRegistry, const std::string& baseTypeName )
138 {
139   // if greater than unresolved means we have a base type, null means no base
140   bool baseExists = ( baseType > UNRESOLVED );
141   // base only needs to be resolved once
142   if( UNRESOLVED == baseType )
143   {
144     TypeRegistry::TypeInfoPointer base = typeRegistry.GetTypeInfo( baseTypeName );
145     if( base )
146     {
147       baseType = base.Get(); // dont pass ownership, just return raw pointer
148       baseExists = true;
149     }
150     else
151     {
152       // no type info found so assuming no base as all type registration is done in startup for now
153       baseType = nullptr;
154     }
155   }
156   return baseExists;
157 }
158
159 } // unnamed namespace
160
161 TypeInfo::TypeInfo( const std::string &name, const std::string &baseTypeName, Dali::TypeInfo::CreateFunction creator,
162                     const Dali::PropertyDetails* defaultProperties, Property::Index defaultPropertyCount )
163 : mTypeRegistry( *TypeRegistry::Get() ), mBaseType( UNRESOLVED ),
164   mTypeName( name ), mBaseTypeName( baseTypeName ), mCreate( creator ), mDefaultProperties( defaultProperties ),
165   mDefaultPropertyCount( defaultPropertyCount ), mCSharpType( false )
166 {
167   DALI_ASSERT_ALWAYS(!name.empty() && "Type info construction must have a name");
168   DALI_ASSERT_ALWAYS(!baseTypeName.empty() && "Type info construction must have a base type name");
169 }
170
171 TypeInfo::TypeInfo(const std::string &name, const std::string &baseTypeName, Dali::CSharpTypeInfo::CreateFunction creator)
172 : mTypeRegistry( *TypeRegistry::Get() ), mBaseType( UNRESOLVED ),
173   mTypeName( name ), mBaseTypeName( baseTypeName ), mCSharpCreate( creator ), mCSharpType( true )
174 {
175   DALI_ASSERT_ALWAYS(!name.empty() && "Type info construction must have a name");
176   DALI_ASSERT_ALWAYS(!baseTypeName.empty() && "Type info construction must have a base type name");
177 }
178
179 TypeInfo::~TypeInfo()
180 {
181 }
182
183 BaseHandle TypeInfo::CreateInstance() const
184 {
185   BaseHandle ret;
186
187   if(mCreate)
188   {
189     if ( mCSharpType )
190     {
191       // CSharp currently only registers one create function for all custom controls
192       // it uses the type name to decide which one to create
193       ret = *mCSharpCreate( mTypeName.c_str() );
194     }
195     else
196     {
197       ret = mCreate();
198     }
199
200     if ( ret )
201     {
202       BaseObject& handle = ret.GetBaseObject();
203       Object *object = dynamic_cast<Internal::Object*>(&handle);
204
205       if ( object )
206       {
207         object->SetTypeInfo( this );
208       }
209     }
210   }
211   return ret;
212 }
213
214 bool TypeInfo::DoActionTo(BaseObject *object, const std::string &actionName, const Property::Map &properties)
215 {
216   bool done = false;
217
218   ActionContainer::iterator iter = find_if(mActions.begin(), mActions.end(), PairFinder<std::string, ActionPair>(actionName));
219
220   if( iter != mActions.end() )
221   {
222     done = (iter->second)(object, actionName, properties);
223   }
224
225   if( !done )
226   {
227     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
228     {
229       // call base type recursively
230       done = mBaseType->DoActionTo( object, actionName, properties );
231     }
232   }
233
234   return done;
235 }
236
237 bool TypeInfo::ConnectSignal( BaseObject* object, ConnectionTrackerInterface* connectionTracker, const std::string& signalName, FunctorDelegate* functor )
238 {
239   bool connected( false );
240
241   ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
242                                                  PairFinder<std::string, ConnectionPair>(signalName) );
243
244   if( iter != mSignalConnectors.end() )
245   {
246     connected = (iter->second)( object, connectionTracker, signalName, functor );
247   }
248
249   if( !connected )
250   {
251     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
252     {
253       // call base type recursively
254       connected = mBaseType->ConnectSignal( object, connectionTracker, signalName, functor );
255     }
256   }
257
258   return connected;
259 }
260
261 const std::string& TypeInfo::GetName() const
262 {
263   return mTypeName;
264 }
265
266 const std::string& TypeInfo::GetBaseName() const
267 {
268   return mBaseTypeName;
269 }
270
271 Dali::TypeInfo::CreateFunction TypeInfo::GetCreator() const
272 {
273   return mCreate;
274 }
275
276 uint32_t TypeInfo::GetActionCount() const
277 {
278   uint32_t count = static_cast<uint32_t>( mActions.size() );
279
280   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
281   {
282     // call base type recursively
283     count += mBaseType->GetActionCount();
284   }
285
286   return count;
287 }
288
289 std::string TypeInfo::GetActionName( uint32_t index ) const
290 {
291   std::string name;
292   const uint32_t count = static_cast<uint32_t>( mActions.size() );
293
294   if( index < count )
295   {
296     name = mActions[index].first;
297   }
298   else
299   {
300     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
301     {
302       // call base type recursively
303       return mBaseType->GetActionName( index - count );
304     }
305   }
306
307   return name;
308 }
309
310 uint32_t TypeInfo::GetSignalCount() const
311 {
312   uint32_t count = static_cast<uint32_t>( mSignalConnectors.size() );
313
314   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
315   {
316     // call base type recursively
317     count += mBaseType->GetSignalCount();
318   }
319
320   return count;
321 }
322
323 std::string TypeInfo::GetSignalName( uint32_t index ) const
324 {
325   std::string name;
326   const uint32_t count = static_cast<uint32_t>( mSignalConnectors.size() );
327
328   if( index < count )
329   {
330     name = mSignalConnectors[index].first;
331   }
332   else
333   {
334     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
335     {
336       // call base type recursively
337       return mBaseType->GetSignalName( index - count );
338     }
339   }
340
341   return name;
342 }
343
344 void TypeInfo::GetPropertyIndices( Property::IndexContainer& indices ) const
345 {
346   // Default Properties
347   if( mDefaultProperties )
348   {
349     indices.Reserve( indices.Size() + mDefaultPropertyCount );
350     for( Property::Index index = 0; index < mDefaultPropertyCount; ++index )
351     {
352       indices.PushBack( mDefaultProperties[ index ].enumIndex );
353     }
354   }
355
356   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
357   {
358     // call base type recursively
359     mBaseType->GetPropertyIndices( indices );
360   }
361
362   AppendProperties( indices, mRegisteredProperties );
363 }
364
365 void TypeInfo::GetChildPropertyIndices( Property::IndexContainer& indices ) const
366 {
367   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
368   {
369     // call base type recursively
370     mBaseType->GetChildPropertyIndices( indices );
371   }
372
373   AppendProperties( indices, mRegisteredChildProperties );
374 }
375
376 /**
377  * Append the indices in RegisteredProperties to the given index container.
378  */
379 void TypeInfo::AppendProperties( Dali::Property::IndexContainer& indices,
380                                  const TypeInfo::RegisteredPropertyContainer& registeredProperties ) const
381 {
382   if ( ! registeredProperties.empty() )
383   {
384     indices.Reserve( indices.Size() + registeredProperties.size() );
385
386     for( auto&& elem : registeredProperties )
387     {
388       indices.PushBack( elem.first );
389     }
390   }
391 }
392
393 const std::string& TypeInfo::GetRegisteredPropertyName( Property::Index index ) const
394 {
395   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
396                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
397   if ( iter != mRegisteredProperties.end() )
398   {
399     return iter->second.name;
400   }
401   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
402   {
403     // call base type recursively
404     return mBaseType->GetRegisteredPropertyName( index );
405   }
406   static std::string empty;
407   return empty;
408 }
409
410 std::string TypeInfo::GetPropertyName( Property::Index index ) const
411 {
412   std::string propertyName;
413   // default or custom
414   if ( mDefaultProperties && ( index < DEFAULT_PROPERTY_MAX_COUNT ) )
415   {
416     std::string_view name;
417     if( GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::name, name ) )
418     {
419       propertyName = name;
420     }
421   }
422   else
423   {
424     RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
425                                                             PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
426     if ( iter != mRegisteredProperties.end() )
427     {
428       return iter->second.name;
429     }
430   }
431   // if not our property, go to parent
432   if( propertyName.empty() )
433   {
434     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
435     {
436       // call base type recursively
437       return mBaseType->GetPropertyName( index );
438     }
439   }
440
441   return propertyName;
442 }
443
444 void TypeInfo::AddActionFunction(std::string actionName, Dali::TypeInfo::ActionFunction function)
445 {
446   if( nullptr == function)
447   {
448     DALI_LOG_WARNING("Action function is empty\n");
449   }
450   else
451   {
452     ActionContainer::iterator iter = std::find_if(mActions.begin(), mActions.end(),
453                                                   PairFinder<std::string, ActionPair>(actionName));
454
455     if( iter == mActions.end() )
456     {
457       mActions.push_back(ActionPair(std::move(actionName), function));
458     }
459     else
460     {
461       DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str());
462     }
463   }
464 }
465
466 void TypeInfo::AddConnectorFunction(std::string signalName, Dali::TypeInfo::SignalConnectorFunction function)
467 {
468   if( nullptr == function)
469   {
470     DALI_LOG_WARNING("Connector function is empty\n");
471   }
472   else
473   {
474     ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
475                                                    PairFinder<std::string, ConnectionPair>(signalName) );
476
477     if( iter == mSignalConnectors.end() )
478     {
479       mSignalConnectors.push_back(ConnectionPair(std::move(signalName), function));
480     }
481     else
482     {
483       DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str());
484     }
485   }
486 }
487
488 void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Type type, Dali::TypeInfo::SetPropertyFunction setFunc, Dali::TypeInfo::GetPropertyFunction getFunc)
489 {
490   // The setter can be empty as a property can be read-only.
491
492   if ( nullptr == getFunc )
493   {
494     DALI_ASSERT_ALWAYS( ! "GetProperty Function is empty" );
495   }
496   else
497   {
498     RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
499                                                           PairFinder< Property::Index, RegisteredPropertyPair>(index) );
500
501     if ( iter == mRegisteredProperties.end() )
502     {
503       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
504     }
505     else
506     {
507       DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
508     }
509   }
510 }
511
512 void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Type type, Dali::CSharpTypeInfo::SetPropertyFunction setFunc, Dali::CSharpTypeInfo::GetPropertyFunction getFunc)
513 {
514
515   // The setter can be empty as a property can be read-only.
516
517   if ( nullptr == getFunc )
518   {
519     DALI_ASSERT_ALWAYS( ! "GetProperty Function is empty" );
520   }
521   else
522   {
523     RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
524                                                           PairFinder< Property::Index, RegisteredPropertyPair>(index) );
525
526     if ( iter == mRegisteredProperties.end() )
527     {
528       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
529     }
530     else
531     {
532       DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
533     }
534   }
535
536 }
537
538 void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Type type)
539 {
540   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
541                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
542
543   if ( iter == mRegisteredProperties.end() )
544   {
545     mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
546   }
547   else
548   {
549     DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
550   }
551 }
552
553 void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Value defaultValue)
554 {
555   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
556                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
557
558   if ( iter == mRegisteredProperties.end() )
559   {
560     mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(defaultValue.GetType(), std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
561     mPropertyDefaultValues.push_back(PropertyDefaultValuePair(index, std::move(defaultValue)));
562   }
563   else
564   {
565     DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
566   }
567 }
568
569 void TypeInfo::AddAnimatablePropertyComponent(std::string name, Property::Index index, Property::Index baseIndex, uint32_t componentIndex)
570 {
571   Property::Type type = GetPropertyType( baseIndex );
572   DALI_ASSERT_ALWAYS( ( type == Property::VECTOR2 || type == Property::VECTOR3 || type == Property::VECTOR4 ) && "Base property does not support component" );
573
574   bool success = false;
575
576   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
577                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
578
579   if ( iter == mRegisteredProperties.end() )
580   {
581     iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
582                     PropertyComponentFinder< RegisteredPropertyPair >( baseIndex, componentIndex ) );
583
584     if ( iter == mRegisteredProperties.end() )
585     {
586       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), baseIndex, componentIndex)));
587       success = true;
588     }
589   }
590
591   DALI_ASSERT_ALWAYS( success && "Property component already registered" );
592 }
593
594 void TypeInfo::AddChildProperty(std::string name, Property::Index index, Property::Type type)
595 {
596   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
597                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
598
599   if ( iter == mRegisteredChildProperties.end() )
600   {
601     mRegisteredChildProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
602   }
603   else
604   {
605     DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
606   }
607 }
608
609 uint32_t TypeInfo::GetPropertyCount() const
610 {
611   uint32_t count = mDefaultPropertyCount + static_cast<uint32_t>( mRegisteredProperties.size() );
612
613   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
614   {
615     // call base type recursively
616     count += mBaseType->GetPropertyCount();
617   }
618
619   return count;
620 }
621
622 Property::Index TypeInfo::GetPropertyIndex( const std::string& name ) const
623 {
624   Property::Index index = Property::INVALID_INDEX;
625   bool found = false;
626
627   // check default properties
628   if( mDefaultProperties )
629   {
630     for( Property::Index tableIndex = 0; tableIndex < mDefaultPropertyCount; ++tableIndex )
631     {
632       if(mDefaultProperties[tableIndex].name == name)
633       {
634         index = mDefaultProperties[ tableIndex ].enumIndex;
635         found = true;
636         break;
637       }
638     }
639   }
640   if( !found )
641   {
642     // Slow but should not be done that often
643     RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
644                                                             PropertyNameFinder< RegisteredPropertyPair >( name ) );
645     if ( iter != mRegisteredProperties.end() )
646     {
647       index = iter->first;
648     }
649     else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
650     {
651       // call base type recursively
652       index = mBaseType->GetPropertyIndex( name );
653     }
654   }
655
656   return index;
657 }
658
659 Property::Index TypeInfo::GetBasePropertyIndex( Property::Index index ) const
660 {
661   Property::Index basePropertyIndex = Property::INVALID_INDEX;
662
663   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
664                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
665
666   if ( iter != mRegisteredProperties.end() )
667   {
668     basePropertyIndex = iter->second.basePropertyIndex;
669   }
670   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
671   {
672     // call base type recursively
673     basePropertyIndex = mBaseType->GetBasePropertyIndex( index );
674   }
675
676   return basePropertyIndex;
677 }
678
679 int32_t TypeInfo::GetComponentIndex( Property::Index index ) const
680 {
681   int componentIndex = Property::INVALID_COMPONENT_INDEX;
682
683   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
684                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
685
686   if ( iter != mRegisteredProperties.end() )
687   {
688     componentIndex = iter->second.componentIndex;
689   }
690   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
691   {
692     // call base type recursively
693     componentIndex = mBaseType->GetComponentIndex( index );
694   }
695
696   return componentIndex;
697 }
698
699 Property::Index TypeInfo::GetChildPropertyIndex( const std::string& name ) const
700 {
701   Property::Index index = Property::INVALID_INDEX;
702
703   // Slow but should not be done that often
704   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
705                                                           PropertyNameFinder< RegisteredPropertyPair >( name ) );
706
707   if ( iter != mRegisteredChildProperties.end() )
708   {
709     index = iter->first;
710   }
711   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
712   {
713     // call base type recursively
714     index = mBaseType->GetChildPropertyIndex( name );
715   }
716
717   return index;
718 }
719
720 const std::string& TypeInfo::GetChildPropertyName( Property::Index index ) const
721 {
722   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
723                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
724
725   if ( iter != mRegisteredChildProperties.end() )
726   {
727     return iter->second.name;
728   }
729
730   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
731   {
732     // call base type recursively
733     return mBaseType->GetChildPropertyName( index );
734   }
735
736   DALI_LOG_ERROR( "Property index %d not found\n", index );
737
738   static std::string empty;
739   return empty;
740 }
741
742 Property::Type TypeInfo::GetChildPropertyType( Property::Index index ) const
743 {
744   Property::Type type( Property::NONE );
745
746   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
747                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
748
749   if ( iter != mRegisteredChildProperties.end() )
750   {
751     type = iter->second.type;
752   }
753   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
754   {
755     // call base type recursively
756     type = mBaseType->GetChildPropertyType( index );
757   }
758   else
759   {
760     DALI_LOG_ERROR( "Property index %d not found\n", index );
761   }
762
763   return type;
764 }
765
766 bool TypeInfo::IsPropertyWritable( Property::Index index ) const
767 {
768   bool writable = false;
769   bool found = false;
770
771   // default property?
772   if ( ( index < DEFAULT_PROPERTY_MAX_COUNT ) && mDefaultProperties )
773   {
774     found = GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::writable, writable );
775   }
776   else if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
777   {
778     writable = true; // animatable property is writable
779     found = true;
780   }
781   else
782   {
783     RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
784                                                             PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
785     if ( iter != mRegisteredProperties.end() )
786     {
787       writable = iter->second.setFunc ? true : false;
788       found = true;
789     }
790   }
791
792   // if not found, continue to base
793   if( !found )
794   {
795     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
796     {
797       // call base type recursively
798       writable = mBaseType->IsPropertyWritable( index );
799     }
800     else
801     {
802       DALI_LOG_ERROR( "Property index %d not found\n", index );
803     }
804   }
805
806   return writable;
807 }
808
809 bool TypeInfo::IsPropertyAnimatable( Property::Index index ) const
810 {
811   bool animatable = false;
812   bool found = false;
813
814   // default property?
815   if ( ( index < DEFAULT_PROPERTY_MAX_COUNT ) && mDefaultProperties )
816   {
817     found = GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::animatable, animatable );
818   }
819   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
820   {
821     // Type Registry event-thread only properties are not animatable.
822     animatable = false;
823     found = true;
824   }
825   else if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
826   {
827     animatable = true;
828     found = true;
829   }
830
831   // if not found, continue to base
832   if( !found )
833   {
834     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
835     {
836       // call base type recursively
837       animatable = mBaseType->IsPropertyAnimatable( index );
838     }
839     else
840     {
841       DALI_LOG_ERROR( "Property index %d not found\n", index );
842     }
843   }
844
845   return animatable;
846 }
847
848 bool TypeInfo::IsPropertyAConstraintInput( Property::Index index ) const
849 {
850   bool constraintInput = false;
851   bool found = false;
852
853   // default property?
854   if ( ( index < DEFAULT_PROPERTY_MAX_COUNT ) && mDefaultProperties )
855   {
856     found = GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::constraintInput, constraintInput );
857   }
858   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
859   {
860     // Type Registry event-thread only properties cannot be used as constraint input
861     constraintInput = false;
862     found = true;
863   }
864   else if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
865   {
866     constraintInput = true;
867     found = true;
868   }
869
870   // if not found, continue to base
871   if( !found )
872   {
873     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
874     {
875       // call base type recursively
876       constraintInput = mBaseType->IsPropertyAConstraintInput( index );
877     }
878     else
879     {
880       DALI_LOG_ERROR( "Property index %d not found\n", index );
881     }
882   }
883
884   return constraintInput;
885 }
886
887
888 Property::Type TypeInfo::GetPropertyType( Property::Index index ) const
889 {
890   Property::Type type( Property::NONE );
891   bool found = false;
892
893   // default property?
894   if ( ( index < DEFAULT_PROPERTY_MAX_COUNT ) && mDefaultProperties )
895   {
896     found = GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::type, type );
897   }
898   else
899   {
900     RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
901                                                             PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
902
903     if ( iter != mRegisteredProperties.end() )
904     {
905       if( iter->second.componentIndex == Property::INVALID_COMPONENT_INDEX )
906       {
907         type = iter->second.type;
908         found = true;
909       }
910       else
911       {
912         // If component index is set, then we should return FLOAT
913         type = Property::FLOAT;
914         found = true;
915       }
916     }
917   }
918
919   if( !found )
920   {
921     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
922     {
923       // call base type recursively
924       type = mBaseType->GetPropertyType( index );
925     }
926     else
927     {
928       DALI_LOG_ERROR( "Property index %d not found\n", index );
929     }
930   }
931
932   return type;
933 }
934
935 Property::Value TypeInfo::GetPropertyDefaultValue( Property::Index index ) const
936 {
937   PropertyDefaultValueContainer::const_iterator iter = find_if( mPropertyDefaultValues.begin(), mPropertyDefaultValues.end(),
938                                                     PairFinder< Property::Index, PropertyDefaultValuePair >( index ) );
939   if( iter != mPropertyDefaultValues.end() )
940   {
941     return iter->second;
942   }
943   // we didn't have a value so ask base
944   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
945   {
946     // call base type recursively
947     return mBaseType->GetPropertyDefaultValue( index );
948   }
949   return Property::Value(); // return none
950 }
951
952 void TypeInfo::SetProperty(BaseObject* object, Property::Index index, Property::Value value) const
953 {
954   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
955                                                               PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
956   if ( iter != mRegisteredProperties.end() )
957   {
958     if( iter->second.setFunc )
959     {
960       if( mCSharpType )
961       {
962         // CSharp wants a property name not an index
963         const std::string& name = (iter->second).name;
964
965         iter->second.cSharpSetFunc( object,name.c_str(), const_cast< Property::Value* >(&value) );
966       }
967       else
968       {
969         iter->second.setFunc(object, index, std::move(value));
970       }
971     }
972   }
973   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
974   {
975     // call base type recursively
976     mBaseType->SetProperty(object, index, std::move(value));
977   }
978   else
979   {
980     DALI_LOG_ERROR( "Property index %d not found\n", index );
981   }
982 }
983
984 void TypeInfo::SetProperty(BaseObject* object, const std::string& name, Property::Value value) const
985 {
986   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
987                                                               PropertyNameFinder< RegisteredPropertyPair >( name ) );
988   if ( iter != mRegisteredProperties.end() )
989   {
990     DALI_ASSERT_ALWAYS( iter->second.setFunc && "Trying to write to a read-only property" );
991
992     if( mCSharpType )
993     {
994       // CSharp wants a property name not an index
995       iter->second.cSharpSetFunc( object,name.c_str(), const_cast< Property::Value* >(&value ));
996     }
997     else
998     {
999       iter->second.setFunc(object, iter->first, std::move(value));
1000     }
1001   }
1002   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
1003   {
1004     // call base type recursively
1005     mBaseType->SetProperty(object, name, std::move(value));
1006   }
1007   else
1008   {
1009     DALI_LOG_ERROR( "Property %s not found", name.c_str() );
1010   }
1011 }
1012
1013 Property::Value TypeInfo::GetProperty( const BaseObject *object, Property::Index index ) const
1014 {
1015   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
1016                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
1017   if( iter != mRegisteredProperties.end() )
1018   {
1019     if( mCSharpType ) // using csharp property get which returns a pointer to a Property::Value
1020     {
1021       // CSharp wants a property name not an index
1022       // CSharp callback can't return an object by value, it can only return a pointer
1023       // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
1024       const std::string& name = (iter->second).name;
1025
1026       return *( iter->second.cSharpGetFunc( const_cast< BaseObject* >( object ), name.c_str()) );
1027
1028     }
1029     else
1030     {
1031       // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
1032       return iter->second.getFunc( const_cast< BaseObject* >( object ), index );
1033     }
1034   }
1035
1036   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
1037   {
1038     // call base type recursively
1039     return mBaseType->GetProperty( object, index );
1040   }
1041
1042   DALI_LOG_ERROR( "Property index %d not found\n", index );
1043   return Property::Value();
1044 }
1045
1046 Property::Value TypeInfo::GetProperty( const BaseObject *object, const std::string& name ) const
1047 {
1048   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
1049                                                             PropertyNameFinder< RegisteredPropertyPair >( name ) );
1050
1051
1052
1053   if( iter != mRegisteredProperties.end() )
1054   {
1055     if( mCSharpType ) // using csharp property get which returns a pointer to a Property::Value
1056     {
1057        // CSharp wants a property name not an index
1058        // CSharp callback can't return an object by value, it can only return a pointer
1059        // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
1060        return *( iter->second.cSharpGetFunc( const_cast< BaseObject* >( object ), name.c_str() ));
1061
1062     }
1063     else
1064     {
1065       // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
1066       return iter->second.getFunc( const_cast< BaseObject* >( object ), iter->first );
1067     }
1068   }
1069
1070   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
1071   {
1072     // call base type recursively
1073     return mBaseType->GetProperty( object, name );
1074   }
1075
1076   DALI_LOG_ERROR( "Property %s not found", name.c_str() );
1077   return Property::Value();
1078 }
1079
1080 } // namespace Internal
1081
1082 } // namespace Dali