Merge "Clean up the code to build successfully on macOS" 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( 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() = default;
180
181 BaseHandle TypeInfo::CreateInstance() const
182 {
183   BaseHandle ret;
184
185   if(mCreate)
186   {
187     if ( mCSharpType )
188     {
189       // CSharp currently only registers one create function for all custom controls
190       // it uses the type name to decide which one to create
191       ret = *mCSharpCreate( mTypeName.c_str() );
192     }
193     else
194     {
195       ret = mCreate();
196     }
197
198     if ( ret )
199     {
200       BaseObject& handle = ret.GetBaseObject();
201       Object *object = dynamic_cast<Internal::Object*>(&handle);
202
203       if ( object )
204       {
205         object->SetTypeInfo( this );
206       }
207     }
208   }
209   return ret;
210 }
211
212 bool TypeInfo::DoActionTo(BaseObject *object, const std::string &actionName, const Property::Map &properties)
213 {
214   bool done = false;
215
216   ActionContainer::iterator iter = find_if(mActions.begin(), mActions.end(), PairFinder<std::string, ActionPair>(actionName));
217
218   if( iter != mActions.end() )
219   {
220     done = (iter->second)(object, actionName, properties);
221   }
222
223   if( !done )
224   {
225     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
226     {
227       // call base type recursively
228       done = mBaseType->DoActionTo( object, actionName, properties );
229     }
230   }
231
232   return done;
233 }
234
235 bool TypeInfo::ConnectSignal( BaseObject* object, ConnectionTrackerInterface* connectionTracker, const std::string& signalName, FunctorDelegate* functor )
236 {
237   bool connected( false );
238
239   ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
240                                                  PairFinder<std::string, ConnectionPair>(signalName) );
241
242   if( iter != mSignalConnectors.end() )
243   {
244     connected = (iter->second)( object, connectionTracker, signalName, functor );
245   }
246
247   if( !connected )
248   {
249     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
250     {
251       // call base type recursively
252       connected = mBaseType->ConnectSignal( object, connectionTracker, signalName, functor );
253     }
254   }
255
256   return connected;
257 }
258
259 const std::string& TypeInfo::GetName() const
260 {
261   return mTypeName;
262 }
263
264 const std::string& TypeInfo::GetBaseName() const
265 {
266   return mBaseTypeName;
267 }
268
269 Dali::TypeInfo::CreateFunction TypeInfo::GetCreator() const
270 {
271   return mCreate;
272 }
273
274 uint32_t TypeInfo::GetActionCount() const
275 {
276   uint32_t count = static_cast<uint32_t>( mActions.size() );
277
278   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
279   {
280     // call base type recursively
281     count += mBaseType->GetActionCount();
282   }
283
284   return count;
285 }
286
287 std::string TypeInfo::GetActionName( uint32_t index ) const
288 {
289   std::string name;
290   const uint32_t count = static_cast<uint32_t>( mActions.size() );
291
292   if( index < count )
293   {
294     name = mActions[index].first;
295   }
296   else
297   {
298     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
299     {
300       // call base type recursively
301       return mBaseType->GetActionName( index - count );
302     }
303   }
304
305   return name;
306 }
307
308 uint32_t TypeInfo::GetSignalCount() const
309 {
310   uint32_t count = static_cast<uint32_t>( mSignalConnectors.size() );
311
312   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
313   {
314     // call base type recursively
315     count += mBaseType->GetSignalCount();
316   }
317
318   return count;
319 }
320
321 std::string TypeInfo::GetSignalName( uint32_t index ) const
322 {
323   std::string name;
324   const uint32_t count = static_cast<uint32_t>( mSignalConnectors.size() );
325
326   if( index < count )
327   {
328     name = mSignalConnectors[index].first;
329   }
330   else
331   {
332     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
333     {
334       // call base type recursively
335       return mBaseType->GetSignalName( index - count );
336     }
337   }
338
339   return name;
340 }
341
342 void TypeInfo::GetPropertyIndices( Property::IndexContainer& indices ) const
343 {
344   // Default Properties
345   if( mDefaultProperties )
346   {
347     indices.Reserve( indices.Size() + mDefaultPropertyCount );
348     for( Property::Index index = 0; index < mDefaultPropertyCount; ++index )
349     {
350       indices.PushBack( mDefaultProperties[ index ].enumIndex );
351     }
352   }
353
354   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
355   {
356     // call base type recursively
357     mBaseType->GetPropertyIndices( indices );
358   }
359
360   AppendProperties( indices, mRegisteredProperties );
361 }
362
363 void TypeInfo::GetChildPropertyIndices( Property::IndexContainer& indices ) const
364 {
365   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
366   {
367     // call base type recursively
368     mBaseType->GetChildPropertyIndices( indices );
369   }
370
371   AppendProperties( indices, mRegisteredChildProperties );
372 }
373
374 /**
375  * Append the indices in RegisteredProperties to the given index container.
376  */
377 void TypeInfo::AppendProperties( Dali::Property::IndexContainer& indices,
378                                  const TypeInfo::RegisteredPropertyContainer& registeredProperties ) const
379 {
380   if ( ! registeredProperties.empty() )
381   {
382     indices.Reserve( indices.Size() + registeredProperties.size() );
383
384     for( auto&& elem : registeredProperties )
385     {
386       indices.PushBack( elem.first );
387     }
388   }
389 }
390
391 const std::string& TypeInfo::GetRegisteredPropertyName( Property::Index index ) const
392 {
393   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
394                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
395   if ( iter != mRegisteredProperties.end() )
396   {
397     return iter->second.name;
398   }
399   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
400   {
401     // call base type recursively
402     return mBaseType->GetRegisteredPropertyName( index );
403   }
404   static std::string empty;
405   return empty;
406 }
407
408 std::string TypeInfo::GetPropertyName( Property::Index index ) const
409 {
410   std::string propertyName;
411   // default or custom
412   if ( mDefaultProperties && ( index < DEFAULT_PROPERTY_MAX_COUNT ) )
413   {
414     std::string_view name;
415     if( GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::name, name ) )
416     {
417       propertyName = name;
418     }
419   }
420   else
421   {
422     RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
423                                                             PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
424     if ( iter != mRegisteredProperties.end() )
425     {
426       return iter->second.name;
427     }
428   }
429   // if not our property, go to parent
430   if( propertyName.empty() )
431   {
432     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
433     {
434       // call base type recursively
435       return mBaseType->GetPropertyName( index );
436     }
437   }
438
439   return propertyName;
440 }
441
442 void TypeInfo::AddActionFunction(std::string actionName, Dali::TypeInfo::ActionFunction function)
443 {
444   if( nullptr == function)
445   {
446     DALI_LOG_WARNING("Action function is empty\n");
447   }
448   else
449   {
450     ActionContainer::iterator iter = std::find_if(mActions.begin(), mActions.end(),
451                                                   PairFinder<std::string, ActionPair>(actionName));
452
453     if( iter == mActions.end() )
454     {
455       mActions.push_back(ActionPair(std::move(actionName), function));
456     }
457     else
458     {
459       DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str());
460     }
461   }
462 }
463
464 void TypeInfo::AddConnectorFunction(std::string signalName, Dali::TypeInfo::SignalConnectorFunction function)
465 {
466   if( nullptr == function)
467   {
468     DALI_LOG_WARNING("Connector function is empty\n");
469   }
470   else
471   {
472     ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
473                                                    PairFinder<std::string, ConnectionPair>(signalName) );
474
475     if( iter == mSignalConnectors.end() )
476     {
477       mSignalConnectors.push_back(ConnectionPair(std::move(signalName), function));
478     }
479     else
480     {
481       DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str());
482     }
483   }
484 }
485
486 void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Type type, Dali::TypeInfo::SetPropertyFunction setFunc, Dali::TypeInfo::GetPropertyFunction getFunc)
487 {
488   // The setter can be empty as a property can be read-only.
489
490   if ( nullptr == getFunc )
491   {
492     DALI_ASSERT_ALWAYS( ! "GetProperty Function is empty" );
493   }
494   else
495   {
496     RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
497                                                           PairFinder< Property::Index, RegisteredPropertyPair>(index) );
498
499     if ( iter == mRegisteredProperties.end() )
500     {
501       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
502     }
503     else
504     {
505       DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
506     }
507   }
508 }
509
510 void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Type type, Dali::CSharpTypeInfo::SetPropertyFunction setFunc, Dali::CSharpTypeInfo::GetPropertyFunction getFunc)
511 {
512
513   // The setter can be empty as a property can be read-only.
514
515   if ( nullptr == getFunc )
516   {
517     DALI_ASSERT_ALWAYS( ! "GetProperty Function is empty" );
518   }
519   else
520   {
521     RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
522                                                           PairFinder< Property::Index, RegisteredPropertyPair>(index) );
523
524     if ( iter == mRegisteredProperties.end() )
525     {
526       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
527     }
528     else
529     {
530       DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
531     }
532   }
533
534 }
535
536 void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Type type)
537 {
538   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
539                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
540
541   if ( iter == mRegisteredProperties.end() )
542   {
543     mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
544   }
545   else
546   {
547     DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
548   }
549 }
550
551 void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Value defaultValue)
552 {
553   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
554                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
555
556   if ( iter == mRegisteredProperties.end() )
557   {
558     mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(defaultValue.GetType(), std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
559     mPropertyDefaultValues.push_back(PropertyDefaultValuePair(index, std::move(defaultValue)));
560   }
561   else
562   {
563     DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
564   }
565 }
566
567 void TypeInfo::AddAnimatablePropertyComponent(std::string name, Property::Index index, Property::Index baseIndex, uint32_t componentIndex)
568 {
569   Property::Type type = GetPropertyType( baseIndex );
570   DALI_ASSERT_ALWAYS( ( type == Property::VECTOR2 || type == Property::VECTOR3 || type == Property::VECTOR4 ) && "Base property does not support component" );
571
572   bool success = false;
573
574   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
575                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
576
577   if ( iter == mRegisteredProperties.end() )
578   {
579     iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
580                     PropertyComponentFinder< RegisteredPropertyPair >( baseIndex, componentIndex ) );
581
582     if ( iter == mRegisteredProperties.end() )
583     {
584       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), baseIndex, componentIndex)));
585       success = true;
586     }
587   }
588
589   DALI_ASSERT_ALWAYS( success && "Property component already registered" );
590 }
591
592 void TypeInfo::AddChildProperty(std::string name, Property::Index index, Property::Type type)
593 {
594   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
595                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
596
597   if ( iter == mRegisteredChildProperties.end() )
598   {
599     mRegisteredChildProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, std::move(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
600   }
601   else
602   {
603     DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
604   }
605 }
606
607 uint32_t TypeInfo::GetPropertyCount() const
608 {
609   uint32_t count = mDefaultPropertyCount + static_cast<uint32_t>( mRegisteredProperties.size() );
610
611   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
612   {
613     // call base type recursively
614     count += mBaseType->GetPropertyCount();
615   }
616
617   return count;
618 }
619
620 Property::Index TypeInfo::GetPropertyIndex( const std::string& name ) const
621 {
622   Property::Index index = Property::INVALID_INDEX;
623   bool found = false;
624
625   // check default properties
626   if( mDefaultProperties )
627   {
628     for( Property::Index tableIndex = 0; tableIndex < mDefaultPropertyCount; ++tableIndex )
629     {
630       if(mDefaultProperties[tableIndex].name == name)
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( const std::string& 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 const std::string& 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;
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   static std::string empty;
737   return empty;
738 }
739
740 Property::Type TypeInfo::GetChildPropertyType( Property::Index index ) const
741 {
742   Property::Type type( Property::NONE );
743
744   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
745                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
746
747   if ( iter != mRegisteredChildProperties.end() )
748   {
749     type = iter->second.type;
750   }
751   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
752   {
753     // call base type recursively
754     type = mBaseType->GetChildPropertyType( index );
755   }
756   else
757   {
758     DALI_LOG_ERROR( "Property index %d not found\n", index );
759   }
760
761   return type;
762 }
763
764 bool TypeInfo::IsPropertyWritable( Property::Index index ) const
765 {
766   bool writable = false;
767   bool found = false;
768
769   // default property?
770   if ( ( index < DEFAULT_PROPERTY_MAX_COUNT ) && mDefaultProperties )
771   {
772     found = GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::writable, writable );
773   }
774   else if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
775   {
776     writable = true; // animatable property is writable
777     found = true;
778   }
779   else
780   {
781     RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
782                                                             PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
783     if ( iter != mRegisteredProperties.end() )
784     {
785       writable = iter->second.setFunc ? true : false;
786       found = true;
787     }
788   }
789
790   // if not found, continue to base
791   if( !found )
792   {
793     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
794     {
795       // call base type recursively
796       writable = mBaseType->IsPropertyWritable( index );
797     }
798     else
799     {
800       DALI_LOG_ERROR( "Property index %d not found\n", index );
801     }
802   }
803
804   return writable;
805 }
806
807 bool TypeInfo::IsPropertyAnimatable( Property::Index index ) const
808 {
809   bool animatable = false;
810   bool found = false;
811
812   // default property?
813   if ( ( index < DEFAULT_PROPERTY_MAX_COUNT ) && mDefaultProperties )
814   {
815     found = GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::animatable, animatable );
816   }
817   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
818   {
819     // Type Registry event-thread only properties are not animatable.
820     animatable = false;
821     found = true;
822   }
823   else if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
824   {
825     animatable = true;
826     found = true;
827   }
828
829   // if not found, continue to base
830   if( !found )
831   {
832     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
833     {
834       // call base type recursively
835       animatable = mBaseType->IsPropertyAnimatable( index );
836     }
837     else
838     {
839       DALI_LOG_ERROR( "Property index %d not found\n", index );
840     }
841   }
842
843   return animatable;
844 }
845
846 bool TypeInfo::IsPropertyAConstraintInput( Property::Index index ) const
847 {
848   bool constraintInput = false;
849   bool found = false;
850
851   // default property?
852   if ( ( index < DEFAULT_PROPERTY_MAX_COUNT ) && mDefaultProperties )
853   {
854     found = GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::constraintInput, constraintInput );
855   }
856   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
857   {
858     // Type Registry event-thread only properties cannot be used as constraint input
859     constraintInput = false;
860     found = true;
861   }
862   else if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
863   {
864     constraintInput = true;
865     found = true;
866   }
867
868   // if not found, continue to base
869   if( !found )
870   {
871     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
872     {
873       // call base type recursively
874       constraintInput = mBaseType->IsPropertyAConstraintInput( index );
875     }
876     else
877     {
878       DALI_LOG_ERROR( "Property index %d not found\n", index );
879     }
880   }
881
882   return constraintInput;
883 }
884
885
886 Property::Type TypeInfo::GetPropertyType( Property::Index index ) const
887 {
888   Property::Type type( Property::NONE );
889   bool found = false;
890
891   // default property?
892   if ( ( index < DEFAULT_PROPERTY_MAX_COUNT ) && mDefaultProperties )
893   {
894     found = GetDefaultPropertyField( mDefaultProperties, mDefaultPropertyCount,index, &Dali::PropertyDetails::type, type );
895   }
896   else
897   {
898     RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
899                                                             PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
900
901     if ( iter != mRegisteredProperties.end() )
902     {
903       if( iter->second.componentIndex == Property::INVALID_COMPONENT_INDEX )
904       {
905         type = iter->second.type;
906         found = true;
907       }
908       else
909       {
910         // If component index is set, then we should return FLOAT
911         type = Property::FLOAT;
912         found = true;
913       }
914     }
915   }
916
917   if( !found )
918   {
919     if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
920     {
921       // call base type recursively
922       type = mBaseType->GetPropertyType( index );
923     }
924     else
925     {
926       DALI_LOG_ERROR( "Property index %d not found\n", index );
927     }
928   }
929
930   return type;
931 }
932
933 Property::Value TypeInfo::GetPropertyDefaultValue( Property::Index index ) const
934 {
935   PropertyDefaultValueContainer::const_iterator iter = find_if( mPropertyDefaultValues.begin(), mPropertyDefaultValues.end(),
936                                                     PairFinder< Property::Index, PropertyDefaultValuePair >( index ) );
937   if( iter != mPropertyDefaultValues.end() )
938   {
939     return iter->second;
940   }
941   // we didn't have a value so ask base
942   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
943   {
944     // call base type recursively
945     return mBaseType->GetPropertyDefaultValue( index );
946   }
947   return Property::Value(); // return none
948 }
949
950 void TypeInfo::SetProperty(BaseObject* object, Property::Index index, Property::Value value) const
951 {
952   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
953                                                               PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
954   if ( iter != mRegisteredProperties.end() )
955   {
956     if( iter->second.setFunc )
957     {
958       if( mCSharpType )
959       {
960         // CSharp wants a property name not an index
961         const std::string& name = (iter->second).name;
962
963         iter->second.cSharpSetFunc( object,name.c_str(), const_cast< Property::Value* >(&value) );
964       }
965       else
966       {
967         iter->second.setFunc(object, index, std::move(value));
968       }
969     }
970   }
971   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
972   {
973     // call base type recursively
974     mBaseType->SetProperty(object, index, std::move(value));
975   }
976   else
977   {
978     DALI_LOG_ERROR( "Property index %d not found\n", index );
979   }
980 }
981
982 void TypeInfo::SetProperty(BaseObject* object, const std::string& name, Property::Value value) const
983 {
984   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
985                                                               PropertyNameFinder< RegisteredPropertyPair >( name ) );
986   if ( iter != mRegisteredProperties.end() )
987   {
988     DALI_ASSERT_ALWAYS( iter->second.setFunc && "Trying to write to a read-only property" );
989
990     if( mCSharpType )
991     {
992       // CSharp wants a property name not an index
993       iter->second.cSharpSetFunc( object,name.c_str(), const_cast< Property::Value* >(&value ));
994     }
995     else
996     {
997       iter->second.setFunc(object, iter->first, std::move(value));
998     }
999   }
1000   else if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
1001   {
1002     // call base type recursively
1003     mBaseType->SetProperty(object, name, std::move(value));
1004   }
1005   else
1006   {
1007     DALI_LOG_ERROR( "Property %s not found", name.c_str() );
1008   }
1009 }
1010
1011 Property::Value TypeInfo::GetProperty( const BaseObject *object, Property::Index index ) const
1012 {
1013   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
1014                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
1015   if( iter != mRegisteredProperties.end() )
1016   {
1017     if( mCSharpType ) // using csharp property get which returns a pointer to a Property::Value
1018     {
1019       // CSharp wants a property name not an index
1020       // CSharp callback can't return an object by value, it can only return a pointer
1021       // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
1022       const std::string& name = (iter->second).name;
1023
1024       return *( iter->second.cSharpGetFunc( const_cast< BaseObject* >( object ), name.c_str()) );
1025
1026     }
1027     else
1028     {
1029       // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
1030       return iter->second.getFunc( const_cast< BaseObject* >( object ), index );
1031     }
1032   }
1033
1034   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
1035   {
1036     // call base type recursively
1037     return mBaseType->GetProperty( object, index );
1038   }
1039
1040   DALI_LOG_ERROR( "Property index %d not found\n", index );
1041   return Property::Value();
1042 }
1043
1044 Property::Value TypeInfo::GetProperty( const BaseObject *object, const std::string& name ) const
1045 {
1046   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
1047                                                             PropertyNameFinder< RegisteredPropertyPair >( name ) );
1048
1049
1050
1051   if( iter != mRegisteredProperties.end() )
1052   {
1053     if( mCSharpType ) // using csharp property get which returns a pointer to a Property::Value
1054     {
1055        // CSharp wants a property name not an index
1056        // CSharp callback can't return an object by value, it can only return a pointer
1057        // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
1058        return *( iter->second.cSharpGetFunc( const_cast< BaseObject* >( object ), name.c_str() ));
1059
1060     }
1061     else
1062     {
1063       // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
1064       return iter->second.getFunc( const_cast< BaseObject* >( object ), iter->first );
1065     }
1066   }
1067
1068   if( GetBaseType( mBaseType, mTypeRegistry, mBaseTypeName ) )
1069   {
1070     // call base type recursively
1071     return mBaseType->GetProperty( object, name );
1072   }
1073
1074   DALI_LOG_ERROR( "Property %s not found", name.c_str() );
1075   return Property::Value();
1076 }
1077
1078 } // namespace Internal
1079
1080 } // namespace Dali