Builder templated constant expansion
authorLee Morgan <Lee.morgan@partner.samsung.com>
Fri, 4 Apr 2014 14:01:53 +0000 (15:01 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 16 Apr 2014 15:45:43 +0000 (16:45 +0100)
[Issue#]   N/A
[Problem]  Template/constant Expansion needed (Image paths etc).
[Cause]    N/A.
[Solution] Added Replacement expansion helper class.

Change-Id: Ib02024c4e7042180df55dec639daacad2c61b2fd
Signed-off-by: Lee Morgan <Lee.morgan@partner.samsung.com>
12 files changed:
automated-tests/dali-test-suite/builder/utc-Dali-Builder.cpp
dali-toolkit/internal/builder/builder-animations.cpp
dali-toolkit/internal/builder/builder-impl.cpp [changed mode: 0755->0644]
dali-toolkit/internal/builder/builder-impl.h
dali-toolkit/internal/builder/builder-set-property.cpp
dali-toolkit/internal/builder/builder-signals.cpp
dali-toolkit/internal/builder/json-parser-state.cpp
dali-toolkit/internal/builder/replacement.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/replacement.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/public-api/builder/builder.cpp
dali-toolkit/public-api/builder/builder.h

index 926e85f..15c93a4 100644 (file)
@@ -167,6 +167,47 @@ namespace
 }                                                                                         \
 ");
 
+  std::string JSON_CONSTANTS("\
+{                                                                                         \
+    'constants':                                                                          \
+    {                                                                                     \
+      'HELLO':'Hello World',                                                              \
+      'HELLO2':'Hello {WORLD}'                                                            \
+    },                                                                                    \
+    'styles':                                                                             \
+    {                                                                                     \
+        'basic-text': {                                                                   \
+                    'type':'TextActor',                                                   \
+                    'text':'{HELLO2}'                                                     \
+                   }                                                                      \
+    },                                                                                    \
+    'animations':                                                                         \
+    {                                                                                     \
+      'rotate':                                                                           \
+      {                                                                                   \
+        'duration': 10,                                                                   \
+        'properties':                                                                     \
+        [                                                                                 \
+          {                                                                               \
+            'actor':'{ACTOR}',                                                            \
+            'property':'rotation',                                                        \
+            'value':[0, 3, 0, 0],                                                         \
+            'alpha-function': 'EASE_IN_OUT',                                              \
+            'time-period': {'delay': 0, 'duration': 3 }                                   \
+          }                                                                               \
+        ]                                                                                 \
+      }                                                                                   \
+    },                                                                                    \
+    'stage':                                                                              \
+    [                                                                                     \
+        {'name':'txt1',                                                                   \
+         'type':'TextActor',                                                              \
+         'text':'{HELLO}'                                                                \
+        }                                                                                 \
+    ]                                                                                     \
+}                                                                                         \
+");
+
 
   std::string ReplaceQuotes(const std::string &in_s)
   {
@@ -186,6 +227,7 @@ extern "C" {
   void (*tet_cleanup)() = Cleanup;
 }
 
+static void UtcDaliBuilderConstants();
 static void UtcDaliBuilderTextActorCreateFromStyle();
 static void UtcDaliBuilderTextActorCreateAnimation();
 static void UtcDaliBuilderTextActorApplyFromStyle();
@@ -199,20 +241,20 @@ enum {
   NEGATIVE_TC_IDX,
 };
 
-// Add test functionality for all APIs in the class (Positive and Negative)
+#define MAX_NUMBER_OF_TESTS 10000
 extern "C" {
-  struct tet_testlist tet_testlist[] = {
-    { UtcDaliBuilderTextActorCreateFromStyle, POSITIVE_TC_IDX },
-    { UtcDaliBuilderTextActorCreateAnimation, POSITIVE_TC_IDX },
-    { UtcDaliBuilderTextActorApplyFromStyle, POSITIVE_TC_IDX },
-    { UtcDaliBuilderStyles, POSITIVE_TC_IDX },
-    { UtcDaliBuilderAddActorsOther, POSITIVE_TC_IDX },
-    { UtcDaliBuilderAddActors, POSITIVE_TC_IDX },
-    { UtcDaliBuilderSetProperty, POSITIVE_TC_IDX },
-    { NULL, 0 }
-  };
+  struct tet_testlist tet_testlist[MAX_NUMBER_OF_TESTS];
 }
 
+TEST_FUNCTION( UtcDaliBuilderConstants                     , POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliBuilderTextActorCreateFromStyle      , POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliBuilderTextActorCreateAnimation      , POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliBuilderTextActorApplyFromStyle       , POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliBuilderStyles                        , POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliBuilderAddActorsOther                , POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliBuilderAddActors                     , POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliBuilderSetProperty                   , POSITIVE_TC_IDX );
+
 // Called only once before first test is run.
 static void Startup()
 {
@@ -223,6 +265,59 @@ static void Cleanup()
 {
 }
 
+static void UtcDaliBuilderConstants()
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" UtcDaliBuilderConstants");
+
+  Builder builder = Builder::New();
+
+  PropertyValueMap userMap;
+  userMap["WORLD"] = "World";
+  builder.AddConstants(userMap);
+
+  builder.LoadFromString( ReplaceQuotes(JSON_CONSTANTS) );
+
+  // constants in json
+  Layer layer = stage.GetRootLayer();
+  size_t count = layer.GetChildCount();
+
+  builder.AddActors( layer );
+  DALI_TEST_CHECK( layer.GetChildCount() == count + 1 );
+
+  TextActor actor = TextActor::DownCast( layer.GetChildAt( count ) );
+  DALI_TEST_CHECK( actor );
+  DALI_TEST_CHECK( actor.GetText() == std::string("Hello World") );
+
+  // global constants
+  PropertyValueMap map;
+  map["HELLO2"] = "Hi";
+
+  builder.AddConstants( map );
+
+  actor = TextActor::DownCast( builder.CreateFromStyle("basic-text") );
+  DALI_TEST_CHECK( actor );
+  DALI_TEST_CHECK( actor.GetText() == std::string("Hi") );
+
+  // user overriding
+  userMap["HELLO2"] = "Hello Dali";
+  actor = TextActor::DownCast( builder.CreateFromStyle("basic-text", userMap) );
+  DALI_TEST_CHECK( actor );
+  DALI_TEST_CHECK( actor.GetText() == std::string("Hello Dali") );
+
+  // animation constants
+  actor = TextActor::DownCast( layer.GetChildAt( count ) );
+  actor.SetName("rotate-me");
+  userMap["ACTOR"] = actor.GetName();
+
+  Animation anim = builder.CreateAnimation("rotate", userMap);
+  DALI_TEST_CHECK( anim );
+  DALI_TEST_CHECK( 10.0f == anim.GetDuration() );
+
+}
+
 static void UtcDaliBuilderTextActorCreateFromStyle()
 {
   ToolkitTestApplication application;
index b8ea43e..82a0669 100644 (file)
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/builder/builder-impl.h>
 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+#include <dali-toolkit/internal/builder/replacement.h>
 
 namespace // unnamed namespace
 {
 
 using namespace Dali;
 
-TimePeriod GetTimePeriod( const TreeNode& child )
+TimePeriod GetTimePeriod( const TreeNode& child, const Toolkit::Internal::Replacement& constant )
 {
-  OptionalFloat delay      = IsFloat( IsChild(child, "delay" ) );
-  OptionalFloat duration   = IsFloat( IsChild(child, "duration" ) );
+  OptionalFloat delay      = constant.IsFloat( IsChild(child, "delay" ) );
+  OptionalFloat duration   = constant.IsFloat( IsChild(child, "duration" ) );
   DALI_ASSERT_ALWAYS( duration && "Time period must have at least a duration" );
 
   if( delay )
@@ -148,18 +149,32 @@ namespace Toolkit
 namespace Internal
 {
 
-Animation CreateAnimation( const TreeNode& child )
+Animation CreateAnimation( const TreeNode& child, const Replacement& constant, Dali::Actor searchRoot )
 {
   float durationSum = 0.f;
 
+  Dali::Actor searchActor = searchRoot ? searchRoot : Dali::Stage::GetCurrent().GetRootLayer();
+
   Animation animation( Animation::New( 0.f ) );
 
-  if( OptionalBoolean looping = IsBoolean(  IsChild(child, "loop" ) ) )
+  // duration needs to be set before AnimateTo calls for correct operation when AnimateTo has no "time-period".
+  OptionalFloat duration = constant.IsFloat( IsChild(child, "duration" ) );
+
+  if( duration )
+  {
+    animation.SetDuration( *duration );
+  }
+  else
+  {
+    animation.SetDuration( durationSum );
+  }
+
+  if( OptionalBoolean looping = constant.IsBoolean(  IsChild(child, "loop" ) ) )
   {
     animation.SetLooping( *looping );
   }
 
-  if( OptionalString endAction = IsString(  IsChild(child, "end-action" ) ) )
+  if( OptionalString endAction = constant.IsString(  IsChild(child, "end-action" ) ) )
   {
     if("BAKE" == *endAction)
     {
@@ -171,7 +186,7 @@ Animation CreateAnimation( const TreeNode& child )
     }
   }
 
-  if( OptionalString endAction = IsString(  IsChild(child, "destroy-action" ) ) )
+  if( OptionalString endAction = constant.IsString(  IsChild(child, "destroy-action" ) ) )
   {
     if("BAKE" == *endAction)
     {
@@ -191,12 +206,12 @@ Animation CreateAnimation( const TreeNode& child )
     {
       const TreeNode::KeyNodePair& pKeyChild = *iter;
 
-      OptionalString actorName( IsString( pKeyChild.second, "actor" ) );
-      OptionalString property(  IsString( pKeyChild.second, "property" ) );
+      OptionalString actorName( constant.IsString( IsChild(pKeyChild.second, "actor" ) ) );
+      OptionalString property(  constant.IsString( IsChild(pKeyChild.second, "property" ) ) );
       DALI_ASSERT_ALWAYS( actorName && "Animation must specify actor name" );
       DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
 
-      Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName( *actorName );
+      Actor targetActor = searchActor.FindChildByName( *actorName );
       DALI_ASSERT_ALWAYS( targetActor && "Actor must exist for property" );
 
       Property::Index idx( targetActor.GetPropertyIndex( *property ) );
@@ -239,14 +254,16 @@ Animation CreateAnimation( const TreeNode& child )
       AlphaFunction alphaFunction( AlphaFunctions::Default );
       TimePeriod timePeriod( 0.f );
 
-      if( OptionalChild timeChild = IsChild( pKeyChild.second, "time-period" ) )
+      OptionalChild timeChild = IsChild( pKeyChild.second, "time-period" );
+
+      if( timeChild )
       {
-        timePeriod = GetTimePeriod( *timeChild );
+        timePeriod = GetTimePeriod( *timeChild, constant );
       }
 
       durationSum = std::max( durationSum, timePeriod.delaySeconds + timePeriod.durationSeconds );
 
-      if( OptionalString alphaChild = IsString( pKeyChild.second, "alpha-function" ) )
+      if( OptionalString alphaChild = constant.IsString( IsChild(pKeyChild.second, "alpha-function" ) ) )
       {
         alphaFunction = GetAlphaFunction( *alphaChild );
       }
@@ -260,7 +277,7 @@ Animation CreateAnimation( const TreeNode& child )
         {
           const TreeNode::KeyNodePair& kfKeyChild = *iter;
 
-          OptionalFloat kfProgress = IsFloat( kfKeyChild.second, "progress" );
+          OptionalFloat kfProgress = constant.IsFloat( IsChild(kfKeyChild.second, "progress" ) );
           DALI_ASSERT_ALWAYS( kfProgress && "Key frame entry must have 'progress'" );
 
           OptionalChild kfValue = IsChild( kfKeyChild.second, "value" );
@@ -280,7 +297,7 @@ Animation CreateAnimation( const TreeNode& child )
           }
 
           AlphaFunction kfAlphaFunction( AlphaFunctions::Default );
-          if( OptionalString alphaFuncStr = IsString( pKeyChild.second, "alpha-function") )
+          if( OptionalString alphaFuncStr = constant.IsString( IsChild(pKeyChild.second, "alpha-function") ) )
           {
             kfAlphaFunction = GetAlphaFunction( *alphaFuncStr );
           }
@@ -288,7 +305,14 @@ Animation CreateAnimation( const TreeNode& child )
           keyframes.Add( *kfProgress, propValue, kfAlphaFunction );
         }
 
-        animation.AnimateBetween( prop, keyframes, alphaFunction, timePeriod );
+        if( timeChild )
+        {
+          animation.AnimateBetween( prop, keyframes, alphaFunction, timePeriod );
+        }
+        else
+        {
+          animation.AnimateBetween( prop, keyframes, alphaFunction );
+        }
       }
       else
       {
@@ -304,30 +328,41 @@ Animation CreateAnimation( const TreeNode& child )
           throw;
         }
 
-        if( OptionalBoolean relative = IsBoolean(pKeyChild.second, "relative") )
+        if( OptionalBoolean relative = constant.IsBoolean( IsChild(pKeyChild.second, "relative") ) )
         {
-          animation.AnimateBy( prop, propValue, alphaFunction, timePeriod );
+          if( timeChild )
+          {
+            animation.AnimateBy( prop, propValue, alphaFunction, timePeriod );
+          }
+          else
+          {
+            animation.AnimateBy( prop, propValue, alphaFunction );
+          }
         }
         else
         {
-          animation.AnimateTo( prop, propValue, alphaFunction, timePeriod );
+          if( timeChild )
+          {
+            animation.AnimateTo( prop, propValue, alphaFunction, timePeriod );
+          }
+          else
+          {
+            animation.AnimateTo( prop, propValue, alphaFunction );
+          }
         }
       }
     }
   }
 
-  if( OptionalFloat duration = IsFloat( child, "duration" ) )
-  {
-    animation.SetDuration( *duration );
-  }
-  else
-  {
-    animation.SetDuration( durationSum );
-  }
-
   return animation;
 }
 
+Animation CreateAnimation( const TreeNode& child )
+{
+  Replacement replacement;
+  return CreateAnimation( child, replacement, Stage::GetCurrent().GetRootLayer() );
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
old mode 100755 (executable)
new mode 100644 (file)
index 83572ec..a301570
@@ -29,6 +29,7 @@
 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
 #include <dali-toolkit/internal/builder/builder-filesystem.h>
 #include <dali-toolkit/internal/builder/builder-declarations.h>
+#include <dali-toolkit/internal/builder/replacement.h>
 
 namespace Dali
 {
@@ -38,9 +39,13 @@ namespace Toolkit
 
 namespace Internal
 {
+class Replacement;
 
-extern Animation CreateAnimation(const TreeNode& child);
+extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot );
+extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
+extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value, const Replacement& replacements );
 extern bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value );
+extern bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value, const Replacement& replacements );
 extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor);
 extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor);
 extern Actor SetupActor( const TreeNode& node, Actor& actor );
@@ -55,10 +60,118 @@ namespace
 
 typedef std::vector<const TreeNode*> TreeNodeList;
 
+template <typename T>
+std::string ToString(const T& value)
+{
+  std::stringstream ss;
+  ss << value;
+  return ss.str();
+}
+
+template <>
+std::string ToString(const Rect<int>& value)
+{
+  std::stringstream ss;
+  ss << value.x << "," << value.y << "," << value.width << "," << value.height;
+  return ss.str();
+}
+
+
+std::string PropertyValueToString( const Property::Value& value )
+{
+  std::string ret;
+
+  switch( value.GetType() )
+  {
+    case Property::NONE:
+    {
+      ret = "NONE";
+      break;
+    }            ///< No type
+    case Property::BOOLEAN:
+    {
+      ret = value.Get<bool>() ? "True" : "False";
+      break;
+    }
+    case Property::FLOAT:
+    {
+
+      ret = ToString( value.Get<float>() );
+      break;
+    }
+    case Property::INTEGER:
+    {
+      ret = ToString( value.Get<int>() );
+      break;
+    }
+    case Property::UNSIGNED_INTEGER:
+    {
+      ret = ToString( value.Get<unsigned int>() );
+      break;
+    }
+    case Property::VECTOR2:
+    {
+      ret = ToString( value.Get<Vector2>() );
+      break;
+    }
+    case Property::VECTOR3:
+    {
+      ret = ToString( value.Get<Vector3>() );
+      break;
+    }
+    case Property::VECTOR4:
+    {
+      ret = ToString( value.Get<Vector4>() );
+      break;
+    }
+    case Property::MATRIX3:
+    {
+      ret = ToString( value.Get<Matrix3>() );
+      break;
+    }
+    case Property::MATRIX:
+    {
+      ret = ToString( value.Get<Matrix>() );
+      break;
+    }
+    case Property::RECTANGLE:
+    {
+      ret = ToString( value.Get< Rect<int> >() );
+      break;
+    }
+    case Property::ROTATION:
+    {
+      break;
+    }
+    case Property::STRING:
+    {
+      ret = value.Get<std::string>();
+      break;
+    }
+    case Property::ARRAY:
+    {
+      ret = std::string("Array Size=") + ToString( value.Get<Property::Array>().size() );
+      break;
+    }
+    case Property::MAP:
+    {
+      ret = std::string("Map Size=") + ToString( value.Get<Property::Map>().size() );
+      break;
+    }
+    case Property::TYPE_COUNT:
+    {
+      ret = "";
+      break;
+    }
+  }
+
+  return ret;
+}
+
 /*
  * Sets the handle properties found in the tree node
  */
-void SetProperties( const TreeNode& node, Handle& handle, Builder& builder )
+void SetProperties( const TreeNode& node, Handle& handle, Builder& builder, const Replacement& constant )
 {
   if( handle )
   {
@@ -83,9 +196,9 @@ void SetProperties( const TreeNode& node, Handle& handle, Builder& builder )
           ImageActor imageActor = ImageActor::DownCast(handle);
           if(imageActor)
           {
-            if( OptionalString s = IsString( keyChild.second ) )
+            if( OptionalString s = constant.IsString( keyChild.second ) )
             {
-              FrameBufferImage fb = builder.GetFrameBufferImage(*s);
+              FrameBufferImage fb = builder.GetFrameBufferImage(*s, constant);
               if(fb)
               {
                 imageActor.SetImage( fb );
@@ -99,10 +212,10 @@ void SetProperties( const TreeNode& node, Handle& handle, Builder& builder )
       if(key == "effect")
       {
         Actor actor = Actor::DownCast(handle);
-        OptionalString s = IsString( keyChild.second );
+        OptionalString s = constant.IsString( keyChild.second );
         if(actor && s)
         {
-          ShaderEffect e = builder.GetShaderEffect(*s);
+          ShaderEffect e = builder.GetShaderEffect(*s, constant);
           actor.SetShaderEffect(e);
         }
         else
@@ -120,7 +233,7 @@ void SetProperties( const TreeNode& node, Handle& handle, Builder& builder )
         Property::Type type = handle.GetPropertyType(index);
 
         Property::Value value;
-        if( !SetPropertyFromNode( keyChild.second, type, value ) )
+        if( !SetPropertyFromNode( keyChild.second, type, value, constant ) )
         {
           // verbose as this might not be a problem
           // eg parent-origin can be a string which is picked up later
@@ -128,7 +241,7 @@ void SetProperties( const TreeNode& node, Handle& handle, Builder& builder )
         }
         else
         {
-          DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d\n", key.c_str(), index, value.GetType());
+          DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() );
 
           handle.SetProperty( index, value );
         }
@@ -233,12 +346,15 @@ void CollectAllStyles( const OptionalChild& optionalStyles, const TreeNode& node
   }
 }
 
+} // namespace anon
+
 /*
  * Create a dali type from a node.
  * If parent given and an actor type was created then add it to the parent and
  * recursively add nodes children.
  */
-BaseHandle Create( ConnectionTracker* tracker, const OptionalChild& optionalStyles, const TreeNode& node, const TreeNode& root, Actor parent, Builder& builder )
+BaseHandle Builder::Create( const OptionalChild& optionalStyles, const TreeNode& node, const TreeNode& root, Actor parent,
+                            const Replacement& replacements )
 {
   BaseHandle baseHandle;
   TreeNodeList allStyles;
@@ -248,7 +364,7 @@ BaseHandle Create( ConnectionTracker* tracker, const OptionalChild& optionalStyl
 
   if(!typeInfo)
   {
-    DALI_SCRIPT_WARNING("Unable to create Dali type from node\n");
+    DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName());
   }
   else
   {
@@ -283,9 +399,47 @@ BaseHandle Create( ConnectionTracker* tracker, const OptionalChild& optionalStyl
 
       for(TreeNodeList::reverse_iterator iter = allStyles.rbegin(); iter != allStyles.rend(); ++iter)
       {
-        SetProperties( *(*iter), handle, builder );
+        if( (*iter)->GetType() == TreeNode::ARRAY )
+        {
+          // if its an array then its a list of styles to set to objects already in the hiearchy by name
+          if( actor )
+          {
+            const TreeNode& styleList = *(*iter);
+            for( TreeNode::ConstIterator iterSubStyle = styleList.CBegin(); iterSubStyle != styleList.CEnd(); ++iterSubStyle )
+            {
+              const TreeNode* nameNode = (*iterSubStyle).second.Find("name");
+              if( nameNode && nameNode->GetType() == TreeNode::STRING )
+              {
+                Dali::Actor found = actor.FindChildByName( nameNode->GetString() );
+                if( found )
+                {
+                  SetProperties( (*iterSubStyle).second, found, *this, replacements );
+                }
+                else
+                {
+                  DALI_SCRIPT_VERBOSE("Cannot find object '%s' in tree to style\n", nameNode->GetString());
+                }
+              }
+              else
+              {
+                DALI_SCRIPT_VERBOSE("Style name is not a string '%s' '%d'\n",
+                                    nameNode->GetString(), (*iterSubStyle).second.GetType());
+              }
+            }
+          }
+          else
+          {
+            DALI_SCRIPT_VERBOSE("Cannot apply style list to non actor\n");
+          }
+        }
+        else
+        {
+          DALI_ASSERT_DEBUG( (*iter)->GetType() == TreeNode::OBJECT );
+          // else it should be a map of properties
+          SetProperties( *(*iter), handle, *this, replacements  );
+        }
 
-        if( actor ) // if we created an actor
+        if( actor )
         {
           SetupActor( *(*iter), actor);
 
@@ -299,7 +453,7 @@ BaseHandle Create( ConnectionTracker* tracker, const OptionalChild& optionalStyl
           {
             for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter )
             {
-              Create( tracker, optionalStyles, (*iter).second, root, actor, builder );
+              Create( optionalStyles, (*iter).second, root, actor, replacements );
             }
           }
         }
@@ -308,8 +462,9 @@ BaseHandle Create( ConnectionTracker* tracker, const OptionalChild& optionalStyl
       if( actor )
       {
         // add signals first
-        SetupSignalAction( tracker, root, node, actor );
-        SetupPropertyNotification( tracker, root, node, actor );
+        SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor );
+
+        SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor );
 
         // then add to parent
         if( parent )
@@ -329,9 +484,6 @@ BaseHandle Create( ConnectionTracker* tracker, const OptionalChild& optionalStyl
 }
 
 
-} // namespace anon
-
-
 ActorContainer Builder::GetTopLevelActors() const
 {
   // deprecated function.
@@ -344,12 +496,12 @@ Animation Builder::GetAnimation( const std::string &name ) const
   return Animation();
 }
 
-void Builder::SetupTask( RenderTask& task, const TreeNode& node )
+void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant )
 {
   const Stage& stage = Stage::GetCurrent();
   Layer root  = stage.GetRootLayer();
 
-  if( OptionalString s = IsString( IsChild(node, "source-actor") ) )
+  if( OptionalString s = constant.IsString( IsChild(node, "source-actor") ) )
   {
     Actor actor = root.FindChildByName(*s);
     if(actor)
@@ -362,7 +514,7 @@ void Builder::SetupTask( RenderTask& task, const TreeNode& node )
     }
   }
 
-  if( OptionalString s = IsString( IsChild(node, "camera-actor") ) )
+  if( OptionalString s = constant.IsString( IsChild(node, "camera-actor") ) )
   {
     CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) );
     if(actor)
@@ -375,9 +527,9 @@ void Builder::SetupTask( RenderTask& task, const TreeNode& node )
     }
   }
 
-  if( OptionalString s = IsString( IsChild(node, "target-frame-buffer") ) )
+  if( OptionalString s = constant.IsString( IsChild(node, "target-frame-buffer") ) )
   {
-    FrameBufferImage fb = GetFrameBufferImage( *s );
+    FrameBufferImage fb = GetFrameBufferImage( *s, constant );
     if(fb)
     {
       task.SetTargetFrameBuffer( fb );
@@ -388,7 +540,7 @@ void Builder::SetupTask( RenderTask& task, const TreeNode& node )
     }
   }
 
-  if( OptionalString s = IsString( IsChild(node, "screen-to-frame-buffer-function") ) )
+  if( OptionalString s = constant.IsString( IsChild(node, "screen-to-frame-buffer-function") ) )
   {
     if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s)
     {
@@ -405,12 +557,14 @@ void Builder::SetupTask( RenderTask& task, const TreeNode& node )
   }
 
   // other setup is via the property system
-  SetProperties( node, task, *this ); // @ todo, remove 'source-actor', 'camera-actor'?
+  SetProperties( node, task, *this, constant  ); // @ todo, remove 'source-actor', 'camera-actor'?
 
 }
 
 void Builder::CreateRenderTask( const std::string &name )
 {
+  Replacement constant(mReplacementMap);
+
   const Stage& stage = Stage::GetCurrent();
 
   OptionalChild tasks = IsChild(*mParser.GetRoot(), "render-tasks");
@@ -439,20 +593,26 @@ void Builder::CreateRenderTask( const std::string &name )
       TreeNode::ConstIterator iter = (*renderTask).CBegin();
       task = list.GetTask( start - 1 );
 
-      SetupTask( task, (*iter).second );
+      SetupTask( task, (*iter).second, constant  );
 
       ++iter;
 
       for(; iter != (*renderTask).CEnd(); ++iter )
       {
         task = list.CreateTask();
-        SetupTask( task, (*iter).second );
+        SetupTask( task, (*iter).second, constant );
       }
     }
   }
 }
 
-ShaderEffect Builder::GetShaderEffect( const std::string &name )
+ShaderEffect Builder::GetShaderEffect( const std::string &name)
+{
+  Replacement constant;
+  return GetShaderEffect( name, constant );
+}
+
+ShaderEffect Builder::GetShaderEffect( const std::string &name, const Replacement& constant )
 {
   ShaderEffect ret;
 
@@ -468,7 +628,7 @@ ShaderEffect Builder::GetShaderEffect( const std::string &name )
       if( OptionalChild effect = IsChild( *effects, name ) )
       {
         Dali::Property::Value propertyMap(Property::MAP);
-        if( SetPropertyFromNode( *effect, Property::MAP, propertyMap ) )
+        if( SetPropertyFromNode( *effect, Property::MAP, propertyMap, constant ) )
         {
           ret = Dali::Scripting::NewShaderEffect( propertyMap );
           mShaderEffectLut[ name ] = ret;
@@ -482,6 +642,12 @@ ShaderEffect Builder::GetShaderEffect( const std::string &name )
 
 FrameBufferImage Builder::GetFrameBufferImage( const std::string &name )
 {
+  Replacement constant;
+  return GetFrameBufferImage(name, constant);
+}
+
+FrameBufferImage Builder::GetFrameBufferImage( const std::string &name, const Replacement& constant )
+{
   FrameBufferImage ret;
 
   ImageLut::const_iterator iter( mFrameBufferImageLut.find( name ) );
@@ -496,7 +662,7 @@ FrameBufferImage Builder::GetFrameBufferImage( const std::string &name )
       if( OptionalChild image = IsChild( *images, name ) )
       {
         Dali::Property::Value propertyMap(Property::MAP);
-        if( SetPropertyFromNode( *image, Property::MAP, propertyMap ) )
+        if( SetPropertyFromNode( *image, Property::MAP, propertyMap, constant ) )
         {
           propertyMap.SetValue("type", Property::Value(std::string("FrameBufferImage")));
           ret = Dali::Scripting::NewImage( propertyMap );
@@ -542,6 +708,9 @@ void Builder::AddActors( Actor toActor )
 
 void Builder::AddActors( const std::string &sectionName, Actor toActor )
 {
+  PropertyValueMap overrideMap;
+  Replacement replacements(overrideMap, mReplacementMap);
+
   OptionalChild addToStage = IsChild(*mParser.GetRoot(), sectionName);
 
   if( addToStage )
@@ -551,7 +720,7 @@ void Builder::AddActors( const std::string &sectionName, Actor toActor )
     for( TreeNode::ConstIterator iter = (*addToStage).CBegin(); iter != (*addToStage).CEnd(); ++iter )
     {
       // empty actor adds directly to the stage
-      BaseHandle baseHandle = Create( mSlotDelegate.GetConnectionTracker(), styles, (*iter).second, *mParser.GetRoot(), Actor(), *this);
+      BaseHandle baseHandle = Create( styles, (*iter).second, *mParser.GetRoot(), Actor(), replacements );
       Actor actor = Actor::DownCast(baseHandle);
       if(actor)
       {
@@ -571,11 +740,10 @@ void Builder::AddActors( const std::string &sectionName, Actor toActor )
         }
       }
     }
-
   }
 }
 
-Animation Builder::CreateAnimation( const std::string& animationName )
+Animation Builder::CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor searchRoot )
 {
   Animation anim;
 
@@ -583,17 +751,46 @@ Animation Builder::CreateAnimation( const std::string& animationName )
   {
     if( OptionalChild animation = IsChild(*animations, animationName) )
     {
-      anim = Dali::Toolkit::Internal::CreateAnimation( *animation );
+      anim = Dali::Toolkit::Internal::CreateAnimation( *animation, replacement, Stage::GetCurrent().GetRootLayer() );
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed\n", animationName.c_str() );
     }
   }
   else
   {
-    DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed\n", animationName.c_str() );
+    DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed (no animation section)\n", animationName.c_str() );
   }
 
   return anim;
 }
 
+Animation Builder::CreateAnimation( const std::string& animationName, const PropertyValueMap& map, Dali::Actor searchRoot )
+{
+  Replacement replacement(map, mReplacementMap);
+  return CreateAnimation( animationName, replacement, searchRoot);
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, const PropertyValueMap& map )
+{
+  Replacement replacement(map, mReplacementMap);
+  return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() );
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor searchRoot )
+{
+  Replacement replacement( mReplacementMap );
+
+  return CreateAnimation( animationName, replacement, searchRoot );
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName )
+{
+  Replacement replacement( mReplacementMap );
+  return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() );
+}
+
 void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format )
 {
   DALI_ASSERT_ALWAYS( format == Dali::Toolkit::Builder::JSON && "Currently only JSON is supported" );
@@ -610,10 +807,81 @@ void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::U
 
   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
 
+  // load constant map (allows the user to override the constants in the json after loading)
+  LoadConstants();
+
+}
+
+void Builder::AddConstants( const PropertyValueMap& map )
+{
+  for(PropertyValueMap::const_iterator iter = map.begin(); iter != map.end(); ++iter)
+  {
+    mReplacementMap[ (*iter).first ] = (*iter).second;
+  }
+}
+
+void Builder::LoadConstants()
+{
+  Replacement replacer(mReplacementMap);
+
+  if( OptionalChild constants = IsChild(*mParser.GetRoot(), "constants") )
+  {
+    for(TreeNode::ConstIterator iter = (*constants).CBegin();
+        iter != (*constants).CEnd(); ++iter)
+    {
+      Dali::Property::Value property;
+      if( (*iter).second.GetName() )
+      {
+#if defined(DEBUG_ENABLED)
+        DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName());
+#endif
+        if( SetPropertyFromNode( (*iter).second, property, replacer ) )
+        {
+          mReplacementMap[ (*iter).second.GetName() ] = property;
+        }
+        else
+        {
+          DALI_SCRIPT_WARNING("Cannot convert property for constant %s\n",
+                              (*iter).second.GetName() == NULL ? "no name?" : (*iter).second.GetName());
+        }
+      }
+    }
+  }
+
+#if defined(DEBUG_ENABLED)
+  PropertyValueMap::const_iterator iter = mReplacementMap.find( "CONFIG_SCRIPT_LOG_LEVEL" );
+  if( iter != mReplacementMap.end() && (*iter).second.GetType() == Property::STRING )
+  {
+    std::string logLevel( (*iter).second.Get< std::string >() );
+    if( logLevel == "NoLogging" )
+    {
+      gFilterScript->SetLogLevel( Integration::Log::NoLogging );
+    }
+    else if( logLevel == "Concise" )
+    {
+      gFilterScript->SetLogLevel( Integration::Log::Concise );
+    }
+    else if( logLevel == "General" )
+    {
+      gFilterScript->SetLogLevel( Integration::Log::General );
+    }
+    else if( logLevel == "Verbose" )
+    {
+      gFilterScript->SetLogLevel( Integration::Log::Verbose );
+    }
+  }
+#endif
+
 }
 
 void Builder::ApplyStyle( const std::string& styleName, Handle& handle )
 {
+  Replacement replacer;
+  ApplyStyle( styleName, handle, replacer );
+}
+
+void Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement )
+{
   OptionalChild styles = IsChild(*mParser.GetRoot(), "styles");
 
   if( styles )
@@ -627,7 +895,44 @@ void Builder::ApplyStyle( const std::string& styleName, Handle& handle )
 
       for(TreeNodeList::reverse_iterator iter = allStyles.rbegin(); iter != allStyles.rend(); ++iter)
       {
-        SetProperties( *style, handle, *this );
+        if( (*iter)->GetType() == TreeNode::ARRAY )
+        {
+          // if its an array then its a list of styles to set to objects already in the hiearchy by name
+          if( Dali::Actor actor = Dali::Actor::DownCast( handle ) )
+          {
+            const TreeNode& styleList = *(*iter);
+            for( TreeNode::ConstIterator iterSubStyle = styleList.CBegin(); iterSubStyle != styleList.CEnd(); ++iterSubStyle )
+            {
+              const TreeNode* nameNode = (*iterSubStyle).second.Find("name");
+              if( nameNode && nameNode->GetType() == TreeNode::STRING )
+              {
+                Dali::Actor found = actor.FindChildByName( nameNode->GetString() );
+                if( found )
+                {
+                  SetProperties( (*iterSubStyle).second, found, *this, replacement );
+                }
+                else
+                {
+                  DALI_SCRIPT_VERBOSE("Cannot find object '%s' in tree to style\n", nameNode->GetString());
+                }
+              }
+              else
+              {
+                DALI_SCRIPT_VERBOSE("Style name is not a string '%s' '%d'\n",
+                                    nameNode->GetString(), (*iterSubStyle).second.GetType());
+              }
+            }
+          }
+          else
+          {
+            DALI_SCRIPT_VERBOSE("Cannot apply style list to non actor\n");
+          }
+        }
+        else
+        {
+          DALI_ASSERT_DEBUG( (*iter)->GetType() == TreeNode::OBJECT );
+          SetProperties( *style, handle, *this, replacement );
+        }
       }
     }
     else
@@ -641,7 +946,13 @@ void Builder::ApplyStyle( const std::string& styleName, Handle& handle )
   }
 }
 
-BaseHandle Builder::CreateFromStyle( const std::string& styleName )
+BaseHandle Builder::CreateFromStyle( const std::string& styleName, const PropertyValueMap& map )
+{
+  Replacement replacement( map, mReplacementMap );
+  return CreateFromStyle( styleName, replacement );
+}
+
+BaseHandle Builder::CreateFromStyle( const std::string& styleName, const Replacement& constant )
 {
   BaseHandle baseHandle;
 
@@ -660,7 +971,7 @@ BaseHandle Builder::CreateFromStyle( const std::string& styleName )
     }
     else
     {
-      OptionalString type = IsString( IsChild(*style, "type") );
+      OptionalString type = constant.IsString( IsChild(*style, "type") );
 
       if(!type)
       {
@@ -668,7 +979,7 @@ BaseHandle Builder::CreateFromStyle( const std::string& styleName )
       }
       else
       {
-        baseHandle = Create( mSlotDelegate.GetConnectionTracker(), styles, *style, *mParser.GetRoot(), Actor(), *this );
+        baseHandle = Create( styles, *style, *mParser.GetRoot(), Actor(), constant );
       }
     }
   }
@@ -676,6 +987,14 @@ BaseHandle Builder::CreateFromStyle( const std::string& styleName )
   return baseHandle;
 }
 
+
+BaseHandle Builder::CreateFromStyle( const std::string& styleName )
+{
+  PropertyValueMap overrideMap;
+  Replacement replacement( overrideMap, mReplacementMap );
+  return CreateFromStyle( styleName, replacement );
+}
+
 Builder::Builder()
 : mSlotDelegate( this )
 {
index ba52c08..7747b49 100644 (file)
@@ -28,6 +28,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/builder/json-parser.h>
 #include <dali-toolkit/public-api/builder/builder.h>
+#include <dali-toolkit/internal/builder/builder-declarations.h>
 
 // Warning messages usually displayed
 #define DALI_SCRIPT_WARNING(format, args...) \
@@ -60,6 +61,7 @@ extern Dali::Integration::Log::Filter* gFilterScript;
 #endif
 
 class Builder;
+class Replacement;
 
 /**
  * @copydoc Toolkit::Builder
@@ -77,16 +79,41 @@ public:
                        Dali::Toolkit::Builder::UIFormat rep = Dali::Toolkit::Builder::JSON );
 
   /**
-   * @copydoc Toolkit::Builder::CreateAnimation
+   * @copydoc Toolkit::Builder::AddConstants
+   */
+  void AddConstants( const PropertyValueMap& map );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateAnimation( const std::string& animationName );
    */
   Animation CreateAnimation( const std::string& animationName );
 
   /**
-   * @copydoc Toolkit::Builder::CreateFromStyle
+   * @copydoc Toolkit::Builder::CreateAnimation( const std::string& animationName, const PropertyValueMap& map );
+   */
+  Animation CreateAnimation( const std::string& animationName, const PropertyValueMap& map );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateAnimation( const std::string& animationName, Dali::Actor searchRoot );
+   */
+  Animation CreateAnimation( const std::string& animationName, Dali::Actor searchRoot );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateAnimation( const std::string& animationName, const PropertyValueMap& map, Dali::Actor searchRoot );
+   */
+  Animation CreateAnimation( const std::string& animationName, const PropertyValueMap& map, Dali::Actor searchRoot );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateFromStyle( const std::string& styleName );
    */
   BaseHandle CreateFromStyle( const std::string& styleName );
 
   /**
+   * @copydoc Toolkit::Builder::CreateFromStyle( const std::string& styleName, const PropertyValueMap& map );
+   */
+  BaseHandle CreateFromStyle( const std::string& styleName, const PropertyValueMap& map );
+
+  /**
    * @copydoc Toolkit::Builder::GetFont
    */
   Font GetFont(const std::string &name) const;
@@ -137,11 +164,21 @@ public:
   ShaderEffect GetShaderEffect( const std::string &name );
 
   /**
+   * @copydoc Toolkit::Builder::GetShaderEffect
+   */
+  ShaderEffect GetShaderEffect( const std::string &name, const Replacement& constant );
+
+  /**
    * @copydoc Toolkit::Builder::GetFrameBufferImage
    */
   FrameBufferImage GetFrameBufferImage( const std::string &name );
 
   /**
+   * @copydoc Toolkit::Builder::GetFrameBufferImage
+   */
+  FrameBufferImage GetFrameBufferImage( const std::string &name, const Replacement& constant );
+
+  /**
    * @copydoc Toolkit::Builder::GetTopLevelActors
    */
   ActorContainer GetTopLevelActors( void ) const;
@@ -155,7 +192,7 @@ private:
   Builder(const Builder&);
   Builder& operator=(const Builder& rhs);
 
-  void SetupTask( RenderTask& task, const Toolkit::TreeNode& node );
+  void SetupTask( RenderTask& task, const Toolkit::TreeNode& node, const Replacement& replacement );
 
 private:
   Toolkit::JsonParser mParser;
@@ -167,6 +204,19 @@ private:
   ShaderEffectLut mShaderEffectLut;
 
   SlotDelegate<Builder> mSlotDelegate;
+
+  PropertyValueMap mReplacementMap;
+
+  BaseHandle Create( const OptionalChild& optionalStyles, const TreeNode& node, const TreeNode& root, Actor parent,
+                     const Replacement& replacement );
+
+  void LoadConstants();
+
+  void ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement);
+
+  Animation CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor searchRoot );
+
+  BaseHandle CreateFromStyle( const std::string& styleName, const Replacement& replacement );
 };
 
 } // namespace Internal
index 5b079bb..e0e98c8 100644 (file)
@@ -17,6 +17,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/builder/builder-impl.h>
 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+#include <dali-toolkit/internal/builder/replacement.h>
 
 namespace Dali
 {
@@ -38,6 +39,16 @@ namespace Internal
 bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
 
 /*
+ * Set a property value from a tree node as SetPropertyFromNode() above
+ * @param node  The node string to convert from
+ * @param value The property value to set
+ * @param replacement The overriding replacement map (if any)
+ * @return true if the string could be converted.
+ */
+bool SetPropertyFromNode( const TreeNode& node, Property::Value& value,
+                          const Replacement& replacement );
+
+/*
  * Set a property value as the given type from a tree node.
  * @param node The node string to convert from
  * @param type The property type to convert to.
@@ -46,16 +57,39 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
  */
 bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value );
 
+/*
+ * Set a property value as the given type from a tree node as SetPropertyFromNode() above
+ * @param node The node string to convert from
+ * @param type The property type to convert to.
+ * @param value The property value to set
+ * @param replacement The overriding replacement map (if any)
+ * @return true if the string could be converted to the correct type.
+ */
+bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value,
+                          const Replacement& replacement );
+
+
+namespace
+{
+
+
+
+} // anon namespace
+
+
 /**
  * A property value type can be forced when its unknown by a disambiguation convention in the json
  * ie  "myarray": [1,2,3,4] ; would be a vector but
  *     "myarray": {'type-cast':'array', 'value':[1,2,3,4]} would be an array
  * @param child The node whos string to search for a disambiguated type
  * @param value The value to set
+ * @param overrideMap The user overriding constant map
+ * @param defaultMap The default map.
  * @return True if child contained a disambiguated string that could be converted.
  */
 bool Disambiguated(const TreeNode& child, // ConstantLut& constantLut,
-                   Dali::Property::Value& value)
+                   Dali::Property::Value& value,
+                   const Replacement& replacement )
 {
   OptionalString childType = IsString( IsChild(child, "type-cast") );
   OptionalChild childValue = IsChild(child, "value");
@@ -67,43 +101,43 @@ bool Disambiguated(const TreeNode& child, // ConstantLut& constantLut,
     // type-cast and value keys. If they do then a work around is to add a bogus key to not run this case.
     if(*childType == "boolean")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::BOOLEAN, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::BOOLEAN, value, replacement);
     }
     else if(*childType == "float")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::FLOAT, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::FLOAT, value, replacement);
     }
     else if(*childType == "vector2")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::VECTOR2, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::VECTOR2, value, replacement);
     }
     else if(*childType == "vector3")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::VECTOR3, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::VECTOR3, value, replacement);
     }
     else if(*childType == "vector4")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::VECTOR4, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::VECTOR4, value, replacement);
     }
     else if(*childType == "rotation")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::ROTATION, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::ROTATION, value, replacement);
     }
     else if(*childType == "rect")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::RECTANGLE, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::RECTANGLE, value, replacement);
     }
     else if(*childType == "string")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::STRING, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::STRING, value, replacement);
     }
     else if(*childType == "map")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::MAP, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::MAP, value, replacement);
     }
     else if(*childType == "array")
     {
-      return SetPropertyFromNode( *childValue, Dali::Property::ARRAY, value);
+      return SetPropertyFromNode( *childValue, Dali::Property::ARRAY, value, replacement);
     }
   }
 
@@ -111,7 +145,15 @@ bool Disambiguated(const TreeNode& child, // ConstantLut& constantLut,
   return false;
 }
 
-bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value )
+
+bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value)
+{
+  Replacement noReplacement;
+  return SetPropertyFromNode( node, type, value, noReplacement );
+}
+
+bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value,
+                          const Replacement& replacer )
 {
   bool done = false;
 
@@ -119,7 +161,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
   {
     case Property::BOOLEAN:
     {
-      if( OptionalBoolean v = IsBoolean(node) )
+      if( OptionalBoolean v = replacer.IsBoolean(node) )
       {
         value = *v;
         done = true;
@@ -128,7 +170,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::FLOAT:
     {
-      if( OptionalFloat v = IsFloat(node) )
+      if( OptionalFloat v = replacer.IsFloat(node) )
       {
         value = *v;
         done = true;
@@ -137,7 +179,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::INTEGER:
     {
-      if( OptionalInteger v = IsInteger(node) )
+      if( OptionalInteger v = replacer.IsInteger(node) )
       {
         value = *v;
         done = true;
@@ -146,7 +188,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::UNSIGNED_INTEGER:
     {
-      if( OptionalInteger v = IsInteger(node) )
+      if( OptionalInteger v = replacer.IsInteger(node) )
       {
         if( *v >= 0 ) // with a loss of resolution....
         {
@@ -158,7 +200,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::VECTOR2:
     {
-      if( OptionalVector2 v = IsVector2(node) )
+      if( OptionalVector2 v = replacer.IsVector2(node) )
       {
         value = *v;
         done = true;
@@ -167,7 +209,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::VECTOR3:
     {
-      if( OptionalVector3 v = IsVector3(node) )
+      if( OptionalVector3 v = replacer.IsVector3(node) )
       {
         value = *v;
         done = true;
@@ -176,16 +218,16 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::VECTOR4:
     {
-      if( OptionalVector4 v = IsVector4(node) )
+      if( OptionalVector4 v = replacer.IsVector4(node) )
       {
         value = *v;
         done = true;
-       }
+      }
       break;
     }
     case Property::MATRIX3:
     {
-      if( OptionalMatrix3 v = IsMatrix3(node) )
+      if( OptionalMatrix3 v = replacer.IsMatrix3(node) )
       {
         value = *v;
         done = true;
@@ -194,7 +236,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::MATRIX:
     {
-      if( OptionalMatrix v = IsMatrix(node) )
+      if( OptionalMatrix v = replacer.IsMatrix(node) )
       {
         value = *v;
         done = true;
@@ -203,7 +245,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::RECTANGLE:
     {
-      if( OptionalRect v = IsRect(node) )
+      if( OptionalRect v = replacer.IsRect(node) )
       {
         value = *v;
         done = true;
@@ -214,7 +256,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     {
       if(4 == node.Size())
       {
-        if( OptionalVector4 ov = IsVector4(node) )
+        if( OptionalVector4 ov = replacer.IsVector4(node) )
         {
           const Vector4& v = *ov;
           // angle, axis as per spec
@@ -226,7 +268,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
       else
       {
         // degrees Euler as per spec
-        if( OptionalVector3 v = IsVector3(node) )
+        if( OptionalVector3 v = replacer.IsVector3(node) )
         {
           value = Quaternion(Radian(Degree((*v).x)),
                              Radian(Degree((*v).y)),
@@ -238,7 +280,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::STRING:
     {
-      if( OptionalString v = IsString(node) )
+      if( OptionalString v = replacer.IsString(node) )
       {
         value = *v;
         done = true;
@@ -247,7 +289,11 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::ARRAY:
     {
-      if(node.Size())
+      if( replacer.IsArray( node, value ) )
+      {
+        done = true;
+      }
+      else if(node.Size())
       {
         value = Property::Value(Property::ARRAY);
         unsigned int i = 0;
@@ -255,7 +301,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
         for( ; i < node.Size(); ++i, ++iter)
         {
           Property::Value v;
-          if( SetPropertyFromNode( (*iter).second, v) )
+          if( SetPropertyFromNode( (*iter).second, v, replacer ) )
           {
             value.AppendItem(v);
           }
@@ -274,7 +320,11 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     }
     case Property::MAP:
     {
-      if(node.Size())
+      if( replacer.IsMap( node, value ) )
+      {
+        done = true;
+      }
+      else if(node.Size())
       {
         value = Property::Value(Property::MAP);
         unsigned int i = 0;
@@ -282,7 +332,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
         for( ; i < node.Size(); ++i, ++iter)
         {
           Property::Value v;
-          if( SetPropertyFromNode( (*iter).second, v) )
+          if( SetPropertyFromNode( (*iter).second, v, replacer ) )
           {
             value.SetValue( (*iter).first, v );
           }
@@ -304,20 +354,27 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     {
       break;
     }
-  }
+  } // switch type
 
   return done;
 }
 
-
 bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )
+
+{
+  Replacement replacer;
+  return SetPropertyFromNode( node, value, replacer );
+}
+
+bool SetPropertyFromNode( const TreeNode& node, Property::Value& value,
+                          const Replacement& replacer )
 {
   bool done = false;
 
   // some values are ambiguous as we have no Property::Type but can be disambiguated in the json
 
   // Currently Rotations and Rectangle must always be disambiguated when a type isnt available
-  if( Disambiguated( node, value ) )
+  if( Disambiguated( node, value, replacer ) )
   {
     done = true;
   }
@@ -351,7 +408,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )
           value = *v;
           done = true;
         }
-        if( OptionalVector4 v = IsVector4(node) )
+        else if( OptionalVector4 v = IsVector4(node) )
         {
           value = *v;
           done = true;
@@ -381,7 +438,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )
 
           for(TreeConstIter iter = node.CBegin(); iter != node.CEnd(); ++iter)
           {
-            if( SetPropertyFromNode( (*iter).second, v) )
+            if( SetPropertyFromNode( (*iter).second, v, replacer ) )
             {
               value.AppendItem(v);
               done = true;
@@ -404,7 +461,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )
           Property::Value v;
           for(unsigned int i = 0; i < node.Size(); ++i, ++iter)
           {
-            if( SetPropertyFromNode( (*iter).second, v) )
+            if( SetPropertyFromNode( (*iter).second, v, replacer ) )
             {
               value.AppendItem(v);
               done = true;
@@ -417,7 +474,7 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )
           Property::Value v;
           for(unsigned int i = 0; i < node.Size(); ++i, ++iter)
           {
-            if( SetPropertyFromNode( (*iter).second, v) )
+            if( SetPropertyFromNode( (*iter).second, v, replacer ) )
             {
               value.SetValue((*iter).first, v);
               done = true;
@@ -429,10 +486,10 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )
     else // if( 0 == node.size() )
     {
       // no children so either one of bool, float, integer, string
-      OptionalBoolean aBool    = IsBoolean(node);
-      OptionalInteger anInt    = IsInteger(node);
-      OptionalFloat   aFloat   = IsFloat(node);
-      OptionalString  aString  = IsString(node);
+      OptionalBoolean aBool    = replacer.IsBoolean(node);
+      OptionalInteger anInt    = replacer.IsInteger(node);
+      OptionalFloat   aFloat   = replacer.IsFloat(node);
+      OptionalString  aString  = replacer.IsString(node);
 
       if(aBool)
       {
index edf961f..0ab0e7b 100644 (file)
@@ -289,6 +289,7 @@ boost::function<void (void)> GetAction(const TreeNode &root, const TreeNode &chi
       {
         DelayedAnimationPlay action;
         action.memento = Toolkit::JsonParser::New(*animNode);
+        // @todo; put constants into the map
         callback = action;
       }
       else
index ca7b139..9b6fa4f 100644 (file)
@@ -663,6 +663,8 @@ char* JsonParserState::EncodeString()
   mNumberOfParsedChars += last - first;
   mNumberOfParsedChars += 1 ; // null terminator
 
+  mCurrent.SetSubstitution( substitution > 1 );
+
   // return true;
   return &(*first);
 
diff --git a/dali-toolkit/internal/builder/replacement.cpp b/dali-toolkit/internal/builder/replacement.cpp
new file mode 100644 (file)
index 0000000..701b7c8
--- /dev/null
@@ -0,0 +1,635 @@
+//
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Flora License, Version 1.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://floralicense.org/license/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an AS IS BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/replacement.h>
+#include <dali-toolkit/internal/builder/builder-impl.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace  // anon
+{
+
+PropertyValueMap::const_iterator FindReplacement( const std::string &str,
+                                                const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap )
+{
+  PropertyValueMap::const_iterator ret  = defaultMap.end();
+
+  PropertyValueMap::const_iterator iter = overrideMap.find( str );
+
+  if( iter != overrideMap.end() )
+  {
+    ret = iter;
+  }
+  else
+  {
+    PropertyValueMap::const_iterator iter = defaultMap.find( str );
+
+    if( iter != defaultMap.end() )
+    {
+      ret = iter;
+    }
+    else
+    {
+      // @ todo
+      // try localized text ie dgettext. Look for colon  {DOMAIN:TEXT} {LC_MESSAGE:ID_XXXX}
+
+    }
+  }
+
+  return ret;
+}
+
+std::size_t FirstUnescapedChar(const std::string &initialValue, const std::size_t& startPos, const char c)
+{
+  std::size_t pos = initialValue.find( c, startPos );
+
+  if(pos > 0)
+  {
+    while( pos != std::string::npos )
+    {
+      if( '\\' == initialValue.at( pos-1 ) )
+      {
+        pos = initialValue.find( c, pos );
+      }
+      else
+      {
+        break;
+      }
+    }
+  }
+
+  return pos;
+}
+
+bool GetSubstitutionPosition( const std::string &initialValue, std::size_t &startPos, std::size_t &size )
+{
+  std::size_t pos = FirstUnescapedChar(initialValue, 0, '{');
+
+  if( std::string::npos == pos )
+  {
+    startPos = std::string::npos;
+    return false;
+  }
+  else
+  {
+    startPos = pos + 1;
+  }
+
+  pos = FirstUnescapedChar(initialValue, startPos, '}');
+
+  if( std::string::npos == pos )
+  {
+    size = std::string::npos;
+    return false;
+  }
+  else
+  {
+    size = pos - startPos;
+  }
+
+  return true;
+}
+
+bool ResolvePartialReplacement( const std::string &initialValue, Property::Value &out,
+                                const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap )
+{
+
+  if( initialValue.size() >= 2 )
+  {
+    // eg '{"constants": { "IMAGE_DIR": "/share/images" },
+    //      ...
+    //        "filename":"{IMAGE_DIR}/theme/header.png",
+    //
+    std::size_t startPos = 0;
+    std::size_t size     = std::string::npos;
+
+    if( !GetSubstitutionPosition( initialValue, startPos, size ) )
+    {
+      out = initialValue;
+      return true;
+    }
+    else
+    {
+      const std::string str( initialValue.substr( startPos, size ) );
+
+      PropertyValueMap::const_iterator iter = FindReplacement( str, overrideMap, defaultMap );
+
+      if( iter == defaultMap.end() )
+      {
+        DALI_SCRIPT_WARNING( "Cannot find replacement for '%s'\n", str.c_str() );
+      }
+      else
+      {
+        if( Property::STRING != (*iter).second.GetType() )
+        {
+          DALI_SCRIPT_WARNING( "Cannot replace substring in non string property type='%s'. Initial value '%s'\n",
+                               PropertyTypes::GetName( out.GetType() ), initialValue.c_str() );
+        }
+        else
+        {
+          std::string newString = \
+            initialValue.substr(0, startPos - 1) +
+            (*iter).second.Get<std::string>() +
+            initialValue.substr( startPos + size + 1 );
+
+          return ResolvePartialReplacement( newString, out, overrideMap,  defaultMap );
+        }
+      }
+    }
+  }
+
+  // if we get here we failed
+  return false;
+}
+
+} // namespace anon
+
+
+Replacement::Replacement( const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap )
+  : mOverrideMap( &overrideMap ), mDefaultMap( &defaultMap )
+{
+
+}
+
+namespace
+{
+PropertyValueMap noMap;
+}
+
+Replacement::Replacement( const PropertyValueMap& defaultMap )
+  : mOverrideMap( &noMap ), mDefaultMap( &defaultMap )
+{
+
+}
+
+Replacement::Replacement(  )
+  : mOverrideMap( &noMap ), mDefaultMap( &noMap )
+{
+
+}
+
+OptionalString Replacement::HasFullReplacement( const TreeNode & node ) const
+{
+  OptionalString ret;
+
+  if( node.HasSubstitution() && ((*mOverrideMap).size() || (*mDefaultMap).size()) )
+  {
+    OptionalString v = ::IsString( node );
+    if( v )
+    {
+      const std::string& initialValue = *v;
+      if( (initialValue[ 0 ] == '{') && (initialValue[ initialValue.size() -1 ] == '}') )
+      {
+        ret = initialValue.substr( 1, initialValue.size() - 2 );
+      }
+    }
+  }
+  return ret;
+}
+
+Property::Value Replacement::GetFullReplacement( const std::string& replacementString ) const
+{
+  Property::Value out;
+  DALI_ASSERT_DEBUG( mOverrideMap && "missing map");
+  DALI_ASSERT_DEBUG( mDefaultMap && "missing map");
+
+  PropertyValueMap::const_iterator iter = FindReplacement( replacementString, *mOverrideMap, *mDefaultMap );
+
+  if( iter == (*mDefaultMap).end() )
+  {
+    DALI_SCRIPT_WARNING("Cannot find replacement for '%s'\n", replacementString.c_str());
+  }
+  else
+  {
+    out = (*iter).second;
+#if defined(DEBUG_ENABLED)
+    DALI_SCRIPT_VERBOSE("  Full replacement for '%s' => to Type '%s'\n",
+                        replacementString.c_str(),
+                        PropertyTypes::GetName( out.GetType()) );
+#endif
+  }
+
+  return out;
+}
+
+OptionalBoolean Replacement::IsBoolean( const TreeNode & node ) const
+{
+  OptionalBoolean ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::BOOLEAN == value.GetType() )
+    {
+      ret = value.Get<bool>();
+    }
+  }
+  else
+  {
+    ret = ::IsBoolean( node );
+  }
+  return ret;
+}
+
+OptionalBoolean Replacement::IsBoolean( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsBoolean( *child );
+  }
+  else
+  {
+    return OptionalBoolean();
+  }
+}
+
+// template <typename T, OptionalValue<T> (*ISTYPE)( const TreeNode& node ), Property::Type TYPE>
+// OptionalValue<T> IsOfType( const TreeNode& node, const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap )
+// {
+//   OptionalValue<T> ret;
+//   if( OptionalString replace = HasFullReplacement( node, overrideMap, defaultMap ) )
+//   {
+//     Property::Value value = GetFullReplacement( *replace, overrideMap, defaultMap );
+//     if( TYPE == value.GetType() )
+//     {
+//       ret = value.Get<T>();
+//     }
+//   }
+//   else
+//   {
+//     ret = ISTYPE( node );
+//   }
+//   return ret;
+
+// }
+
+// OptionalFloat Replacement::IsFloat( const TreeNode & node ) const
+// {
+//   return IsOfType<float, ::IsFloat, Property::FLOAT>( node, *mOverrideMap, *mDefaultMap );
+//   /* OptionalFloat ret; */
+//   /* if( OptionalString replace = HasFullReplacement( node ) ) */
+//   /* { */
+//   /*   Property::Value value = GetFullReplacement( replace ); */
+//   /*   if( Property::FLOAT == value.GetType() ) */
+//   /*   { */
+//   /*     ret = value.Get<float>(); */
+//   /*   } */
+//   /* } */
+//   /* else */
+//   /* { */
+//   /*   ret = IsFloat( node ); */
+//   /* } */
+//   /* return ret; */
+// }
+
+OptionalFloat Replacement::IsFloat( const TreeNode & node ) const
+{
+  OptionalFloat ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::FLOAT == value.GetType() )
+    {
+      ret = value.Get<float>();
+    }
+  }
+  else
+  {
+    ret = ::IsFloat( node );
+  }
+  return ret;
+}
+
+OptionalString Replacement::IsString( const TreeNode& node ) const
+{
+  OptionalString ret;
+
+  DALI_ASSERT_DEBUG( mOverrideMap && "missing map");
+  DALI_ASSERT_DEBUG( mDefaultMap && "missing map");
+
+  if( node.HasSubstitution() && ((*mOverrideMap).size() || (*mDefaultMap).size()) )
+  {
+    if( OptionalString v = ::IsString( node ) )
+    {
+      Property::Value value;
+      if( ResolvePartialReplacement( *v, value, *mOverrideMap, *mDefaultMap ) )
+      {
+        if( Property::STRING == value.GetType() )
+        {
+          ret = value.Get<std::string>();
+#if defined(DEBUG_ENABLED)
+          DALI_SCRIPT_VERBOSE("  Resolved substring replacement for '%s' => '%s'\n", (*v).c_str(), (*ret).c_str());
+#endif
+        }
+      }
+    }
+  }
+  else
+  {
+    ret = ::IsString( node );
+  }
+  return ret;
+}
+
+OptionalInteger Replacement::IsInteger( const TreeNode & node ) const
+{
+  OptionalInteger ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::INTEGER == value.GetType() )
+    {
+      ret = value.Get<int>();
+    }
+  }
+  else
+  {
+    ret = ::IsInteger( node );
+  }
+  return ret;
+}
+
+OptionalVector2 Replacement::IsVector2( const TreeNode & node ) const
+{
+  OptionalVector2 ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::VECTOR2 == value.GetType() )
+    {
+      ret = value.Get<Vector2>();
+    }
+  }
+  else
+  {
+    ret = ::IsVector2( node );
+  }
+  return ret;
+}
+
+OptionalVector3 Replacement::IsVector3( const TreeNode & node ) const
+{
+  OptionalVector3 ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::VECTOR3 == value.GetType() )
+    {
+      ret = value.Get<Vector3>();
+    }
+  }
+  else
+  {
+    ret = ::IsVector3( node );
+  }
+  return ret;
+}
+
+OptionalVector4 Replacement::IsVector4( const TreeNode & node ) const
+{
+  OptionalVector4 ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::VECTOR4 == value.GetType() )
+    {
+      ret = value.Get<Vector4>();
+    }
+  }
+  else
+  {
+    ret = ::IsVector4( node );
+  }
+  return ret;
+}
+
+OptionalMatrix Replacement::IsMatrix( const TreeNode & node ) const
+{
+  OptionalMatrix ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::MATRIX == value.GetType() )
+    {
+      ret = value.Get<Matrix>();
+    }
+  }
+  else
+  {
+    ret = ::IsMatrix( node );
+  }
+  return ret;
+}
+
+OptionalMatrix3 Replacement::IsMatrix3( const TreeNode & node ) const
+{
+  OptionalMatrix3 ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::MATRIX3 == value.GetType() )
+    {
+      ret = value.Get<Matrix3>();
+    }
+  }
+  else
+  {
+    ret = ::IsMatrix3( node );
+  }
+  return ret;
+}
+
+OptionalRect Replacement::IsRect( const TreeNode & node ) const
+{
+  OptionalRect ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::RECTANGLE == value.GetType() )
+    {
+      ret = value.Get<Rect<int> >();
+    }
+  }
+  else
+  {
+    ret = ::IsRect( node );
+  }
+  return ret;
+}
+
+
+
+OptionalFloat Replacement::IsFloat( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsFloat( *child );
+  }
+  else
+  {
+    return OptionalFloat();
+  }
+}
+
+
+OptionalString Replacement::IsString( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsString( *child );
+  }
+  else
+  {
+    return OptionalString();
+  }
+}
+
+OptionalInteger Replacement::IsInteger( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsInteger( *child );
+  }
+  else
+  {
+    return OptionalInteger();
+  }
+}
+
+OptionalVector2 Replacement::IsVector2( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsVector2( *child );
+  }
+  else
+  {
+    return OptionalVector2();
+  }
+}
+
+OptionalVector3 Replacement::IsVector3( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsVector3( *child );
+  }
+  else
+  {
+    return OptionalVector3();
+  }
+}
+
+OptionalVector4 Replacement::IsVector4( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsVector4( *child );
+  }
+  else
+  {
+    return OptionalVector4();
+  }
+}
+
+OptionalMatrix Replacement::IsMatrix( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsMatrix( *child );
+  }
+  else
+  {
+    return OptionalMatrix();
+  }
+}
+
+OptionalMatrix3 Replacement::IsMatrix3( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsMatrix3( *child );
+  }
+  else
+  {
+    return OptionalMatrix3();
+  }
+}
+
+OptionalRect Replacement::IsRect( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsRect( *child );
+  }
+  else
+  {
+    return OptionalRect();
+  }
+}
+
+bool Replacement::IsMap( OptionalChild child, Property::Value& out ) const
+{
+  bool ret = false;
+
+  if( child )
+  {
+    if( OptionalString replace = HasFullReplacement( *child ) )
+    {
+      out = GetFullReplacement( *replace );
+      if( Property::MAP == out.GetType() )
+      {
+        ret = true;
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool Replacement::IsArray( OptionalChild child, Property::Value& out ) const
+{
+  bool ret = false;
+
+  if( child )
+  {
+    if( OptionalString replace = HasFullReplacement( *child ) )
+    {
+      out = GetFullReplacement( *replace );
+      if( Property::ARRAY == out.GetType() )
+      {
+        ret = true;
+      }
+    }
+  }
+
+  return ret;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
diff --git a/dali-toolkit/internal/builder/replacement.h b/dali-toolkit/internal/builder/replacement.h
new file mode 100644 (file)
index 0000000..879c57c
--- /dev/null
@@ -0,0 +1,248 @@
+#ifndef __DALI_TOOLKIT_INTERNAL_BUILDER_REPLACEMENT__
+#define __DALI_TOOLKIT_INTERNAL_BUILDER_REPLACEMENT__
+
+//
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Flora License, Version 1.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://floralicense.org/license/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an AS IS BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <dali/public-api/object/property-value.h>
+#include <dali-toolkit/public-api/builder/builder.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+  class TreeNode;
+}
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/*
+ * Supports template replacement functionality
+ *
+ */
+class Replacement
+{
+public:
+
+  /*
+   * Constructor
+   */
+  Replacement();
+
+  /*
+   * Constructor with default and overriding map
+   *
+   * Make a deep copy of the tree.
+   * @param overrideMap The user overriding map
+   * @param defaultMap The default map to use
+   */
+  Replacement( const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap );
+
+  /*
+   * Constructor with default map
+   *
+   * Make a deep copy of the tree.
+   * @param overrideMap The user overriding map
+   */
+  Replacement( const PropertyValueMap& defaultMap );
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalString IsString( const TreeNode& node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalBoolean IsBoolean( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalFloat IsFloat( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalInteger IsInteger( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalVector2 IsVector2( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalVector3 IsVector3( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalVector4 IsVector4( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalMatrix IsMatrix( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalMatrix3 IsMatrix3( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalRect IsRect( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalString IsString( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalFloat IsFloat( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalBoolean IsBoolean( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalInteger IsInteger( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalVector2 IsVector2( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalVector3 IsVector3( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalVector4 IsVector4( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalMatrix IsMatrix( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalMatrix3 IsMatrix3( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalRect IsRect( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  bool IsMap( OptionalChild child, Property::Value& out ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  bool IsArray( OptionalChild child, Property::Value& out ) const;
+
+private:
+  // Overriding map (overrides the default map). The map is not owned.
+  const PropertyValueMap* const mOverrideMap;
+
+  // Defautl map. The map is not owned.
+  const PropertyValueMap* const mDefaultMap;
+
+  // compiler
+  // Replacement & operation=( Replacement& replacement );
+  // Replacement( const Replacement& copy );
+
+  // Returns the string if the node has a full replacement ie IMAGES if node is "{IMAGES}"
+  OptionalString HasFullReplacement( const TreeNode & node ) const;
+
+  // Returns the property value for a full replacement from the maps
+  Property::Value GetFullReplacement( const std::string& replacementString ) const;
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // header
index e0e8ebc..221e1b6 100644 (file)
@@ -10,6 +10,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/builder/json-parser-state.cpp \
    $(toolkit_src_dir)/builder/json-parser-impl.cpp \
    $(toolkit_src_dir)/builder/tree-node-manipulator.cpp \
+   $(toolkit_src_dir)/builder/replacement.cpp \
    $(toolkit_src_dir)/controls/relayout-controller.cpp \
    $(toolkit_src_dir)/controls/relayout-controller-impl.cpp \
    $(toolkit_src_dir)/controls/relayout-helper.cpp \
index 8613016..4a3fdfc 100644 (file)
@@ -53,16 +53,31 @@ void Builder::LoadFromString( const std::string &data, UIFormat rep )
   GetImpl(*this).LoadFromString( data );
 }
 
+void Builder::AddConstants( const PropertyValueMap& map )
+{
+  GetImpl(*this).AddConstants( map );
+}
+
 Animation Builder::CreateAnimation( const std::string& animationName )
 {
   return GetImpl(*this).CreateAnimation( animationName );
 }
 
+Animation Builder::CreateAnimation( const std::string& animationName, const PropertyValueMap& map )
+{
+  return GetImpl(*this).CreateAnimation( animationName, map );
+}
+
 BaseHandle Builder::CreateFromStyle( const std::string& styleName )
 {
   return GetImpl(*this).CreateFromStyle( styleName );
 }
 
+BaseHandle Builder::CreateFromStyle( const std::string& styleName, const PropertyValueMap& map )
+{
+  return GetImpl(*this).CreateFromStyle( styleName, map );
+}
+
 void Builder::ApplyStyle( const std::string& styleName, Handle& handle )
 {
   GetImpl(*this).ApplyStyle( styleName, handle );
index 8df2619..abc5a26 100644 (file)
@@ -31,6 +31,8 @@ namespace Internal DALI_INTERNAL
 class Builder;
 }
 
+typedef std::map<std::string, Property::Value> PropertyValueMap;
+
 /**
  * Builder
  * This class provides the ability to load an actor tree from a string representation.
@@ -122,6 +124,19 @@ class Builder;
   void LoadFromString( const std::string& data, UIFormat format = JSON );
 
   /**
+   * @brief Adds user defined constants to all future style template or animation expansions
+   *
+   * e.g.
+   *   PropertyValueMap map;
+   *   map["IMAGE_DIRECTORY"] = "/usr/share/images";
+   *   builder.AddConstants( map );
+   *
+   * @pre The Builder has been initialized.
+   * @param map The user defined constants used in template expansions.
+   */
+  void AddConstants( const PropertyValueMap& map );
+
+  /**
    * Creates an animation from the set of known animations
    * e.g.
    *   Animation a = builder.CreateAnimation( "wobble");
@@ -135,7 +150,26 @@ class Builder;
   Animation CreateAnimation( const std::string& animationName );
 
   /**
-   * Creates an object (e.g. an actor) from the set of known styles
+   * @brief Creates an animation from the set of known animations with user defined constants
+   *
+   * e.g.
+   *   PropertyValueMap map;
+   *   map["ACTOR"] = actor.GetName();       // replaces '{ACTOR} in the template
+   *   Animation a = builder.CreateAnimation( "wobble");
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @pre The animationName exists in the animations section of the data representation
+   * @pre The map contains all the constant expansions in the style template
+   * @param animationName The animation name to create
+   * @param map The user defined constants used in style template expansion.
+   * @returns The base handle of the created object
+   */
+  Animation CreateAnimation( const std::string& animationName, const PropertyValueMap& map );
+
+  /**
+   * @brief Creates an object (e.g. an actor) from the set of known style templates
+   *
    * e.g.
    *   mActor.Add( Actor::DownCast(builder.CreateFromStyle( "default-text")) );
    *
@@ -149,6 +183,25 @@ class Builder;
   BaseHandle CreateFromStyle( const std::string& styleName );
 
   /**
+   * @brief Creates an object from the style templates with user defined constants
+   *
+   * e.g.
+   *   PropertyValueMap map;
+   *   map["IMAGE_DIR"] = "/usr/share/images"; // replaces '{IMAGE_DIR} in the template
+   *   mActor.Add( Actor::DownCast(builder.CreateFromStyle( "default-image", map) ) );
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @pre The styleName has been loaded from the styles section of the data representation
+   *      and contains 'type' property used to create the object.
+   * @pre The map contains all the constant expansions in the style template
+   * @param styleName The set of styles/properties to set on the handle object.
+   * @param map The user defined constants used in style template expansion.
+   * @returns The base handle of the created object
+   */
+  BaseHandle CreateFromStyle( const std::string& styleName, const PropertyValueMap& map );
+
+  /**
    * Apply a style (a collection of properties) to an actor.
    * @pre The Builder has been initialized.
    * @pre Preconditions have been met for creating dali objects ie Images, Actors etc