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