From af74001e7e61033e86323da5ad079ccbc310680a Mon Sep 17 00:00:00 2001 From: Lee Morgan Date: Fri, 4 Apr 2014 15:01:53 +0100 Subject: [PATCH] Builder templated constant expansion [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 --- .../dali-test-suite/builder/utc-Dali-Builder.cpp | 117 +++- .../internal/builder/builder-animations.cpp | 91 ++- dali-toolkit/internal/builder/builder-impl.cpp | 397 +++++++++++-- dali-toolkit/internal/builder/builder-impl.h | 56 +- .../internal/builder/builder-set-property.cpp | 139 +++-- dali-toolkit/internal/builder/builder-signals.cpp | 1 + .../internal/builder/json-parser-state.cpp | 2 + dali-toolkit/internal/builder/replacement.cpp | 635 +++++++++++++++++++++ dali-toolkit/internal/builder/replacement.h | 248 ++++++++ dali-toolkit/internal/file.list | 1 + dali-toolkit/public-api/builder/builder.cpp | 15 + dali-toolkit/public-api/builder/builder.h | 55 +- 12 files changed, 1634 insertions(+), 123 deletions(-) mode change 100755 => 100644 dali-toolkit/internal/builder/builder-impl.cpp create mode 100644 dali-toolkit/internal/builder/replacement.cpp create mode 100644 dali-toolkit/internal/builder/replacement.h diff --git a/automated-tests/dali-test-suite/builder/utc-Dali-Builder.cpp b/automated-tests/dali-test-suite/builder/utc-Dali-Builder.cpp index 926e85f..15c93a4 100644 --- a/automated-tests/dali-test-suite/builder/utc-Dali-Builder.cpp +++ b/automated-tests/dali-test-suite/builder/utc-Dali-Builder.cpp @@ -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; diff --git a/dali-toolkit/internal/builder/builder-animations.cpp b/dali-toolkit/internal/builder/builder-animations.cpp index b8ea43e..82a0669 100644 --- a/dali-toolkit/internal/builder/builder-animations.cpp +++ b/dali-toolkit/internal/builder/builder-animations.cpp @@ -20,16 +20,17 @@ // INTERNAL INCLUDES #include #include +#include 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 diff --git a/dali-toolkit/internal/builder/builder-impl.cpp b/dali-toolkit/internal/builder/builder-impl.cpp old mode 100755 new mode 100644 index 83572ec..a301570 --- a/dali-toolkit/internal/builder/builder-impl.cpp +++ b/dali-toolkit/internal/builder/builder-impl.cpp @@ -29,6 +29,7 @@ #include #include #include +#include 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 TreeNodeList; +template +std::string ToString(const T& value) +{ + std::stringstream ss; + ss << value; + return ss.str(); +} + +template <> +std::string ToString(const Rect& 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() ? "True" : "False"; + break; + } + case Property::FLOAT: + { + + ret = ToString( value.Get() ); + break; + } + case Property::INTEGER: + { + ret = ToString( value.Get() ); + break; + } + case Property::UNSIGNED_INTEGER: + { + ret = ToString( value.Get() ); + break; + } + case Property::VECTOR2: + { + ret = ToString( value.Get() ); + break; + } + case Property::VECTOR3: + { + ret = ToString( value.Get() ); + break; + } + case Property::VECTOR4: + { + ret = ToString( value.Get() ); + break; + } + case Property::MATRIX3: + { + ret = ToString( value.Get() ); + break; + } + case Property::MATRIX: + { + ret = ToString( value.Get() ); + break; + } + case Property::RECTANGLE: + { + ret = ToString( value.Get< Rect >() ); + break; + } + case Property::ROTATION: + { + break; + } + case Property::STRING: + { + ret = value.Get(); + break; + } + case Property::ARRAY: + { + ret = std::string("Array Size=") + ToString( value.Get().size() ); + break; + } + case Property::MAP: + { + ret = std::string("Map Size=") + ToString( value.Get().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 §ionName, 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 §ionName, 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 §ionName, 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 ) { diff --git a/dali-toolkit/internal/builder/builder-impl.h b/dali-toolkit/internal/builder/builder-impl.h index ba52c08..7747b49 100644 --- a/dali-toolkit/internal/builder/builder-impl.h +++ b/dali-toolkit/internal/builder/builder-impl.h @@ -28,6 +28,7 @@ // INTERNAL INCLUDES #include #include +#include // 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 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 diff --git a/dali-toolkit/internal/builder/builder-set-property.cpp b/dali-toolkit/internal/builder/builder-set-property.cpp index 5b079bb..e0e98c8 100644 --- a/dali-toolkit/internal/builder/builder-set-property.cpp +++ b/dali-toolkit/internal/builder/builder-set-property.cpp @@ -17,6 +17,7 @@ // INTERNAL INCLUDES #include #include +#include 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) { diff --git a/dali-toolkit/internal/builder/builder-signals.cpp b/dali-toolkit/internal/builder/builder-signals.cpp index edf961f..0ab0e7b 100644 --- a/dali-toolkit/internal/builder/builder-signals.cpp +++ b/dali-toolkit/internal/builder/builder-signals.cpp @@ -289,6 +289,7 @@ boost::function GetAction(const TreeNode &root, const TreeNode &chi { DelayedAnimationPlay action; action.memento = Toolkit::JsonParser::New(*animNode); + // @todo; put constants into the map callback = action; } else diff --git a/dali-toolkit/internal/builder/json-parser-state.cpp b/dali-toolkit/internal/builder/json-parser-state.cpp index ca7b139..9b6fa4f 100644 --- a/dali-toolkit/internal/builder/json-parser-state.cpp +++ b/dali-toolkit/internal/builder/json-parser-state.cpp @@ -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 index 0000000..701b7c8 --- /dev/null +++ b/dali-toolkit/internal/builder/replacement.cpp @@ -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 +#include +#include + +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() + + 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(); + } + } + else + { + ret = ::IsBoolean( node ); + } + return ret; +} + +OptionalBoolean Replacement::IsBoolean( OptionalChild child ) const +{ + if( child ) + { + return IsBoolean( *child ); + } + else + { + return OptionalBoolean(); + } +} + +// template (*ISTYPE)( const TreeNode& node ), Property::Type TYPE> +// OptionalValue IsOfType( const TreeNode& node, const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap ) +// { +// OptionalValue ret; +// if( OptionalString replace = HasFullReplacement( node, overrideMap, defaultMap ) ) +// { +// Property::Value value = GetFullReplacement( *replace, overrideMap, defaultMap ); +// if( TYPE == value.GetType() ) +// { +// ret = value.Get(); +// } +// } +// else +// { +// ret = ISTYPE( node ); +// } +// return ret; + +// } + +// OptionalFloat Replacement::IsFloat( const TreeNode & node ) const +// { +// return IsOfType( node, *mOverrideMap, *mDefaultMap ); +// /* OptionalFloat ret; */ +// /* if( OptionalString replace = HasFullReplacement( node ) ) */ +// /* { */ +// /* Property::Value value = GetFullReplacement( replace ); */ +// /* if( Property::FLOAT == value.GetType() ) */ +// /* { */ +// /* ret = value.Get(); */ +// /* } */ +// /* } */ +// /* 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(); + } + } + 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(); +#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(); + } + } + 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(); + } + } + 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(); + } + } + 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(); + } + } + 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(); + } + } + 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(); + } + } + 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 >(); + } + } + 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 index 0000000..879c57c --- /dev/null +++ b/dali-toolkit/internal/builder/replacement.h @@ -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 +#include +#include + +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 diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index e0e8ebc..221e1b6 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -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 \ diff --git a/dali-toolkit/public-api/builder/builder.cpp b/dali-toolkit/public-api/builder/builder.cpp index 8613016..4a3fdfc 100644 --- a/dali-toolkit/public-api/builder/builder.cpp +++ b/dali-toolkit/public-api/builder/builder.cpp @@ -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 ); diff --git a/dali-toolkit/public-api/builder/builder.h b/dali-toolkit/public-api/builder/builder.h index 8df2619..abc5a26 100644 --- a/dali-toolkit/public-api/builder/builder.h +++ b/dali-toolkit/public-api/builder/builder.h @@ -31,6 +31,8 @@ namespace Internal DALI_INTERNAL class Builder; } +typedef std::map 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 -- 2.7.4