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