Add Internal::IndexedMap
[platform/core/uifw/dali-core.git] / dali / internal / event / common / type-info-impl.cpp
1 /*
2  * Copyright (c) 2022 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 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
219   auto iter = mActions.Get(ConstString(actionName));
220 #else
221   ActionContainer::iterator    iter = find_if(mActions.begin(), mActions.end(), PairFinder<std::string, ActionPair>(actionName));
222 #endif
223   if(iter != mActions.end())
224   {
225     done = (iter->second)(object, actionName, properties);
226   }
227
228   if(!done)
229   {
230     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
231     {
232       // call base type recursively
233       done = mBaseType->DoActionTo(object, actionName, properties);
234     }
235   }
236
237   return done;
238 }
239
240 bool TypeInfo::ConnectSignal(BaseObject* object, ConnectionTrackerInterface* connectionTracker, const std::string& signalName, FunctorDelegate* functor)
241 {
242   bool connected(false);
243
244 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
245   auto iter = mSignalConnectors.Get(ConstString(signalName));
246 #else
247   ConnectorContainer::iterator iter = find_if(mSignalConnectors.begin(), mSignalConnectors.end(), PairFinder<std::string, ConnectionPair>(signalName));
248 #endif
249   if(iter != mSignalConnectors.end())
250   {
251     connected = (iter->second)(object, connectionTracker, signalName, functor);
252   }
253
254   if(!connected)
255   {
256     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
257     {
258       // call base type recursively
259       connected = mBaseType->ConnectSignal(object, connectionTracker, signalName, functor);
260     }
261   }
262
263   return connected;
264 }
265
266 const std::string& TypeInfo::GetName() const
267 {
268   return mTypeName;
269 }
270
271 const std::string& TypeInfo::GetBaseName() const
272 {
273   return mBaseTypeName;
274 }
275
276 Dali::TypeInfo::CreateFunction TypeInfo::GetCreator() const
277 {
278   return mCreate;
279 }
280
281 uint32_t TypeInfo::GetActionCount() const
282 {
283   uint32_t count = static_cast<uint32_t>(mActions.size());
284
285   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
286   {
287     // call base type recursively
288     count += mBaseType->GetActionCount();
289   }
290
291   return count;
292 }
293
294 std::string TypeInfo::GetActionName(uint32_t index) const
295 {
296   std::string    name;
297   const uint32_t count = static_cast<uint32_t>(mActions.size());
298
299   if(index < count)
300   {
301 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
302     name = std::string(mActions.GetKeyByIndex(index).GetStringView());
303 #else
304     name = mActions[index].first;
305 #endif
306   }
307   else
308   {
309     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
310     {
311       // call base type recursively
312       return mBaseType->GetActionName(index - count);
313     }
314   }
315
316   return name;
317 }
318
319 uint32_t TypeInfo::GetSignalCount() const
320 {
321   uint32_t count = static_cast<uint32_t>(mSignalConnectors.size());
322
323   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
324   {
325     // call base type recursively
326     count += mBaseType->GetSignalCount();
327   }
328
329   return count;
330 }
331
332 std::string TypeInfo::GetSignalName(uint32_t index) const
333 {
334   std::string    name;
335   const uint32_t count = static_cast<uint32_t>(mSignalConnectors.size());
336
337   if(index < count)
338   {
339 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
340     name = std::string(mSignalConnectors.GetKeyByIndex(index).GetStringView());
341 #else
342     name = mSignalConnectors[index].first;
343 #endif
344   }
345   else
346   {
347     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
348     {
349       // call base type recursively
350       return mBaseType->GetSignalName(index - count);
351     }
352   }
353
354   return name;
355 }
356
357 void TypeInfo::GetPropertyIndices(Property::IndexContainer& indices) const
358 {
359   // Default Properties
360   if(mDefaultProperties)
361   {
362     indices.Reserve(indices.Size() + mDefaultPropertyCount);
363     for(Property::Index index = 0; index < mDefaultPropertyCount; ++index)
364     {
365       indices.PushBack(mDefaultProperties[index].enumIndex);
366     }
367   }
368
369   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
370   {
371     // call base type recursively
372     mBaseType->GetPropertyIndices(indices);
373   }
374
375   AppendProperties(indices, mRegisteredProperties);
376 }
377
378 void TypeInfo::GetChildPropertyIndices(Property::IndexContainer& indices) const
379 {
380   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
381   {
382     // call base type recursively
383     mBaseType->GetChildPropertyIndices(indices);
384   }
385
386   AppendProperties(indices, mRegisteredChildProperties);
387 }
388
389 /**
390  * Append the indices in RegisteredProperties to the given index container.
391  */
392 void TypeInfo::AppendProperties(Dali::Property::IndexContainer&              indices,
393                                 const TypeInfo::RegisteredPropertyContainer& registeredProperties) const
394 {
395   if(!registeredProperties.empty())
396   {
397     indices.Reserve(indices.Size() + registeredProperties.size());
398
399     for(auto&& elem : registeredProperties)
400     {
401       indices.PushBack(elem.first);
402     }
403   }
404 }
405
406 std::string_view TypeInfo::GetRegisteredPropertyName(Property::Index index) const
407 {
408 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
409   const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
410 #else
411   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
412 #endif
413   if(iter != mRegisteredProperties.end())
414   {
415     return iter->second.name.GetStringView();
416   }
417   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
418   {
419     // call base type recursively
420     return mBaseType->GetRegisteredPropertyName(index);
421   }
422   static std::string empty;
423   return empty;
424 }
425
426 std::string_view TypeInfo::GetPropertyName(Property::Index index) const
427 {
428   std::string_view propertyName;
429   // default or custom
430   if(mDefaultProperties && (index < DEFAULT_PROPERTY_MAX_COUNT))
431   {
432     std::string_view name;
433     if(GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::name, name))
434     {
435       propertyName = name;
436     }
437   }
438   else
439   {
440 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
441     const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
442 #else
443     RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
444 #endif
445     if(iter != mRegisteredProperties.end())
446     {
447       return iter->second.name.GetStringView();
448     }
449   }
450   // if not our property, go to parent
451   if(propertyName.empty())
452   {
453     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
454     {
455       // call base type recursively
456       return mBaseType->GetPropertyName(index);
457     }
458   }
459
460   return propertyName;
461 }
462
463 void TypeInfo::AddActionFunction(std::string actionName, Dali::TypeInfo::ActionFunction function)
464 {
465   if(nullptr == function)
466   {
467     DALI_LOG_WARNING("Action function is empty\n");
468   }
469   else
470   {
471 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
472     if(!mActions.Register(ConstString(actionName), function))
473     {
474       DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str());
475     }
476 #else
477     ActionContainer::iterator                   iter = std::find_if(mActions.begin(), mActions.end(), PairFinder<std::string, ActionPair>(actionName));
478
479     if(iter == mActions.end())
480     {
481       mActions.push_back(ActionPair(std::move(actionName), function));
482     }
483     else
484     {
485       DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str());
486     }
487 #endif
488   }
489 }
490
491 void TypeInfo::AddConnectorFunction(std::string signalName, Dali::TypeInfo::SignalConnectorFunction function)
492 {
493   if(nullptr == function)
494   {
495     DALI_LOG_WARNING("Connector function is empty\n");
496   }
497   else
498   {
499 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
500     if(!mSignalConnectors.Register(ConstString(signalName), function))
501     {
502       DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str());
503     }
504 #else
505     ConnectorContainer::iterator iter = find_if(mSignalConnectors.begin(), mSignalConnectors.end(), PairFinder<std::string, ConnectionPair>(signalName));
506
507     if(iter == mSignalConnectors.end())
508     {
509       mSignalConnectors.push_back(ConnectionPair(std::move(signalName), function));
510     }
511     else
512     {
513       DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str());
514     }
515 #endif
516   }
517 }
518
519 void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Type type, Dali::TypeInfo::SetPropertyFunction setFunc, Dali::TypeInfo::GetPropertyFunction getFunc)
520 {
521   // The setter can be empty as a property can be read-only.
522
523   if(nullptr == getFunc)
524   {
525     DALI_ASSERT_ALWAYS(!"GetProperty Function is empty");
526   }
527   else
528   {
529 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
530     if(!mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
531     {
532       DALI_ASSERT_ALWAYS(!"Property index already added to Type");
533     }
534 #else
535     RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
536     if(iter == mRegisteredProperties.end())
537     {
538       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
539     }
540     else
541     {
542       DALI_ASSERT_ALWAYS(!"Property index already added to Type");
543     }
544 #endif
545   }
546 }
547
548 void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Type type, Dali::CSharpTypeInfo::SetPropertyFunction setFunc, Dali::CSharpTypeInfo::GetPropertyFunction getFunc)
549 {
550   // The setter can be empty as a property can be read-only.
551
552   if(nullptr == getFunc)
553   {
554     DALI_ASSERT_ALWAYS(!"GetProperty Function is empty");
555   }
556   else
557   {
558 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
559     if(!mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
560     {
561       DALI_ASSERT_ALWAYS(!"Property index already added to Type");
562     }
563 #else
564     RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
565     if(iter == mRegisteredProperties.end())
566     {
567       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
568     }
569     else
570     {
571       DALI_ASSERT_ALWAYS(!"Property index already added to Type");
572     }
573 #endif
574   }
575 }
576
577 void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Type type)
578 {
579 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
580   if(!mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
581   {
582     DALI_ASSERT_ALWAYS(!"Property index already added to Type");
583   }
584 #else
585   RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
586   if(iter == mRegisteredProperties.end())
587   {
588     mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
589   }
590   else
591   {
592     DALI_ASSERT_ALWAYS(!"Property index already added to Type");
593   }
594 #endif
595 }
596
597 void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Value defaultValue)
598 {
599 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
600   if(!mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(defaultValue.GetType(), ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
601   {
602     DALI_ASSERT_ALWAYS(!"Property index already added to Type");
603   }
604   else
605   {
606     mPropertyDefaultValues.Register(static_cast<std::uint32_t>(index), std::move(defaultValue));
607   }
608 #else
609   RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
610   if(iter == mRegisteredProperties.end())
611   {
612     mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(defaultValue.GetType(), ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
613     mPropertyDefaultValues.push_back(PropertyDefaultValuePair(index, std::move(defaultValue)));
614   }
615   else
616   {
617     DALI_ASSERT_ALWAYS(!"Property index already added to Type");
618   }
619 #endif
620 }
621
622 void TypeInfo::AddAnimatablePropertyComponent(std::string name, Property::Index index, Property::Index baseIndex, uint32_t componentIndex)
623 {
624   Property::Type type = GetPropertyType(baseIndex);
625   DALI_ASSERT_ALWAYS((type == Property::VECTOR2 || type == Property::VECTOR3 || type == Property::VECTOR4) && "Base property does not support component");
626
627   bool success = false;
628
629 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
630   if(mRegisteredProperties.Get(static_cast<std::uint32_t>(index)) == mRegisteredProperties.end())
631   {
632     const auto& iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyComponentFinder<RegisteredPropertyPair>(baseIndex, componentIndex));
633
634     if(iter == mRegisteredProperties.end())
635     {
636       mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, ConstString(name), baseIndex, componentIndex));
637       success = true;
638     }
639   }
640 #else
641   RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
642   if(iter == mRegisteredProperties.end())
643   {
644     iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyComponentFinder<RegisteredPropertyPair>(baseIndex, componentIndex));
645
646     if(iter == mRegisteredProperties.end())
647     {
648       mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), baseIndex, componentIndex)));
649       success = true;
650     }
651   }
652 #endif
653
654   DALI_ASSERT_ALWAYS(success && "Property component already registered");
655 }
656
657 void TypeInfo::AddChildProperty(std::string name, Property::Index index, Property::Type type)
658 {
659 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
660   if(!mRegisteredChildProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
661 #else
662   RegisteredPropertyContainer::iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
663   if(iter == mRegisteredChildProperties.end())
664   {
665     mRegisteredChildProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
666   }
667   else
668 #endif
669   {
670     DALI_ASSERT_ALWAYS(!"Property index already added to Type");
671   }
672 }
673
674 uint32_t TypeInfo::GetPropertyCount() const
675 {
676   uint32_t count = mDefaultPropertyCount + static_cast<uint32_t>(mRegisteredProperties.size());
677
678   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
679   {
680     // call base type recursively
681     count += mBaseType->GetPropertyCount();
682   }
683
684   return count;
685 }
686
687 Property::Index TypeInfo::GetPropertyIndex(ConstString name) const
688 {
689   Property::Index index = Property::INVALID_INDEX;
690   bool            found = false;
691
692   // check default properties
693   if(mDefaultProperties)
694   {
695     auto stringView = name.GetStringView();
696     for(Property::Index tableIndex = 0; tableIndex < mDefaultPropertyCount; ++tableIndex)
697     {
698       if(mDefaultProperties[tableIndex].name == stringView)
699       {
700         index = mDefaultProperties[tableIndex].enumIndex;
701         found = true;
702         break;
703       }
704     }
705   }
706   if(!found)
707   {
708     // Slow but should not be done that often
709     RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(name));
710     if(iter != mRegisteredProperties.end())
711     {
712       index = iter->first;
713     }
714     else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
715     {
716       // call base type recursively
717       index = mBaseType->GetPropertyIndex(name);
718     }
719   }
720
721   return index;
722 }
723
724 Property::Index TypeInfo::GetBasePropertyIndex(Property::Index index) const
725 {
726   Property::Index basePropertyIndex = Property::INVALID_INDEX;
727
728 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
729   const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
730 #else
731   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
732 #endif
733   if(iter != mRegisteredProperties.end())
734   {
735     basePropertyIndex = iter->second.basePropertyIndex;
736   }
737   else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
738   {
739     // call base type recursively
740     basePropertyIndex = mBaseType->GetBasePropertyIndex(index);
741   }
742
743   return basePropertyIndex;
744 }
745
746 int32_t TypeInfo::GetComponentIndex(Property::Index index) const
747 {
748   int componentIndex = Property::INVALID_COMPONENT_INDEX;
749
750 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
751   const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
752 #else
753   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
754 #endif
755   if(iter != mRegisteredProperties.end())
756   {
757     componentIndex = iter->second.componentIndex;
758   }
759   else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
760   {
761     // call base type recursively
762     componentIndex = mBaseType->GetComponentIndex(index);
763   }
764
765   return componentIndex;
766 }
767
768 Property::Index TypeInfo::GetChildPropertyIndex(ConstString name) const
769 {
770   Property::Index index = Property::INVALID_INDEX;
771
772   // Slow but should not be done that often
773   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(name));
774
775   if(iter != mRegisteredChildProperties.end())
776   {
777     index = iter->first;
778   }
779   else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
780   {
781     // call base type recursively
782     index = mBaseType->GetChildPropertyIndex(name);
783   }
784
785   return index;
786 }
787
788 std::string_view TypeInfo::GetChildPropertyName(Property::Index index) const
789 {
790 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
791   const auto& iter = mRegisteredChildProperties.Get(static_cast<std::uint32_t>(index));
792 #else
793   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
794 #endif
795   if(iter != mRegisteredChildProperties.end())
796   {
797     return iter->second.name.GetStringView();
798   }
799
800   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
801   {
802     // call base type recursively
803     return mBaseType->GetChildPropertyName(index);
804   }
805
806   DALI_LOG_ERROR("Property index %d not found\n", index);
807
808   return {};
809 }
810
811 Property::Type TypeInfo::GetChildPropertyType(Property::Index index) const
812 {
813   Property::Type type(Property::NONE);
814
815 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
816   const auto& iter = mRegisteredChildProperties.Get(static_cast<std::uint32_t>(index));
817 #else
818   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
819 #endif
820   if(iter != mRegisteredChildProperties.end())
821   {
822     type = iter->second.type;
823   }
824   else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
825   {
826     // call base type recursively
827     type = mBaseType->GetChildPropertyType(index);
828   }
829   else
830   {
831     DALI_LOG_ERROR("Property index %d not found\n", index);
832   }
833
834   return type;
835 }
836
837 bool TypeInfo::IsPropertyWritable(Property::Index index) const
838 {
839   bool writable = false;
840   bool found    = false;
841
842   // default property?
843   if((index < DEFAULT_PROPERTY_MAX_COUNT) && mDefaultProperties)
844   {
845     found = GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::writable, writable);
846   }
847   else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
848   {
849     writable = true; // animatable property is writable
850     found    = true;
851   }
852   else
853   {
854 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
855     const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
856 #else
857     RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
858 #endif
859     if(iter != mRegisteredProperties.end())
860     {
861       writable = iter->second.setFunc ? true : false;
862       found    = true;
863     }
864   }
865
866   // if not found, continue to base
867   if(!found)
868   {
869     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
870     {
871       // call base type recursively
872       writable = mBaseType->IsPropertyWritable(index);
873     }
874     else
875     {
876       DALI_LOG_ERROR("Property index %d not found\n", index);
877     }
878   }
879
880   return writable;
881 }
882
883 bool TypeInfo::IsPropertyAnimatable(Property::Index index) const
884 {
885   bool animatable = false;
886   bool found      = false;
887
888   // default property?
889   if((index < DEFAULT_PROPERTY_MAX_COUNT) && mDefaultProperties)
890   {
891     found = GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::animatable, animatable);
892   }
893   else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
894   {
895     // Type Registry event-thread only properties are not animatable.
896     animatable = false;
897     found      = true;
898   }
899   else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
900   {
901     animatable = true;
902     found      = true;
903   }
904
905   // if not found, continue to base
906   if(!found)
907   {
908     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
909     {
910       // call base type recursively
911       animatable = mBaseType->IsPropertyAnimatable(index);
912     }
913     else
914     {
915       DALI_LOG_ERROR("Property index %d not found\n", index);
916     }
917   }
918
919   return animatable;
920 }
921
922 bool TypeInfo::IsPropertyAConstraintInput(Property::Index index) const
923 {
924   bool constraintInput = false;
925   bool found           = false;
926
927   // default property?
928   if((index < DEFAULT_PROPERTY_MAX_COUNT) && mDefaultProperties)
929   {
930     found = GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::constraintInput, constraintInput);
931   }
932   else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
933   {
934     // Type Registry event-thread only properties cannot be used as constraint input
935     constraintInput = false;
936     found           = true;
937   }
938   else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
939   {
940     constraintInput = true;
941     found           = true;
942   }
943
944   // if not found, continue to base
945   if(!found)
946   {
947     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
948     {
949       // call base type recursively
950       constraintInput = mBaseType->IsPropertyAConstraintInput(index);
951     }
952     else
953     {
954       DALI_LOG_ERROR("Property index %d not found\n", index);
955     }
956   }
957
958   return constraintInput;
959 }
960
961 Property::Type TypeInfo::GetPropertyType(Property::Index index) const
962 {
963   Property::Type type(Property::NONE);
964   bool           found = false;
965
966   // default property?
967   if((index < DEFAULT_PROPERTY_MAX_COUNT) && mDefaultProperties)
968   {
969     found = GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::type, type);
970   }
971   else
972   {
973 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
974     const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
975 #else
976     RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
977 #endif
978     if(iter != mRegisteredProperties.end())
979     {
980       if(iter->second.componentIndex == Property::INVALID_COMPONENT_INDEX)
981       {
982         type  = iter->second.type;
983         found = true;
984       }
985       else
986       {
987         // If component index is set, then we should return FLOAT
988         type  = Property::FLOAT;
989         found = true;
990       }
991     }
992   }
993
994   if(!found)
995   {
996     if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
997     {
998       // call base type recursively
999       type = mBaseType->GetPropertyType(index);
1000     }
1001     else
1002     {
1003       DALI_LOG_ERROR("Property index %d not found\n", index);
1004     }
1005   }
1006
1007   return type;
1008 }
1009
1010 Property::Value TypeInfo::GetPropertyDefaultValue(Property::Index index) const
1011 {
1012 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
1013   const auto& iter = mPropertyDefaultValues.Get(static_cast<std::uint32_t>(index));
1014 #else
1015   PropertyDefaultValueContainer::const_iterator iter = find_if(mPropertyDefaultValues.begin(), mPropertyDefaultValues.end(), PairFinder<Property::Index, PropertyDefaultValuePair>(index));
1016 #endif
1017   if(iter != mPropertyDefaultValues.end())
1018   {
1019     return iter->second;
1020   }
1021   // we didn't have a value so ask base
1022   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
1023   {
1024     // call base type recursively
1025     return mBaseType->GetPropertyDefaultValue(index);
1026   }
1027   return Property::Value(); // return none
1028 }
1029
1030 void TypeInfo::SetProperty(BaseObject* object, Property::Index index, Property::Value value) const
1031 {
1032 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
1033   const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
1034 #else
1035   RegisteredPropertyContainer::const_iterator   iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
1036 #endif
1037   if(iter != mRegisteredProperties.end())
1038   {
1039     if(iter->second.setFunc)
1040     {
1041       if(mCSharpType)
1042       {
1043         // CSharp wants a property name not an index
1044         auto name = (iter->second).name;
1045
1046         iter->second.cSharpSetFunc(object, name.GetCString(), const_cast<Property::Value*>(&value));
1047       }
1048       else
1049       {
1050         iter->second.setFunc(object, index, std::move(value));
1051       }
1052     }
1053   }
1054   else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
1055   {
1056     // call base type recursively
1057     mBaseType->SetProperty(object, index, std::move(value));
1058   }
1059   else
1060   {
1061     DALI_LOG_ERROR("Property index %d not found\n", index);
1062   }
1063 }
1064
1065 void TypeInfo::SetProperty(BaseObject* object, const std::string& name, Property::Value value) const
1066 {
1067   // Slow but should not be done that often
1068   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(ConstString(name)));
1069   if(iter != mRegisteredProperties.end())
1070   {
1071     DALI_ASSERT_ALWAYS(iter->second.setFunc && "Trying to write to a read-only property");
1072
1073     if(mCSharpType)
1074     {
1075       // CSharp wants a property name not an index
1076       iter->second.cSharpSetFunc(object, name.c_str(), const_cast<Property::Value*>(&value));
1077     }
1078     else
1079     {
1080       iter->second.setFunc(object, iter->first, std::move(value));
1081     }
1082   }
1083   else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
1084   {
1085     // call base type recursively
1086     mBaseType->SetProperty(object, name, std::move(value));
1087   }
1088   else
1089   {
1090     DALI_LOG_ERROR("Property %s not found", name.c_str());
1091   }
1092 }
1093
1094 Property::Value TypeInfo::GetProperty(const BaseObject* object, Property::Index index) const
1095 {
1096 #ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
1097   const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
1098 #else
1099   RegisteredPropertyContainer::const_iterator   iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
1100 #endif
1101   if(iter != mRegisteredProperties.end())
1102   {
1103     if(mCSharpType) // using csharp property get which returns a pointer to a Property::Value
1104     {
1105       // CSharp wants a property name not an index
1106       // CSharp callback can't return an object by value, it can only return a pointer
1107       // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
1108       auto name = (iter->second).name;
1109
1110       return *(iter->second.cSharpGetFunc(const_cast<BaseObject*>(object), name.GetCString()));
1111     }
1112     else
1113     {
1114       // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
1115       return iter->second.getFunc(const_cast<BaseObject*>(object), index);
1116     }
1117   }
1118
1119   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
1120   {
1121     // call base type recursively
1122     return mBaseType->GetProperty(object, index);
1123   }
1124
1125   DALI_LOG_ERROR("Property index %d not found\n", index);
1126   return Property::Value();
1127 }
1128
1129 Property::Value TypeInfo::GetProperty(const BaseObject* object, const std::string& name) const
1130 {
1131   RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(ConstString(name)));
1132
1133   if(iter != mRegisteredProperties.end())
1134   {
1135     if(mCSharpType) // using csharp property get which returns a pointer to a Property::Value
1136     {
1137       // CSharp wants a property name not an index
1138       // CSharp callback can't return an object by value, it can only return a pointer
1139       // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
1140       return *(iter->second.cSharpGetFunc(const_cast<BaseObject*>(object), name.c_str()));
1141     }
1142     else
1143     {
1144       // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
1145       return iter->second.getFunc(const_cast<BaseObject*>(object), iter->first);
1146     }
1147   }
1148
1149   if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
1150   {
1151     // call base type recursively
1152     return mBaseType->GetProperty(object, name);
1153   }
1154
1155   DALI_LOG_ERROR("Property %s not found", name.c_str());
1156   return Property::Value();
1157 }
1158
1159 } // namespace Internal
1160
1161 } // namespace Dali