From 3dce4163d27820a63fedb91ad4628efc3f864152 Mon Sep 17 00:00:00 2001 From: David Steele Date: Wed, 8 Feb 2017 20:59:57 +0000 Subject: [PATCH] Reordered builder implementation ahead of rework Re-ordered methods in source file to match public header APIs, Re-ordered private methods in source/header file in a roughly top down invocation order. Expect new private methods to go at the end. Change-Id: Ib8d53cf7268f3ae64d858766fd461170baeee5e7 Signed-off-by: David Steele --- .../src/dali-toolkit-styling/theme2.json | 9 + .../src/dali-toolkit-styling/theme3.json | 10 + .../dali-toolkit-styling/utc-Dali-StyleManager.cpp | 117 ++ dali-toolkit/internal/builder/builder-impl.cpp | 1247 ++++++++++---------- dali-toolkit/internal/builder/builder-impl.h | 142 ++- 5 files changed, 844 insertions(+), 681 deletions(-) create mode 100644 automated-tests/src/dali-toolkit-styling/theme2.json create mode 100644 automated-tests/src/dali-toolkit-styling/theme3.json diff --git a/automated-tests/src/dali-toolkit-styling/theme2.json b/automated-tests/src/dali-toolkit-styling/theme2.json new file mode 100644 index 0000000..8ca44cd --- /dev/null +++ b/automated-tests/src/dali-toolkit-styling/theme2.json @@ -0,0 +1,9 @@ +{ + "styles": + { + "testbutton": + { + "backgroundColor":[1.0,1.0,0.0,1.0] + } + } +} diff --git a/automated-tests/src/dali-toolkit-styling/theme3.json b/automated-tests/src/dali-toolkit-styling/theme3.json new file mode 100644 index 0000000..68a292e --- /dev/null +++ b/automated-tests/src/dali-toolkit-styling/theme3.json @@ -0,0 +1,10 @@ +{ + "styles": + { + "testbutton": + { + "backgroundColor":[1.0,1.0,0.0,1.0] +// Deliberate Error: trailing comma + }, + }, +} diff --git a/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp b/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp index 8d93d9c..ff6e7df 100644 --- a/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp +++ b/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp @@ -33,6 +33,10 @@ namespace { const char* defaultTheme = "{\n" +" \"constants\":\n" +" {\n" +" \"CONFIG_SCRIPT_LOG_LEVEL\":\"NoLogging\"\n" +" },\n" " \"styles\":\n" " {\n" " \"textlabel\":\n" @@ -258,6 +262,10 @@ int UtcDaliStyleManagerApplyTheme(void) const char* json1 = "{\n" + " \"constants\":\n" + " {\n" + " \"CONFIG_SCRIPT_LOG_LEVEL\":\"Verbose\"\n" + " },\n" " \"styles\":\n" " {\n" " \"testbutton\":\n" @@ -362,6 +370,10 @@ int UtcDaliStyleManagerApplyDefaultTheme(void) const char* defaultTheme = "{\n" + " \"constants\":\n" + " {\n" + " \"CONFIG_SCRIPT_LOG_LEVEL\":\"Concise\"\n" + " },\n" " \"styles\":\n" " {\n" " \"testbutton\":\n" @@ -505,6 +517,10 @@ int UtcDaliStyleManagerApplyStyle(void) const char* json1 = "{\n" + " \"constants\":\n" + " {\n" + " \"CONFIG_SCRIPT_LOG_LEVEL\":\"General\"\n" + " },\n" " \"styles\":\n" " {\n" " \"testbutton\":\n" @@ -574,6 +590,107 @@ int UtcDaliStyleManagerApplyStyle(void) } +int UtcDaliStyleManagerIncludeStyleP(void) +{ + ToolkitTestApplication application; + + tet_infoline( "UtcDaliStyleManagerIncludeStyle - test that style sheet inclusion works" ); + + const char* json1 = + "{\n" + " \"includes\":\n" + " [\n" + " \"src/dali-toolkit-styling/theme2.json\"\n" + " ],\n" + " \"styles\":\n" + " {\n" + " \"testbutton\":\n" + " {\n" + " \"foregroundColor\":[0.0,0.0,1.0,1.0]\n" + " }\n" + " }\n" + "}\n"; + + // Add 2 buttons + Test::TestButton testButton = Test::TestButton::New(); + Test::TestButton testButton2 = Test::TestButton::New(); + Stage::GetCurrent().Add( testButton ); + Stage::GetCurrent().Add( testButton2 ); + StyleChangedSignalChecker styleChangedSignalHandler; + StyleManager styleManager = StyleManager::Get(); + + styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged); + + tet_infoline("Apply the style"); + + std::string themeFile("ThemeOne"); + Test::StyleMonitor::SetThemeFileOutput(themeFile, json1); + + styleManager.ApplyTheme(themeFile); + + // Render and notify + application.SendNotification(); + application.Render(); + + Property::Value themedBgColor( testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR) ); + Property::Value themedFgColor( testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR) ); + + DALI_TEST_EQUALS( themedBgColor, Property::Value(Color::YELLOW), 0.001, TEST_LOCATION ); + DALI_TEST_EQUALS( themedFgColor, Property::Value(Color::BLUE), 0.001, TEST_LOCATION ); + + END_TEST; +} + + +int UtcDaliStyleManagerIncludeStyleN(void) +{ + ToolkitTestApplication application; + + tet_infoline( "UtcDaliStyleManagerIncludeStyle - test that style sheet inclusion works, but included stylesheet is bad json" ); + + const char* json1 = + "{\n" + " \"includes\":\n" + " [\n" + " \"src/dali-toolkit-styling/theme3.json\"\n" + " ],\n" + " \"styles\":\n" + " {\n" + " \"testbutton\":\n" + " {\n" + " \"foregroundColor\":[0.0,0.0,1.0,1.0]\n" + " }\n" + " }\n" + "}\n"; + + // Add 2 buttons + Test::TestButton testButton = Test::TestButton::New(); + Test::TestButton testButton2 = Test::TestButton::New(); + Stage::GetCurrent().Add( testButton ); + Stage::GetCurrent().Add( testButton2 ); + StyleChangedSignalChecker styleChangedSignalHandler; + StyleManager styleManager = StyleManager::Get(); + + styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged); + + tet_infoline("Apply the style"); + + std::string themeFile("ThemeOne"); + Test::StyleMonitor::SetThemeFileOutput(themeFile, json1); + + try + { + styleManager.ApplyTheme(themeFile); + } + catch( Dali::DaliException& e ) + { + DALI_TEST_ASSERT( e, "!\"Cannot parse JSON\"", TEST_LOCATION ); + } + + END_TEST; +} + + int UtcDaliStyleManagerStyleChangedSignalFontFamily(void) { tet_infoline("Test that the StyleChange signal is fired when the font family is altered" ); diff --git a/dali-toolkit/internal/builder/builder-impl.cpp b/dali-toolkit/internal/builder/builder-impl.cpp index a7fabdf..fdf8d21 100644 --- a/dali-toolkit/internal/builder/builder-impl.cpp +++ b/dali-toolkit/internal/builder/builder-impl.cpp @@ -22,29 +22,29 @@ #include #include -#include +#include +#include +#include #include #include -#include -#include -#include -#include +#include #include +#include #include +#include // INTERNAL INCLUDES #include #include -#include -#include #include +#include +#include +#include #include #include #include -#include - namespace Dali { @@ -56,9 +56,12 @@ namespace Internal class Replacement; extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot, Builder* const builder ); + 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); + #if defined(DEBUG_ENABLED) Integration::Log::Filter* gFilterScript = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT"); #endif @@ -68,14 +71,14 @@ namespace #define TOKEN_STRING(x) #x -const std::string KEYNAME_STYLES = "styles"; -const std::string KEYNAME_TYPE = "type"; -const std::string KEYNAME_ACTORS = "actors"; -const std::string KEYNAME_SIGNALS = "signals"; -const std::string KEYNAME_NAME = "name"; -const std::string KEYNAME_TEMPLATES = "templates"; -const std::string KEYNAME_INCLUDES = "includes"; -const std::string KEYNAME_MAPPINGS = "mappings"; +const std::string KEYNAME_ACTORS = "actors"; +const std::string KEYNAME_INCLUDES = "includes"; +const std::string KEYNAME_MAPPINGS = "mappings"; +const std::string KEYNAME_NAME = "name"; +const std::string KEYNAME_SIGNALS = "signals"; +const std::string KEYNAME_STYLES = "styles"; +const std::string KEYNAME_TEMPLATES = "templates"; +const std::string KEYNAME_TYPE = "type"; const std::string PROPERTIES = "properties"; const std::string ANIMATABLE_PROPERTIES = "animatableProperties"; @@ -134,379 +137,228 @@ void CollectAllStyles( const TreeNode& stylesCollection, const TreeNode& style, } // namespace anon -/* - * Sets the handle properties found in the tree node - */ -void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant ) + +Builder::Builder() +: mSlotDelegate( this ) { - if( handle ) - { + mParser = Dali::Toolkit::JsonParser::New(); - for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter ) - { - const TreeNode::KeyNodePair& keyChild = *iter; + 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_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR; - std::string key( keyChild.first ); + AddConstants( defaultDirs ); +} - // ignore special fields; type,actors,signals,styles - if(key == KEYNAME_TYPE || key == KEYNAME_ACTORS || key == KEYNAME_SIGNALS || key == KEYNAME_STYLES || key == KEYNAME_MAPPINGS ) - { - continue; - } +void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format ) +{ + // parser to get constants and includes only + Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New(); - Handle propertyObject( handle ); + if( !parser.Parse( data ) ) + { + DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", + parser.GetErrorLineNumber(), + parser.GetErrorColumn(), + parser.GetErrorDescription().c_str() ); - Dali::Property::Index index = propertyObject.GetPropertyIndex( key ); + DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); + } + else + { + // load constant map (allows the user to override the constants in the json after loading) + LoadConstants( *parser.GetRoot(), mReplacementMap ); - if( Property::INVALID_INDEX != index ) + // merge includes + if( OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES) ) + { + Replacement replacer( mReplacementMap ); + + for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter) { - Property::Type type = propertyObject.GetPropertyType(index); - Property::Value value; - bool mapped = false; + OptionalString filename = replacer.IsString( (*iter).second ); - // if node.value is a mapping, get the property value from the "mappings" table - if( keyChild.second.GetType() == TreeNode::STRING ) - { - std::string mappingKey; - if( GetMappingKey(keyChild.second.GetString(), mappingKey) ) - { - OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS ); - mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value ); - } - } - if( ! mapped ) - { - 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 ); - } - } - if( mapped ) + if( filename ) { - DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() ); - - propertyObject.SetProperty( index, value ); +#if defined(DEBUG_ENABLED) + DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str()); +#endif + LoadFromString( GetFileContents(*filename) ); } } - else - { - DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str()); - } + } - // Add custom properties - SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE); - SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE); + if( !mParser.Parse( data ) ) + { + DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", + mParser.GetErrorLineNumber(), + mParser.GetErrorColumn(), + mParser.GetErrorDescription().c_str() ); - } // for property nodes - } - else - { - DALI_SCRIPT_WARNING("Style applied to empty handle\n"); + DALI_ASSERT_ALWAYS(!"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::SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant, - const std::string& childName, Property::AccessMode accessMode ) +void Builder::AddConstants( const Property::Map& map ) { - // 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 ); + mReplacementMap.Merge( map ); +} - Property::Value value; - DeterminePropertyFromNode( keyChild.second, value, constant ); - // Register/Set property. - handle.RegisterProperty( key, value, accessMode ); - } - } +void Builder::AddConstant( const std::string& key, const Property::Value& value ) +{ + mReplacementMap[key] = value; } -// Set properties from node on handle. -void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ) +const Property::Map& Builder::GetConstants() const { - if( Actor actor = Actor::DownCast(handle) ) - { - SetProperties( node, actor, constant ); + return mReplacementMap; +} - if( actor ) - { - // add signals - SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); - SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); - } +const Property::Value& Builder::GetConstant( const std::string& key ) const +{ + Property::Value* match = mReplacementMap.Find( key ); + if( match ) + { + return (*match); } else { - SetProperties( node, handle, constant ); + static Property::Value invalid; + return invalid; } } -// Appling by style helper -// use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node -void Builder::ApplyStylesByActor( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ) +Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor ) { - if( Dali::Actor actor = Dali::Actor::DownCast( handle ) ) - { - if( const TreeNode* actors = node.GetChild( KEYNAME_ACTORS ) ) - { - // in a style the actor subtree properties referenced by actor name - for( TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter ) - { - Dali::Actor foundActor; - - if( (*iter).first ) - { - foundActor = actor.FindChildByName( (*iter).first ); - } - - if( !foundActor ) - { - // debug log cannot find searched for actor -#if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first); -#endif - } - else - { -#if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first); -#endif - ApplyProperties( root, (*iter).second, foundActor, constant ); - } - } - } - } + Replacement replacement(map, mReplacementMap); + return CreateAnimation( animationName, replacement, sourceActor); } - -void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ) +Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map ) { - OptionalChild styles = IsChild(root, KEYNAME_STYLES); - OptionalChild style = IsChild(node, KEYNAME_STYLES); + Replacement replacement(map, mReplacementMap); + return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() ); +} - if( styles && style ) - { - TreeNodeList additionalStyles; +Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor ) +{ + Replacement replacement( mReplacementMap ); - CollectAllStyles( *styles, *style, additionalStyles ); + return CreateAnimation( animationName, replacement, sourceActor ); +} -#if defined(DEBUG_ENABLED) - for(TreeNode::ConstIterator iter = (*style).CBegin(); iter != (*style).CEnd(); ++iter) - { - if( OptionalString styleName = IsString( (*iter).second ) ) - { - DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str()); - } - } -#endif +Animation Builder::CreateAnimation( const std::string& animationName ) +{ + Replacement replacement( mReplacementMap ); - // a style may have other styles, which has other styles etc so we apply in reverse by convention. - for(TreeNodeList::reverse_iterator iter = additionalStyles.rbegin(); iter != additionalStyles.rend(); ++iter) - { - ApplyProperties( root, *(*iter), handle, constant ); + return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() ); +} - ApplyStylesByActor( root, *(*iter), handle, constant ); - } - } - - // applying given node last - ApplyProperties( root, node, handle, constant ); - - ApplyStylesByActor( root, node, handle, constant ); +BaseHandle Builder::Create( const std::string& templateName ) +{ + Replacement replacement( mReplacementMap ); + return Create( templateName, replacement ); +} +BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map ) +{ + Replacement replacement( map, mReplacementMap ); + return Create( templateName, replacement ); } - -/* - * 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 Builder::DoCreate( const TreeNode& root, const TreeNode& node, - Actor parent, const Replacement& replacements ) +BaseHandle Builder::CreateFromJson( const std::string& json ) { - BaseHandle baseHandle; - TypeInfo typeInfo; - const TreeNode* templateNode = NULL; - - if( OptionalString typeName = IsString(node, KEYNAME_TYPE) ) - { - typeInfo = TypeRegistry::Get().GetTypeInfo( *typeName ); - - if( !typeInfo ) - { - // a template name is also allowed inplace of the type name - OptionalChild templates = IsChild( root, KEYNAME_TEMPLATES); - - if( templates ) - { - if( OptionalChild isTemplate = IsChild( *templates, *typeName ) ) - { - templateNode = &(*isTemplate); + BaseHandle ret; - if( OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE) ) - { - typeInfo = TypeRegistry::Get().GetTypeInfo( *templateTypeName ); - } - } - } - } - } + // merge in new template, hoping no one else has one named '@temp@' + std::string newTemplate = + std::string("{\"templates\":{\"@temp@\":") + \ + json + \ + std::string("}}"); - if(!typeInfo) + if( mParser.Parse(newTemplate) ) { - DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName()); + Replacement replacement( mReplacementMap ); + ret = Create( "@temp@", replacement ); } - else - { - baseHandle = typeInfo.CreateInstance(); - Handle handle = Handle::DownCast(baseHandle); - Actor actor = Actor::DownCast(handle); - - if(handle) - { - - DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str()); - -#if defined(DEBUG_ENABLED) - if(handle) - { - DALI_SCRIPT_VERBOSE(" Is Handle Object=%d\n", (long*)handle.GetObjectPtr()); - DALI_SCRIPT_VERBOSE(" Is Handle Property Count=%d\n", handle.GetPropertyCount()); - } - if(actor) - { - DALI_SCRIPT_VERBOSE(" Is Actor id=%d\n", actor.GetId()); - } - - Toolkit::Control control = Toolkit::Control::DownCast(handle); - if(control) - { - DALI_SCRIPT_VERBOSE(" Is Control id=%d\n", actor.GetId()); - } -#endif // DEBUG_ENABLED + return ret; +} - if( templateNode ) - { - ApplyProperties( root, *templateNode, handle, replacements ); +bool Builder::ApplyFromJson( Handle& handle, const std::string& json ) +{ + bool ret = false; - if( OptionalChild actors = IsChild( *templateNode, KEYNAME_ACTORS ) ) - { - for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) - { - DoCreate( root, (*iter).second, actor, replacements ); - } - } - } + // merge new style, hoping no one else has one named '@temp@' + std::string newStyle = + std::string("{\"styles\":{\"@temp@\":") + \ + json + \ + std::string("}}"); - if( actor ) - { - // add children of all the styles - if( OptionalChild actors = IsChild( node, KEYNAME_ACTORS ) ) - { - for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) - { - DoCreate( root, (*iter).second, actor, replacements ); - } - } + if( mParser.Parse(newStyle) ) + { + Replacement replacement( mReplacementMap ); + ret = ApplyStyle( "@temp@", handle, replacement ); + } - // apply style on top as they need the children to exist - ApplyAllStyleProperties( root, node, actor, replacements ); + return ret; +} - // then add to parent - if( parent ) - { - parent.Add( actor ); - } - } - else - { - ApplyProperties( root, node, handle, replacements ); - } - } - else - { - DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str()); - } - } +bool Builder::ApplyStyle( const std::string& styleName, Handle& handle ) +{ + Replacement replacer( mReplacementMap ); + return ApplyStyle( styleName, handle, replacer ); +} - return baseHandle; +void Builder::AddActors( Actor toActor ) +{ + // 'stage' is the default/by convention section to add from + AddActors( "stage", toActor ); } -void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant ) +void Builder::AddActors( const std::string §ionName, Actor toActor ) { - const Stage& stage = Stage::GetCurrent(); - Layer root = stage.GetRootLayer(); + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - if( OptionalString s = constant.IsString( IsChild(node, "sourceActor") ) ) - { - Actor actor = root.FindChildByName(*s); - if(actor) - { - task.SetSourceActor( actor ); - } - else - { - DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str() ); - } - } + Property::Map overrideMap; + Replacement replacements(overrideMap, mReplacementMap); - if( OptionalString s = constant.IsString( IsChild(node, "cameraActor") ) ) - { - CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) ); - if(actor) - { - task.SetCameraActor( actor ); - } - else - { - DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str() ); - } - } + OptionalChild add = IsChild(*mParser.GetRoot(), sectionName); - if( OptionalString s = constant.IsString( IsChild(node, "targetFrameBuffer") ) ) + if( add ) { - FrameBufferImage fb = GetFrameBufferImage( *s, constant ); - if(fb) - { - task.SetTargetFrameBuffer( fb ); - } - else + for( TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter ) { - DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() ); + // empty actor adds directly to the stage + BaseHandle baseHandle = DoCreate( *mParser.GetRoot(), (*iter).second, Actor(), replacements ); + Actor actor = Actor::DownCast(baseHandle); + if(actor) + { + toActor.Add( actor ); + } } - } - if( OptionalString s = constant.IsString( IsChild(node, "screenToFrameBufferFunction") ) ) - { - if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s) - { - task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ); - } - else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s) - { - task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION ); - } - else + // if were adding the 'stage' section then also check for a render task called stage + // to add automatically + if( "stage" == sectionName ) { - DALI_SCRIPT_WARNING("todo"); + if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "renderTasks") ) + { + if( OptionalChild tasks = IsChild(*renderTasks, "stage") ) + { + CreateRenderTask( "stage" ); + } + } } } - - // other setup is via the property system - SetProperties( node, task, constant ); } void Builder::CreateRenderTask( const std::string &name ) @@ -741,6 +593,7 @@ PathConstrainer Builder::GetPathConstrainer( const std::string& name ) return ret; } + bool Builder::IsPathConstrainer( const std::string& name ) { size_t count( mPathConstrainerLut.size() ); @@ -877,47 +730,54 @@ void Builder::EmitQuitSignal() mQuitSignal.Emit(); } -void Builder::AddActors( Actor toActor ) +Builder::~Builder() { - // 'stage' is the default/by convention section to add from - AddActors( "stage", toActor ); } -void Builder::AddActors( const std::string §ionName, Actor toActor ) +void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap ) { - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - - Property::Map overrideMap; - Replacement replacements(overrideMap, mReplacementMap); - - OptionalChild add = IsChild(*mParser.GetRoot(), sectionName); + Replacement replacer(intoMap); - if( add ) + if( OptionalChild constants = IsChild(root, "constants") ) { - for( TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter ) + for(TreeNode::ConstIterator iter = (*constants).CBegin(); + iter != (*constants).CEnd(); ++iter) { - // empty actor adds directly to the stage - BaseHandle baseHandle = DoCreate( *mParser.GetRoot(), (*iter).second, Actor(), replacements ); - Actor actor = Actor::DownCast(baseHandle); - if(actor) + Dali::Property::Value property; + if( (*iter).second.GetName() ) { - toActor.Add( actor ); +#if defined(DEBUG_ENABLED) + DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName()); +#endif + DeterminePropertyFromNode( (*iter).second, property, replacer ); + intoMap[ (*iter).second.GetName() ] = property; } } + } - // if were adding the 'stage' section then also check for a render task called stage - // to add automatically - if( "stage" == sectionName ) +#if defined(DEBUG_ENABLED) + Property::Value* iter = intoMap.Find( "CONFIG_SCRIPT_LOG_LEVEL" ); + if( iter && iter->GetType() == Property::STRING ) + { + std::string logLevel( iter->Get< std::string >() ); + if( logLevel == "NoLogging" ) { - if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "renderTasks") ) - { - if( OptionalChild tasks = IsChild(*renderTasks, "stage") ) - { - CreateRenderTask( "stage" ); - } - } + 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 } Animation Builder::CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor ) @@ -945,286 +805,224 @@ Animation Builder::CreateAnimation( const std::string& animationName, const Repl return anim; } -Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor ) +BaseHandle Builder::Create( const std::string& templateName, const Replacement& constant ) { - Replacement replacement(map, mReplacementMap); - return CreateAnimation( animationName, replacement, sourceActor); -} + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); -Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map ) -{ - Replacement replacement(map, mReplacementMap); - return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() ); -} + BaseHandle baseHandle; -Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor ) -{ - Replacement replacement( mReplacementMap ); + OptionalChild templates = IsChild(*mParser.GetRoot(), KEYNAME_TEMPLATES); - return CreateAnimation( animationName, replacement, sourceActor ); -} + if( !templates ) + { + DALI_SCRIPT_WARNING("No template section found to CreateFromTemplate\n"); + } + else + { + OptionalChild childTemplate = IsChild(*templates, templateName); + if(!childTemplate) + { + DALI_SCRIPT_WARNING("Template '%s' does not exist in template section\n", templateName.c_str()); + } + else + { + OptionalString type = constant.IsString( IsChild(*childTemplate, KEYNAME_TYPE) ); -Animation Builder::CreateAnimation( const std::string& animationName ) -{ - Replacement replacement( mReplacementMap ); + if(!type) + { + DALI_SCRIPT_WARNING("Cannot create template '%s' as template section is missing 'type'\n", templateName.c_str()); + } + else + { + baseHandle = DoCreate( *mParser.GetRoot(), *childTemplate, Actor(), constant ); + } + } + } - return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() ); + return baseHandle; } -bool Builder::ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child ) +/* + * 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 Builder::DoCreate( const TreeNode& root, const TreeNode& node, + Actor parent, const Replacement& replacements ) { - bool result = false; + BaseHandle baseHandle; + TypeInfo typeInfo; + const TreeNode* templateNode = NULL; - switch( child.GetType() ) + if( OptionalString typeName = IsString(node, KEYNAME_TYPE) ) { - case Property::STRING: + typeInfo = TypeRegistry::Get().GetTypeInfo( *typeName ); + + if( !typeInfo ) { - std::string value; - if( child.Get( value ) ) + // a template name is also allowed inplace of the type name + OptionalChild templates = IsChild( root, KEYNAME_TEMPLATES); + + if( templates ) { - std::string key; - if( GetMappingKey( value, key ) ) + if( OptionalChild isTemplate = IsChild( *templates, *typeName ) ) { - // 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; - } - } + templateNode = &(*isTemplate); - if( result ) + if( OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE) ) { - // The following call will overwrite the child with the value - // from the mapping. - RecursePropertyMap( mappingRoot, keyStack, key.c_str(), Property::NONE, child ); - result = true; + typeInfo = TypeRegistry::Get().GetTypeInfo( *templateTypeName ); } } } - break; } + } - case Property::MAP: + if(!typeInfo) + { + DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName()); + } + else + { + baseHandle = typeInfo.CreateInstance(); + Handle handle = Handle::DownCast(baseHandle); + Actor actor = Actor::DownCast(handle); + + if(handle) { - Property::Map* map = child.GetMap(); - if( map ) + + DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str()); + +#if defined(DEBUG_ENABLED) + if(handle) { - for( Property::Map::SizeType i=0; i < map->Count(); ++i ) - { - Property::Value& child = map->GetValue(i); - ConvertChildValue(mappingRoot, keyStack, child); - } + DALI_SCRIPT_VERBOSE(" Is Handle Object=%d\n", (long*)handle.GetObjectPtr()); + DALI_SCRIPT_VERBOSE(" Is Handle Property Count=%d\n", handle.GetPropertyCount()); } - break; - } - case Property::ARRAY: - { - Property::Array* array = child.GetArray(); - if( array ) + if(actor) { - for( Property::Array::SizeType i=0; i < array->Count(); ++i ) - { - Property::Value& child = array->GetElementAt(i); - ConvertChildValue(mappingRoot, keyStack, child); - } + DALI_SCRIPT_VERBOSE(" Is Actor id=%d\n", actor.GetId()); } - break; - } - default: - // Ignore other types. - break; - } - - return result; -} + Toolkit::Control control = Toolkit::Control::DownCast(handle); + if(control) + { + DALI_SCRIPT_VERBOSE(" Is Control id=%d\n", actor.GetId()); + } +#endif // DEBUG_ENABLED -bool Builder::RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value ) -{ - Replacement replacer( mReplacementMap ); - bool result = false; + if( templateNode ) + { + ApplyProperties( root, *templateNode, handle, replacements ); - keyStack.push_back( theKey ); + if( OptionalChild actors = IsChild( *templateNode, KEYNAME_ACTORS ) ) + { + for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) + { + DoCreate( root, (*iter).second, actor, replacements ); + } + } + } - for( TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter ) - { - std::string aKey( (*iter).first ); - if( aKey.compare( theKey ) == 0 ) - { - if( propertyType == Property::NONE ) + if( actor ) { - DeterminePropertyFromNode( (*iter).second, value, replacer ); - result = true; + // add children of all the styles + if( OptionalChild actors = IsChild( node, KEYNAME_ACTORS ) ) + { + for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) + { + DoCreate( root, (*iter).second, actor, replacements ); + } + } + + // apply style on top as they need the children to exist + ApplyAllStyleProperties( root, node, actor, replacements ); + + // then add to parent + if( parent ) + { + parent.Add( actor ); + } } else { - result = DeterminePropertyFromNode( (*iter).second, propertyType, value, replacer ); - } - - if( result ) - { - ConvertChildValue(mappingRoot, keyStack, value); + ApplyProperties( root, node, handle, replacements ); } - break; + } + else + { + DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str()); } } - 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 ); + return baseHandle; } - -void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format ) +void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant ) { - // parser to get constants and includes only - Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New(); + const Stage& stage = Stage::GetCurrent(); + Layer root = stage.GetRootLayer(); - if( !parser.Parse( data ) ) + if( OptionalString s = constant.IsString( IsChild(node, "sourceActor") ) ) { - DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", - parser.GetErrorLineNumber(), - parser.GetErrorColumn(), - parser.GetErrorDescription().c_str() ); - - DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); - } - else - { - // load constant map (allows the user to override the constants in the json after loading) - LoadConstants( *parser.GetRoot(), mReplacementMap ); - - // merge includes - if( OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES) ) + Actor actor = root.FindChildByName(*s); + if(actor) { - Replacement replacer( mReplacementMap ); - - for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter) - { - OptionalString filename = replacer.IsString( (*iter).second ); - - if( filename ) - { -#if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str()); -#endif - LoadFromString( GetFileContents(*filename) ); - } - } + task.SetSourceActor( actor ); } - - if( !mParser.Parse( data ) ) + else { - DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", - mParser.GetErrorLineNumber(), - mParser.GetErrorColumn(), - mParser.GetErrorDescription().c_str() ); - - DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); + DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str() ); } } - 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 ) -{ - mReplacementMap.Merge( map ); -} - -void Builder::AddConstant( const std::string& key, const Property::Value& value ) -{ - mReplacementMap[key] = value; -} - -const Property::Map& Builder::GetConstants() const -{ - return mReplacementMap; -} - -const Property::Value& Builder::GetConstant( const std::string& key ) const -{ - Property::Value* match = mReplacementMap.Find( key ); - if( match ) - { - return (*match); - } - else + if( OptionalString s = constant.IsString( IsChild(node, "cameraActor") ) ) { - static Property::Value invalid; - return invalid; + CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) ); + if(actor) + { + task.SetCameraActor( actor ); + } + else + { + DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str() ); + } } -} -void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap ) -{ - Replacement replacer(intoMap); - - if( OptionalChild constants = IsChild(root, "constants") ) + if( OptionalString s = constant.IsString( IsChild(node, "targetFrameBuffer") ) ) { - for(TreeNode::ConstIterator iter = (*constants).CBegin(); - iter != (*constants).CEnd(); ++iter) + FrameBufferImage fb = GetFrameBufferImage( *s, constant ); + if(fb) { - 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 - DeterminePropertyFromNode( (*iter).second, property, replacer ); - intoMap[ (*iter).second.GetName() ] = property; - } + task.SetTargetFrameBuffer( fb ); + } + else + { + DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() ); } } -#if defined(DEBUG_ENABLED) - Property::Value* iter = intoMap.Find( "CONFIG_SCRIPT_LOG_LEVEL" ); - if( iter && iter->GetType() == Property::STRING ) + if( OptionalString s = constant.IsString( IsChild(node, "screenToFrameBufferFunction") ) ) { - std::string logLevel( iter->Get< std::string >() ); - if( logLevel == "NoLogging" ) - { - gFilterScript->SetLogLevel( Integration::Log::NoLogging ); - } - else if( logLevel == "Concise" ) + if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s) { - gFilterScript->SetLogLevel( Integration::Log::Concise ); + task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ); } - else if( logLevel == "General" ) + else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s) { - gFilterScript->SetLogLevel( Integration::Log::General ); + task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION ); } - else if( logLevel == "Verbose" ) + else { - gFilterScript->SetLogLevel( Integration::Log::Verbose ); + DALI_SCRIPT_WARNING("todo"); } } -#endif + // other setup is via the property system + SetProperties( node, task, constant ); } -bool Builder::ApplyStyle( const std::string& styleName, Handle& handle ) -{ - Replacement replacer( mReplacementMap ); - return ApplyStyle( styleName, handle, replacer ); -} bool Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement ) { @@ -1246,110 +1044,309 @@ bool Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Re } } -BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map ) +void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node, + Dali::Handle& handle, const Replacement& constant ) { - Replacement replacement( map, mReplacementMap ); - return Create( templateName, replacement ); -} + OptionalChild styles = IsChild(root, KEYNAME_STYLES); + OptionalChild style = IsChild(node, KEYNAME_STYLES); -BaseHandle Builder::Create( const std::string& templateName, const Replacement& constant ) -{ - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + if( styles && style ) + { + TreeNodeList additionalStyles; - BaseHandle baseHandle; + CollectAllStyles( *styles, *style, additionalStyles ); - OptionalChild templates = IsChild(*mParser.GetRoot(), KEYNAME_TEMPLATES); +#if defined(DEBUG_ENABLED) + for(TreeNode::ConstIterator iter = (*style).CBegin(); iter != (*style).CEnd(); ++iter) + { + if( OptionalString styleName = IsString( (*iter).second ) ) + { + DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str()); + } + } +#endif - if( !templates ) + // a style may have other styles, which has other styles etc so we apply in reverse by convention. + for(TreeNodeList::reverse_iterator iter = additionalStyles.rbegin(); iter != additionalStyles.rend(); ++iter) + { + ApplyProperties( root, *(*iter), handle, constant ); + ApplyStylesByActor( root, *(*iter), handle, constant ); + } + } + + // applying given node last + ApplyProperties( root, node, handle, constant ); + ApplyStylesByActor( root, node, handle, constant ); +} + +// Set properties from node on handle. +void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node, + Dali::Handle& handle, const Replacement& constant ) +{ + if( Actor actor = Actor::DownCast(handle) ) { - DALI_SCRIPT_WARNING("No template section found to CreateFromTemplate\n"); + SetProperties( node, actor, constant ); + + if( actor ) + { + // add signals + SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); + SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); + } } else { - OptionalChild childTemplate = IsChild(*templates, templateName); - if(!childTemplate) + SetProperties( node, handle, constant ); + } +} + +// Appling by style helper +// use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node +void Builder::ApplyStylesByActor( const TreeNode& root, const TreeNode& node, + Dali::Handle& handle, const Replacement& constant ) +{ + if( Dali::Actor actor = Dali::Actor::DownCast( handle ) ) + { + if( const TreeNode* actors = node.GetChild( KEYNAME_ACTORS ) ) { - DALI_SCRIPT_WARNING("Template '%s' does not exist in template section\n", templateName.c_str()); + // in a style the actor subtree properties referenced by actor name + for( TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter ) + { + Dali::Actor foundActor; + + if( (*iter).first ) + { + foundActor = actor.FindChildByName( (*iter).first ); + } + + if( !foundActor ) + { + // debug log cannot find searched for actor +#if defined(DEBUG_ENABLED) + DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first); +#endif + } + else + { +#if defined(DEBUG_ENABLED) + DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first); +#endif + ApplyProperties( root, (*iter).second, foundActor, constant ); + } + } } - else + } +} + +/* + * Sets the handle properties found in the tree node + */ +void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant ) +{ + if( handle ) + { + for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter ) { - OptionalString type = constant.IsString( IsChild(*childTemplate, KEYNAME_TYPE) ); + const TreeNode::KeyNodePair& keyChild = *iter; - if(!type) + std::string key( keyChild.first ); + + // ignore special fields; + if( key == KEYNAME_TYPE || key == KEYNAME_ACTORS || key == KEYNAME_SIGNALS || key == KEYNAME_STYLES || key == KEYNAME_MAPPINGS ) { - DALI_SCRIPT_WARNING("Cannot create template '%s' as template section is missing 'type'\n", templateName.c_str()); + continue; + } + + Handle propertyObject( handle ); + + Dali::Property::Index index = propertyObject.GetPropertyIndex( key ); + + if( Property::INVALID_INDEX != index ) + { + 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 ) + { + std::string mappingKey; + if( GetMappingKey(keyChild.second.GetString(), mappingKey) ) + { + OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS ); + mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value ); + } + } + if( ! mapped ) + { + 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 ); + } + } + 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() ); + + propertyObject.SetProperty( index, value ); + } } else { - baseHandle = DoCreate( *mParser.GetRoot(), *childTemplate, Actor(), constant ); + DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str()); } - } + + // Add custom properties + SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE); + SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE); + + } // for property nodes } + else + { + DALI_SCRIPT_WARNING("Style applied to empty handle\n"); + } +} - return baseHandle; +bool Builder::GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value ) +{ + KeyStack keyStack; + return RecursePropertyMap( mappingRoot, keyStack, theKey, propertyType, value ); } -BaseHandle Builder::CreateFromJson( const std::string& json ) +bool Builder::RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value ) { - BaseHandle ret; + Replacement replacer( mReplacementMap ); + bool result = false; - // merge in new template, hoping no one else has one named '@temp@' - std::string newTemplate = - std::string("{\"templates\":{\"@temp@\":") + \ - json + \ - std::string("}}"); + keyStack.push_back( theKey ); - if( mParser.Parse(newTemplate) ) + for( TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter ) { - Replacement replacement( mReplacementMap ); - ret = Create( "@temp@", replacement ); + 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 ret; + return result; } -bool Builder::ApplyFromJson( Handle& handle, const std::string& json ) +bool Builder::ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child ) { - bool ret = false; - - // merge new style, hoping no one else has one named '@temp@' - std::string newStyle = - std::string("{\"styles\":{\"@temp@\":") + \ - json + \ - std::string("}}"); + bool result = false; - if( mParser.Parse(newStyle) ) + switch( child.GetType() ) { - Replacement replacement( mReplacementMap ); - ret = ApplyStyle( "@temp@", handle, replacement ); - } - - return ret; -} + 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; + } -BaseHandle Builder::Create( const std::string& templateName ) -{ - Replacement replacement( mReplacementMap ); - return Create( templateName, replacement ); -} + 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; + } -Builder::Builder() -: mSlotDelegate( this ) -{ - mParser = Dali::Toolkit::JsonParser::New(); + 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; + } - 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_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR; + default: + // Ignore other types. + break; + } - AddConstants( defaultDirs ); + return result; } -Builder::~Builder() +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 ); + } + } } } // namespace Internal diff --git a/dali-toolkit/internal/builder/builder-impl.h b/dali-toolkit/internal/builder/builder-impl.h index 4c018aa..3051917 100644 --- a/dali-toolkit/internal/builder/builder-impl.h +++ b/dali-toolkit/internal/builder/builder-impl.h @@ -28,6 +28,7 @@ #include #include #include +#include #include // INTERNAL INCLUDES @@ -219,94 +220,123 @@ protected: virtual ~Builder(); private: - // Undefined - Builder(const Builder&); - Builder& operator=(const Builder& rhs); - - void SetupTask( RenderTask& task, const Toolkit::TreeNode& node, const Replacement& replacement ); - - void SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant, const std::string& childName, Property::AccessMode accessMode ); - -private: - Toolkit::JsonParser mParser; - - typedef std::map ImageLut; - ImageLut mFrameBufferImageLut; - - typedef std::map PathLut; - PathLut mPathLut; - + typedef std::vector KeyStack; + typedef std::vector< TreeNode::KeyNodePair > MappingsLut; + typedef struct{ std::string name; Dali::LinearConstrainer linearConstrainer; } LinearConstrainerEntry; + typedef std::vector LinearConstrainerLut; typedef struct{ std::string name; Dali::PathConstrainer pathConstrainer; } PathConstrainerEntry; typedef std::vector PathConstrainerLut; - PathConstrainerLut mPathConstrainerLut; + typedef std::map PathLut; + typedef std::map ImageLut; - typedef struct{ std::string name; Dali::LinearConstrainer linearConstrainer; } LinearConstrainerEntry; - typedef std::vector LinearConstrainerLut; - LinearConstrainerLut mLinearConstrainerLut; +private: + // Undefined + Builder(const Builder&); - SlotDelegate mSlotDelegate; + // Undefined + Builder& operator=(const Builder& rhs); - Property::Map mReplacementMap; + void LoadConstants( const TreeNode& root, Property::Map& intoMap ); - typedef std::vector< TreeNode::KeyNodePair > MappingsLut; - MappingsLut mCompleteMappings; + Animation CreateAnimation( const std::string& animationName, + const Replacement& replacement, + Dali::Actor sourceActor ); - BaseHandle Create( const std::string& templateName, const Replacement& constant ); + BaseHandle Create( const std::string& templateName, + const Replacement& constant ); - BaseHandle DoCreate( const TreeNode& root, const TreeNode& node, Actor parent, const Replacement& replacements ); + BaseHandle DoCreate( const TreeNode& root, + const TreeNode& node, + Actor parent, + const Replacement& replacements ); - void LoadConstants( const TreeNode& root, Property::Map& intoMap ); + void SetupTask( RenderTask& task, + const Toolkit::TreeNode& node, + const Replacement& replacement ); - void LoadIncludes( const std::string& data ); + bool ApplyStyle( const std::string& styleName, + Handle& handle, + const Replacement& replacement); - bool ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement); + void ApplyAllStyleProperties( const TreeNode& root, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& constant ); - Animation CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor ); + void ApplyProperties( const TreeNode& root, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& constant ); - typedef std::vector KeyStack; + void ApplyStylesByActor( const TreeNode& root, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& constant ); + + void SetProperties( const TreeNode& node, + Handle& handle, + const Replacement& constant ); /** - * Tests if the value is a string delimited by <>. If it is, then it attempts to - * change the value to the mapping from a matching key in the mappings table. + * Find the key in the mapping table, if it's present, then generate + * a property value for it (of the given type if available), + * recursing as necessary, and stopping if any cycles are detected. + * * @param[in] mappingRoot The JSON node containing the mappings - * @param[in,out] keyStack the stack of visited keys + * @param[in] theKey The key to search for + * @param[in] propertyType The property type if known, or NONE * @param[in,out] value The string value to test and write back to. - * @return true if the value was converted, false otherwise. */ - bool ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& value ); + bool GetPropertyMap( const TreeNode& mappingRoot, + const char* theKey, + Property::Type propertyType, + Property::Value& value ); + + void SetCustomProperties( const TreeNode& node, + Handle& handle, + const Replacement& constant, + const std::string& childName, + Property::AccessMode accessMode ); /** - * Find the key in the mapping table, if it's present, then generate a property value for it (of the given type if available), recursing as necessary, and stopping if any cycles - * are detected. + * Find the key in the mapping table, if it's present, then generate + * a property value for it (of the given type if available), + * recursing as necessary, and stopping if any cycles are detected. + * * @param[in] mappingRoot The JSON node containing the mappings * @param[in] theKey The key to search for * @param[in,out] keyStack the stack of visited keys * @param[in] propertyType The property type if known, or NONE * @param[in,out] value The string value to test and write back to. */ - bool RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value ); + bool RecursePropertyMap( const TreeNode& mappingRoot, + KeyStack& keyStack, + const char* theKey, + Property::Type propertyType, + Property::Value& value ); + /** - * Find the key in the mapping table, if it's present, then generate a property value for it (of the given type if available), recursing as necessary, and stopping if any cycles - * are detected. + * Tests if the value is a string delimited by <>. If it is, then it attempts to + * change the value to the mapping from a matching key in the mappings table. * @param[in] mappingRoot The JSON node containing the mappings - * @param[in] theKey The key to search for - * @param[in] propertyType The property type if known, or NONE + * @param[in,out] keyStack the stack of visited keys * @param[in,out] value The string value to test and write back to. + * @return true if the value was converted, false otherwise. */ - bool GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value ); - - void ApplyProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ); - - void ApplyStylesByActor( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ); - - void ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ); - - void SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant ); + bool ConvertChildValue( const TreeNode& mappingRoot, + KeyStack& keyStack, + Property::Value& value ); +private: + Toolkit::JsonParser mParser; + ImageLut mFrameBufferImageLut; + PathLut mPathLut; + PathConstrainerLut mPathConstrainerLut; + LinearConstrainerLut mLinearConstrainerLut; + SlotDelegate mSlotDelegate; + Property::Map mReplacementMap; + MappingsLut mCompleteMappings; Toolkit::Builder::BuilderSignalType mQuitSignal; }; -- 2.7.4