/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 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.
// EXTERNAL INCLUDES
#include <sys/stat.h>
#include <sstream>
+
#include <dali/public-api/render-tasks/render-task-list.h>
#include <dali/public-api/object/type-info.h>
#include <dali/public-api/object/type-registry.h>
#include <dali/public-api/object/property-array.h>
#include <dali/public-api/actors/layer.h>
-#include <dali/public-api/actors/image-actor.h>
#include <dali/public-api/actors/camera-actor.h>
#include <dali/devel-api/scripting/scripting.h>
#include <dali/public-api/signals/functor-delegate.h>
#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/builder-set-property.h>
#include <dali-toolkit/internal/builder/replacement.h>
+#include <dali-toolkit/internal/builder/tree-node-manipulator.h>
+
+#include <dali-toolkit/internal/builder/builder-impl-debug.h>
namespace Dali
{
class Replacement;
extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot, Builder* const builder );
-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, Dali::Toolkit::Internal::Builder* const builder);
extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
-extern Actor SetupActor( const TreeNode& node, Actor& actor, const Replacement& constant );
#if defined(DEBUG_ENABLED)
Integration::Log::Filter* gFilterScript = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT");
const std::string KEYNAME_NAME = "name";
const std::string KEYNAME_TEMPLATES = "templates";
const std::string KEYNAME_INCLUDES = "includes";
+const std::string KEYNAME_MAPPINGS = "mappings";
-typedef std::vector<const TreeNode*> TreeNodeList;
+const std::string PROPERTIES = "properties";
+const std::string ANIMATABLE_PROPERTIES = "animatableProperties";
-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();
-}
+typedef std::vector<const TreeNode*> TreeNodeList;
-#if defined(DEBUG_ENABLED)
-std::string PropertyValueToString( const Property::Value& value )
+bool GetMappingKey( const std::string& str, std::string& key )
{
- std::string ret;
-
- switch( value.GetType() )
+ bool result = false;
+ std::string test( str );
+ if( ! test.empty() )
{
- 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::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:
+ if( test.at(0) == '<' )
{
- ret = std::string("Map Size=") + ToString( value.Get<Property::Map>().Count() );
- break;
+ if( test.at(test.length()-1) == '>' )
+ {
+ key = test.substr( 1, test.length()-2 );
+ result = true;
+ }
}
}
-
- return ret;
+ return result;
}
-#endif // DEBUG_ENABLED
/*
* Recursively collects all stylesin a node (An array of style names).
{
if( handle )
{
+
for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
{
const TreeNode::KeyNodePair& keyChild = *iter;
std::string key( keyChild.first );
// ignore special fields; type,actors,signals,styles
- if(key == KEYNAME_TYPE || key == KEYNAME_ACTORS || key == KEYNAME_SIGNALS || key == KEYNAME_STYLES)
+ if(key == KEYNAME_TYPE || key == KEYNAME_ACTORS || key == KEYNAME_SIGNALS || key == KEYNAME_STYLES || key == KEYNAME_MAPPINGS )
{
continue;
}
- // special field 'image' usually contains an json object description
- // although sometimes refers to a framebuffer
- if( 0 == keyChild.second.Size() )
- {
- if(key == "image")
- {
- ImageActor imageActor = ImageActor::DownCast(handle);
- if(imageActor)
- {
- if( OptionalString s = constant.IsString( keyChild.second ) )
- {
- FrameBufferImage fb = GetFrameBufferImage(*s, constant);
- if(fb)
- {
- imageActor.SetImage( fb );
- }
- }
- }
- }
- }
-
- // special field 'effect' references the shader effect instances
- if(key == "effect")
- {
- ImageActor actor = ImageActor::DownCast(handle);
- if( actor )
- {
- OptionalString str = constant.IsString( keyChild.second );
- if( str )
- {
- ShaderEffect effect = GetShaderEffect( *str, constant );
- actor.SetShaderEffect(effect);
- }
- }
- else
- {
- DALI_SCRIPT_WARNING("Could not find or set shader effect\n");
- }
-
- continue;
- }
-
Handle propertyObject( handle );
Dali::Property::Index index = propertyObject.GetPropertyIndex( key );
- if( Property::INVALID_INDEX == index )
+ if( Property::INVALID_INDEX != index )
{
- ImageActor actor = ImageActor::DownCast(handle);
- if( actor )
+ Property::Type type = propertyObject.GetPropertyType(index);
+ Property::Value value;
+ bool mapped = false;
+
+ // if node.value is a mapping, get the property value from the "mappings" table
+ if( keyChild.second.GetType() == TreeNode::STRING )
{
- if( ShaderEffect effect = actor.GetShaderEffect() )
+ std::string mappingKey;
+ if( GetMappingKey(keyChild.second.GetString(), mappingKey) )
{
- index = effect.GetPropertyIndex( key );
- if(index != Property::INVALID_INDEX)
- {
- propertyObject = effect;
- }
+ OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS );
+ mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value );
}
}
- }
-
- if( Property::INVALID_INDEX != index )
- {
- Property::Type type = propertyObject.GetPropertyType(index);
-
- Property::Value value;
- if( !SetPropertyFromNode( keyChild.second, type, value, constant ) )
+ if( ! mapped )
{
- // verbose as this might not be a problem
- // eg parent-origin can be a string which is picked up later
- DALI_SCRIPT_VERBOSE("Could not convert property:%s\n", key.c_str());
+ mapped = DeterminePropertyFromNode( keyChild.second, type, value, constant );
+ if( ! mapped )
+ {
+ // Just determine the property from the node and if it's valid, let the property object handle it
+ DeterminePropertyFromNode( keyChild.second, value, constant );
+ mapped = ( value.GetType() != Property::NONE );
+ }
}
- else
+ if( mapped )
{
DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() );
DALI_SCRIPT_VERBOSE("SetProperty INVALID '%s' Index=:%d\n", key.c_str(), index);
}
+ // Add custom properties
+ SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE);
+ SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE);
+
} // for property nodes
}
else
}
}
+void Builder::SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant,
+ const std::string& childName, Property::AccessMode accessMode )
+{
+ // Add custom properties
+ if( OptionalChild customPropertiesChild = IsChild(node, childName) )
+ {
+ const TreeNode& customPropertiesNode = *customPropertiesChild;
+ const TreeConstIter endIter = customPropertiesNode.CEnd();
+ for( TreeConstIter iter = customPropertiesNode.CBegin(); endIter != iter; ++iter )
+ {
+ const TreeNode::KeyNodePair& keyChild = *iter;
+ std::string key( keyChild.first );
+
+ Property::Value value;
+ DeterminePropertyFromNode( keyChild.second, value, constant );
+ // Register/Set property.
+ handle.RegisterProperty( key, value, accessMode );
+ }
+ }
+}
+
// Set properties from node on handle.
void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node,
Dali::Handle& handle, const Replacement& constant )
if( actor )
{
- SetupActor( node, actor, constant );
-
// add signals
SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
const Stage& stage = Stage::GetCurrent();
Layer root = stage.GetRootLayer();
- if( OptionalString s = constant.IsString( IsChild(node, "source-actor") ) )
+ if( OptionalString s = constant.IsString( IsChild(node, "sourceActor") ) )
{
Actor actor = root.FindChildByName(*s);
if(actor)
}
}
- if( OptionalString s = constant.IsString( IsChild(node, "camera-actor") ) )
+ if( OptionalString s = constant.IsString( IsChild(node, "cameraActor") ) )
{
CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) );
if(actor)
}
}
- if( OptionalString s = constant.IsString( IsChild(node, "target-frame-buffer") ) )
+ if( OptionalString s = constant.IsString( IsChild(node, "targetFrameBuffer") ) )
{
FrameBufferImage fb = GetFrameBufferImage( *s, constant );
if(fb)
}
}
- if( OptionalString s = constant.IsString( IsChild(node, "screen-to-frame-buffer-function") ) )
+ if( OptionalString s = constant.IsString( IsChild(node, "screenToFrameBufferFunction") ) )
{
if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s)
{
}
// other setup is via the property system
- SetProperties( node, task, constant ); // @ todo, remove 'source-actor', 'camera-actor'?
-
+ SetProperties( node, task, constant );
}
void Builder::CreateRenderTask( const std::string &name )
const Stage& stage = Stage::GetCurrent();
- OptionalChild tasks = IsChild(*mParser.GetRoot(), "render-tasks");
+ OptionalChild tasks = IsChild(*mParser.GetRoot(), "renderTasks");
if(tasks)
{
}
}
-ShaderEffect Builder::GetShaderEffect( const std::string &name)
-{
- Replacement constant( mReplacementMap );
- return GetShaderEffect( name, constant );
-}
-
-ShaderEffect Builder::GetShaderEffect( const std::string &name, const Replacement& constant )
-{
- DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
-
- ShaderEffect ret;
-
- ShaderEffectLut::const_iterator iter( mShaderEffectLut.find( name ) );
- if( iter != mShaderEffectLut.end() )
- {
- ret = iter->second;
- }
- else
- {
- if( OptionalChild effects = IsChild( *mParser.GetRoot(), "shader-effects") )
- {
- if( OptionalChild effect = IsChild( *effects, name ) )
- {
- Dali::Property::Value propertyMap(Property::MAP);
- if( SetPropertyFromNode( *effect, Property::MAP, propertyMap, constant ) )
- {
- ret = Dali::Scripting::NewShaderEffect( propertyMap );
- mShaderEffectLut[ name ] = ret;
- }
- }
- }
- }
-
- return ret;
-}
-
FrameBufferImage Builder::GetFrameBufferImage( const std::string &name )
{
Replacement constant( mReplacementMap );
}
else
{
- if( OptionalChild images = IsChild( *mParser.GetRoot(), "frame-buffer-images") )
+ if( OptionalChild images = IsChild( *mParser.GetRoot(), "frameBufferImages") )
{
if( OptionalChild image = IsChild( *images, name ) )
{
Dali::Property::Value property(Property::MAP);
- if( SetPropertyFromNode( *image, Property::MAP, property, constant ) )
+ if( DeterminePropertyFromNode( *image, Property::MAP, property, constant ) )
{
Property::Map* map = property.GetMap();
if( OptionalChild pointsProperty = IsChild( *path, "points") )
{
Dali::Property::Value points(Property::ARRAY);
- if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+ if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
{
ret = Path::New();
ret.SetProperty( Path::Property::POINTS, points);
- //control-points property
- if( OptionalChild pointsProperty = IsChild( *path, "control-points") )
+ //controlPoints property
+ if( OptionalChild pointsProperty = IsChild( *path, "controlPoints") )
{
Dali::Property::Value points(Property::ARRAY);
- if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+ if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
{
ret.SetProperty( Path::Property::CONTROL_POINTS, points);
}
if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "points") )
{
Dali::Property::Value points(Property::ARRAY);
- if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+ if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
{
ret = PathConstrainer::New();
ret.SetProperty( PathConstrainer::Property::POINTS, points);
- //control-points property
- if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "control-points") )
+ //controlPoints property
+ if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "controlPoints") )
{
Dali::Property::Value points(Property::ARRAY);
- if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+ if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
{
ret.SetProperty( PathConstrainer::Property::CONTROL_POINTS, points);
}
if( OptionalChild pointsProperty = IsChild( *linearConstrainer, "value") )
{
Dali::Property::Value points(Property::ARRAY);
- if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+ if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
{
ret = Dali::LinearConstrainer::New();
ret.SetProperty( LinearConstrainer::Property::VALUE, points);
- //control-points property
+ //controlPoints property
if( OptionalChild pointsProperty = IsChild( *linearConstrainer, "progress") )
{
Dali::Property::Value points(Property::ARRAY);
- if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+ if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
{
ret.SetProperty( LinearConstrainer::Property::PROGRESS, points);
}
bool Builder::IsLinearConstrainer( const std::string& name )
{
- //Search the LinearConstrainer in the LUT
+ // Search the LinearConstrainer in the LUT
size_t count( mLinearConstrainerLut.size() );
for( size_t i(0); i!=count; ++i )
{
// to add automatically
if( "stage" == sectionName )
{
- if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "render-tasks") )
+ if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "renderTasks") )
{
if( OptionalChild tasks = IsChild(*renderTasks, "stage") )
{
return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() );
}
+bool Builder::ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child )
+{
+ bool result = false;
+
+ switch( child.GetType() )
+ {
+ case Property::STRING:
+ {
+ std::string value;
+ if( child.Get( value ) )
+ {
+ std::string key;
+ if( GetMappingKey( value, key ) )
+ {
+ // Check key for cycles:
+ result=true;
+ for( KeyStack::iterator iter = keyStack.begin() ; iter != keyStack.end(); ++iter )
+ {
+ if( key.compare(*iter) == 0 )
+ {
+ // key is already in stack; stop.
+ DALI_LOG_WARNING("Detected cycle in stylesheet mapping table:%s\n", key.c_str());
+ child = Property::Value("");
+ result=false;
+ break;
+ }
+ }
+
+ if( result )
+ {
+ // The following call will overwrite the child with the value
+ // from the mapping.
+ RecursePropertyMap( mappingRoot, keyStack, key.c_str(), Property::NONE, child );
+ result = true;
+ }
+ }
+ }
+ break;
+ }
+
+ case Property::MAP:
+ {
+ Property::Map* map = child.GetMap();
+ if( map )
+ {
+ for( Property::Map::SizeType i=0; i < map->Count(); ++i )
+ {
+ Property::Value& child = map->GetValue(i);
+ ConvertChildValue(mappingRoot, keyStack, child);
+ }
+ }
+ break;
+ }
+
+ case Property::ARRAY:
+ {
+ Property::Array* array = child.GetArray();
+ if( array )
+ {
+ for( Property::Array::SizeType i=0; i < array->Count(); ++i )
+ {
+ Property::Value& child = array->GetElementAt(i);
+ ConvertChildValue(mappingRoot, keyStack, child);
+ }
+ }
+ break;
+ }
+
+ default:
+ // Ignore other types.
+ break;
+ }
+
+ return result;
+}
+
+bool Builder::RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value )
+{
+ Replacement replacer( mReplacementMap );
+ bool result = false;
+
+ keyStack.push_back( theKey );
+
+ for( TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter )
+ {
+ std::string aKey( (*iter).first );
+ if( aKey.compare( theKey ) == 0 )
+ {
+ if( propertyType == Property::NONE )
+ {
+ DeterminePropertyFromNode( (*iter).second, value, replacer );
+ result = true;
+ }
+ else
+ {
+ result = DeterminePropertyFromNode( (*iter).second, propertyType, value, replacer );
+ }
+
+ if( result )
+ {
+ ConvertChildValue(mappingRoot, keyStack, value);
+ }
+ break;
+ }
+ }
+ keyStack.pop_back();
+
+ return result;
+}
+
+
+bool Builder::GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value )
+{
+ KeyStack keyStack;
+ return RecursePropertyMap( mappingRoot, keyStack, theKey, propertyType, value );
+}
+
+
void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format )
{
// parser to get constants and includes only
parser.GetErrorDescription().c_str() );
DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
-
}
else
{
}
}
- DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
+ DUMP_PARSE_TREE(parser); // This macro only writes out if DEBUG is enabled and the "DUMP_TREE" constant is defined in the stylesheet.
+ DUMP_TEST_MAPPINGS(parser);
+ DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
}
void Builder::AddConstants( const Property::Map& map )
#if defined(DEBUG_ENABLED)
DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName());
#endif
- if( SetPropertyFromNode( (*iter).second, property, replacer ) )
- {
- intoMap[ (*iter).second.GetName() ] = property;
- }
- else
- {
- DALI_SCRIPT_WARNING("Cannot convert property for constant %s\n",
- (*iter).second.GetName() == NULL ? "no name?" : (*iter).second.GetName());
- }
+ DeterminePropertyFromNode( (*iter).second, property, replacer );
+ intoMap[ (*iter).second.GetName() ] = property;
}
}
}
mParser = Dali::Toolkit::JsonParser::New();
Property::Map defaultDirs;
- defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ] = DALI_IMAGE_DIR;
- defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ] = DALI_SOUND_DIR;
- defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ] = DALI_STYLE_DIR;
+ defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ] = DALI_IMAGE_DIR;
+ defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ] = DALI_SOUND_DIR;
+ defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ] = DALI_STYLE_DIR;
+ defaultDirs[ TOKEN_STRING(DALI_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR;
AddConstants( defaultDirs );
}