Making DALi core internals typesafe using guaranteed types; uint8_t, uint32_t
[platform/core/uifw/dali-core.git] / dali / internal / event / common / type-info-impl.cpp
index b73d925..cb69d1f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -106,7 +106,14 @@ namespace Internal
 {
 
 TypeInfo::TypeInfo(const std::string &name, const std::string &baseTypeName, Dali::TypeInfo::CreateFunction creator)
-  : mTypeName(name), mBaseTypeName(baseTypeName), mCreate(creator)
+  : mTypeName(name), mBaseTypeName(baseTypeName), mCSharpType(false), mCreate(creator)
+{
+  DALI_ASSERT_ALWAYS(!name.empty() && "Type info construction must have a name");
+  DALI_ASSERT_ALWAYS(!baseTypeName.empty() && "Type info construction must have a base type name");
+}
+
+TypeInfo::TypeInfo(const std::string &name, const std::string &baseTypeName, Dali::CSharpTypeInfo::CreateFunction creator)
+  : mTypeName(name), mBaseTypeName(baseTypeName), mCSharpType(true), mCSharpCreate(creator)
 {
   DALI_ASSERT_ALWAYS(!name.empty() && "Type info construction must have a name");
   DALI_ASSERT_ALWAYS(!baseTypeName.empty() && "Type info construction must have a base type name");
@@ -122,7 +129,16 @@ BaseHandle TypeInfo::CreateInstance() const
 
   if(mCreate)
   {
-    ret = mCreate();
+    if ( mCSharpType )
+    {
+      // CSharp currently only registers one create function for all custom controls
+      // it uses the type name to decide which one to create
+      ret = *mCSharpCreate( mTypeName.c_str() );
+    }
+    else
+    {
+      ret = mCreate();
+    }
 
     if ( ret )
     {
@@ -301,14 +317,34 @@ void TypeInfo::GetPropertyIndices( Property::IndexContainer& indices ) const
     baseImpl.GetPropertyIndices( indices );
   }
 
-  if ( ! mRegisteredProperties.empty() )
+  AppendProperties( indices, mRegisteredProperties );
+}
+
+void TypeInfo::GetChildPropertyIndices( Property::IndexContainer& indices ) const
+{
+  Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
+  if ( base )
+  {
+    const TypeInfo& baseImpl( GetImplementation( base ) );
+    baseImpl.GetChildPropertyIndices( indices );
+  }
+
+  AppendProperties( indices, mRegisteredChildProperties );
+}
+
+/**
+ * Append the indices in RegisteredProperties to the given index container.
+ */
+void TypeInfo::AppendProperties( Dali::Property::IndexContainer& indices,
+                                 const TypeInfo::RegisteredPropertyContainer& registeredProperties ) const
+{
+  if ( ! registeredProperties.empty() )
   {
-    indices.Reserve( indices.Size() + mRegisteredProperties.size() );
+    indices.Reserve( indices.Size() + registeredProperties.size() );
 
-    const RegisteredPropertyContainer::const_iterator endIter = mRegisteredProperties.end();
-    for ( RegisteredPropertyContainer::const_iterator iter = mRegisteredProperties.begin(); iter != endIter; ++iter )
+    for( auto&& elem : registeredProperties )
     {
-      indices.PushBack( iter->first );
+      indices.PushBack( elem.first );
     }
   }
 }
@@ -349,7 +385,7 @@ void TypeInfo::AddActionFunction( const std::string &actionName, Dali::TypeInfo:
     }
     else
     {
-      DALI_LOG_WARNING("Action already exists in TypeRegistry Type", actionName.c_str());
+      DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str());
     }
   }
 }
@@ -371,7 +407,7 @@ void TypeInfo::AddConnectorFunction( const std::string& signalName, Dali::TypeIn
     }
     else
     {
-      DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function", signalName.c_str());
+      DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str());
     }
   }
 }
@@ -400,6 +436,33 @@ void TypeInfo::AddProperty( const std::string& name, Property::Index index, Prop
   }
 }
 
+void TypeInfo::AddProperty( const std::string& name, Property::Index index, Property::Type type, Dali::CSharpTypeInfo::SetPropertyFunction setFunc, Dali::CSharpTypeInfo::GetPropertyFunction getFunc)
+{
+
+  // The setter can be empty as a property can be read-only.
+
+  if ( NULL == getFunc )
+  {
+    DALI_ASSERT_ALWAYS( ! "GetProperty Function is empty" );
+  }
+  else
+  {
+    RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
+                                                          PairFinder< Property::Index, RegisteredPropertyPair>(index) );
+
+    if ( iter == mRegisteredProperties.end() )
+    {
+      mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, setFunc, getFunc, name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
+    }
+    else
+    {
+      DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
+    }
+  }
+
+}
+
+
 void TypeInfo::AddAnimatableProperty( const std::string& name, Property::Index index, Property::Type type )
 {
   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
@@ -407,7 +470,23 @@ void TypeInfo::AddAnimatableProperty( const std::string& name, Property::Index i
 
   if ( iter == mRegisteredProperties.end() )
   {
-    mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, NULL, NULL, name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
+    mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
+  }
+}
+
+void TypeInfo::AddAnimatableProperty( const std::string& name, Property::Index index, const Property::Value& defaultValue )
+{
+  RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
+                                                        PairFinder< Property::Index, RegisteredPropertyPair>(index) );
+
+  if ( iter == mRegisteredProperties.end() )
+  {
+    mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( defaultValue.GetType(), name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
+    mPropertyDefaultValues.push_back( PropertyDefaultValuePair( index, defaultValue ) );
   }
   else
   {
@@ -432,7 +511,7 @@ void TypeInfo::AddAnimatablePropertyComponent( const std::string& name, Property
 
     if ( iter == mRegisteredProperties.end() )
     {
-      mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, NULL, NULL, name, baseIndex, componentIndex ) ) );
+      mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, name, baseIndex, componentIndex ) ) );
       success = true;
     }
   }
@@ -440,15 +519,30 @@ void TypeInfo::AddAnimatablePropertyComponent( const std::string& name, Property
   DALI_ASSERT_ALWAYS( success && "Property component already registered" );
 }
 
-size_t TypeInfo::GetPropertyCount() const
+void TypeInfo::AddChildProperty( const std::string& name, Property::Index index, Property::Type type )
 {
-  size_t count( mRegisteredProperties.size() );
+  RegisteredPropertyContainer::iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
+                                                        PairFinder< Property::Index, RegisteredPropertyPair>(index) );
+
+  if ( iter == mRegisteredChildProperties.end() )
+  {
+    mRegisteredChildProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
+  }
+}
+
+uint32_t TypeInfo::GetPropertyCount() const
+{
+  uint32_t count = static_cast<uint32_t>( mRegisteredProperties.size() );
 
   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
   while ( base )
   {
     const TypeInfo& baseImpl( GetImplementation(base) );
-    count += baseImpl.mRegisteredProperties.size();
+    count += static_cast<uint32_t>( baseImpl.mRegisteredProperties.size() );
     base = TypeRegistry::Get()->GetTypeInfo( baseImpl.mBaseTypeName );
   }
 
@@ -525,6 +619,79 @@ int TypeInfo::GetComponentIndex( Property::Index index ) const
   return componentIndex;
 }
 
+Property::Index TypeInfo::GetChildPropertyIndex( const std::string& name ) const
+{
+  Property::Index index = Property::INVALID_INDEX;
+
+  // Slow but should not be done that often
+  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
+                                                          PropertyNameFinder< RegisteredPropertyPair >( name ) );
+
+  if ( iter != mRegisteredChildProperties.end() )
+  {
+    index = iter->first;
+  }
+  else
+  {
+    Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
+    if ( base )
+    {
+      index = GetImplementation(base).GetChildPropertyIndex( name );
+    }
+  }
+
+  return index;
+}
+
+const std::string& TypeInfo::GetChildPropertyName( Property::Index index ) const
+{
+  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
+                                                          PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
+
+  if ( iter != mRegisteredChildProperties.end() )
+  {
+    return iter->second.name;
+  }
+
+  Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
+  if ( base )
+  {
+    return GetImplementation(base).GetChildPropertyName( index );
+  }
+
+  DALI_LOG_WARNING("Cannot find property index");
+
+  static std::string emptyString;
+  return emptyString;
+}
+
+Property::Type TypeInfo::GetChildPropertyType( Property::Index index ) const
+{
+  Property::Type type( Property::NONE );
+
+  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(),
+                                                          PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
+
+  if ( iter != mRegisteredChildProperties.end() )
+  {
+    type = iter->second.type;
+  }
+  else
+  {
+    Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
+    if ( base )
+    {
+      type = GetImplementation(base).GetChildPropertyType( index );
+    }
+    else
+    {
+      DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
+    }
+  }
+
+  return type;
+}
+
 bool TypeInfo::IsPropertyWritable( Property::Index index ) const
 {
   bool writable( false );
@@ -568,7 +735,15 @@ Property::Type TypeInfo::GetPropertyType( Property::Index index ) const
 
   if ( iter != mRegisteredProperties.end() )
   {
-    type = iter->second.type;
+    if( iter->second.componentIndex == Property::INVALID_COMPONENT_INDEX )
+    {
+      type = iter->second.type;
+    }
+    else
+    {
+      // If component index is set, then we should return FLOAT
+      type = Property::FLOAT;
+    }
   }
   else
   {
@@ -586,6 +761,20 @@ Property::Type TypeInfo::GetPropertyType( Property::Index index ) const
   return type;
 }
 
+Property::Value TypeInfo::GetPropertyDefaultValue( Property::Index index ) const
+{
+  PropertyDefaultValueContainer::const_iterator iter = find_if( mPropertyDefaultValues.begin(), mPropertyDefaultValues.end(),
+                                                    PairFinder< Property::Index, PropertyDefaultValuePair >( index ) );
+  if( iter !=  mPropertyDefaultValues.end() )
+  {
+    return iter->second;
+  }
+  else
+  {
+    return Property::Value( GetPropertyType( index ) );
+  }
+}
+
 void TypeInfo::SetProperty( BaseObject *object, Property::Index index, const Property::Value& value ) const
 {
   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
@@ -594,7 +783,17 @@ void TypeInfo::SetProperty( BaseObject *object, Property::Index index, const Pro
   {
     if( iter->second.setFunc )
     {
-      iter->second.setFunc( object, index, value );
+      if( mCSharpType )
+      {
+        // CSharp wants a property name not an index
+        const std::string& name = (iter->second).name;
+
+        iter->second.cSharpSetFunc( object,name.c_str(), const_cast< Property::Value* >(&value) );
+      }
+      else
+      {
+        iter->second.setFunc( object, index, value );
+      }
     }
   }
   else
@@ -618,7 +817,16 @@ void TypeInfo::SetProperty( BaseObject *object, const std::string& name, const P
   if ( iter != mRegisteredProperties.end() )
   {
     DALI_ASSERT_ALWAYS( iter->second.setFunc && "Trying to write to a read-only property" );
-    iter->second.setFunc( object, iter->first, value );
+
+    if( mCSharpType )
+    {
+      // CSharp wants a property name not an index
+      iter->second.cSharpSetFunc( object,name.c_str(), const_cast< Property::Value* >(&value ));
+    }
+    else
+    {
+      iter->second.setFunc( object, iter->first, value );
+    }
   }
   else
   {
@@ -640,8 +848,21 @@ Property::Value TypeInfo::GetProperty( const BaseObject *object, Property::Index
                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
   if( iter != mRegisteredProperties.end() )
   {
-    // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
-    return iter->second.getFunc( const_cast< BaseObject* >( object ), index );
+    if( mCSharpType ) // using csharp property get which returns a pointer to a Property::Value
+    {
+      // CSharp wants a property name not an index
+      // CSharp callback can't return an object by value, it can only return a pointer
+      // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
+      const std::string& name = (iter->second).name;
+
+      return *( iter->second.cSharpGetFunc( const_cast< BaseObject* >( object ), name.c_str()) );
+
+    }
+    else
+    {
+      // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
+      return iter->second.getFunc( const_cast< BaseObject* >( object ), index );
+    }
   }
 
   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
@@ -656,11 +877,25 @@ Property::Value TypeInfo::GetProperty( const BaseObject *object, Property::Index
 Property::Value TypeInfo::GetProperty( const BaseObject *object, const std::string& name ) const
 {
   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                          PropertyNameFinder< RegisteredPropertyPair >( name ) );
+                                                            PropertyNameFinder< RegisteredPropertyPair >( name ) );
+
+
+
   if( iter != mRegisteredProperties.end() )
   {
-    // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
-    return iter->second.getFunc( const_cast< BaseObject* >( object ), iter->first );
+    if( mCSharpType ) // using csharp property get which returns a pointer to a Property::Value
+    {
+       // CSharp wants a property name not an index
+       // CSharp callback can't return an object by value, it can only return a pointer
+       // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
+       return *( iter->second.cSharpGetFunc( const_cast< BaseObject* >( object ), name.c_str() ));
+
+    }
+    else
+    {
+      // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
+      return iter->second.getFunc( const_cast< BaseObject* >( object ), iter->first );
+    }
   }
 
   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );