X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fbuilder%2Fbuilder-impl.cpp;h=73facc7abe90d43316dab7af147ee961ee683449;hp=202e94432057d5d7177d139573527ad4773325f2;hb=a97ac15ed81fec420ac3597a4b3c1da7565f6aeb;hpb=56d412791a44c2a79135d2293c13fddb135c9d54 diff --git a/dali-toolkit/internal/builder/builder-impl.cpp b/dali-toolkit/internal/builder/builder-impl.cpp index 202e944..73facc7 100644 --- a/dali-toolkit/internal/builder/builder-impl.cpp +++ b/dali-toolkit/internal/builder/builder-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,25 +20,30 @@ // EXTERNAL INCLUDES #include -#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 { @@ -51,13 +56,11 @@ namespace Internal class Replacement; extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot, Builder* const builder ); -extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value ); -extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value, const Replacement& replacements ); -extern bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value ); -extern bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value, const Replacement& replacements ); -extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function quitAction, Dali::Toolkit::Internal::Builder* const builder); -extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function quitAction, Dali::Toolkit::Internal::Builder* const builder); -extern Actor SetupActor( const TreeNode& node, Actor& actor, const Replacement& constant ); + +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"); @@ -66,128 +69,49 @@ Integration::Log::Filter* gFilterScript = Integration::Log::Filter::New(Debug:: namespace { -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"; +#define TOKEN_STRING(x) #x + +const std::string KEYNAME_ACTORS = "actors"; +const std::string KEYNAME_ENTRY_TRANSITION = "entryTransition"; +const std::string KEYNAME_EXIT_TRANSITION = "exitTransition"; +const std::string KEYNAME_INCLUDES = "includes"; +const std::string KEYNAME_INHERIT = "inherit"; +const std::string KEYNAME_MAPPINGS = "mappings"; +const std::string KEYNAME_NAME = "name"; +const std::string KEYNAME_SIGNALS = "signals"; +const std::string KEYNAME_STATES = "states"; +const std::string KEYNAME_STYLES = "styles"; +const std::string KEYNAME_TEMPLATES = "templates"; +const std::string KEYNAME_TRANSITIONS = "transitions"; +const std::string KEYNAME_TYPE = "type"; +const std::string KEYNAME_VISUALS = "visuals"; + +const std::string PROPERTIES = "properties"; +const std::string ANIMATABLE_PROPERTIES = "animatableProperties"; 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(); -} - -#if defined(DEBUG_ENABLED) -std::string PropertyValueToString( const Property::Value& value ) +bool GetMappingKey( const std::string& str, std::string& key ) { - std::string ret; - - switch( value.GetType() ) + bool result = false; + std::string test( str ); + if( ! test.empty() ) { - case Property::NONE: - { - ret = "NONE"; - break; - } ///< No type - case Property::BOOLEAN: - { - ret = value.Get() ? "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().Count() ); - break; - } - case Property::TYPE_COUNT: + if( test.at(0) == '<' ) { - ret = ""; - break; + if( test.at(test.length()-1) == '>' ) + { + key = test.substr( 1, test.length()-2 ); + result = true; + } } } - - return ret; + return result; } -#endif // DEBUG_ENABLED /* - * Recursively collects all stylesin a node (An array of style names). + * Recursively collects all styles in a node (An array of style names). * * stylesCollection The set of styles from the json file (a json object of named styles) * style The style array to begin the collection from @@ -202,11 +126,16 @@ void CollectAllStyles( const TreeNode& stylesCollection, const TreeNode& style, { if( OptionalString styleName = IsString( (*iter).second ) ) { - if( OptionalChild node = IsChild( stylesCollection, *styleName) ) + if( OptionalChild node = IsChildIgnoreCase( stylesCollection, *styleName) ) { styleList.push_back( &(*node) ); - if( OptionalChild subStyle = IsChild( *node, KEYNAME_STYLES ) ) + OptionalChild subStyle = IsChild( *node, KEYNAME_INHERIT ); + if( ! subStyle ) + { + subStyle = IsChild( *node, KEYNAME_STYLES ); + } + if( subStyle ) { CollectAllStyles( stylesCollection, *subStyle, styleList ); } @@ -216,422 +145,270 @@ void CollectAllStyles( const TreeNode& stylesCollection, const TreeNode& style, } } -struct QuitAction -{ -public: - QuitAction( Builder& builder ) - : mBuilder( builder ) - { - } - - void operator()(void) - { - mBuilder.EmitQuitSignal(); - } - -private: - Builder& mBuilder; -}; } // namespace anon -/* - * 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 ) - { - const TreeNode::KeyNodePair& keyChild = *iter; - - std::string key( keyChild.first ); - - // ignore special fields; type,actors,signals,styles - if(key == KEYNAME_TYPE || key == KEYNAME_ACTORS || key == KEYNAME_SIGNALS || key == KEYNAME_STYLES) - { - continue; - } - - // special field 'image' usually contains an json object description - // although sometimes refers to a framebuffer - if( 0 == keyChild.second.Size() ) - { - if(key == "image") - { - ImageActor imageActor = ImageActor::DownCast(handle); - if(imageActor) - { - if( OptionalString s = constant.IsString( keyChild.second ) ) - { - FrameBufferImage fb = GetFrameBufferImage(*s, constant); - if(fb) - { - imageActor.SetImage( fb ); - } - } - } - } - } - - // special field 'effect' references the shader effect instances - if(key == "effect") - { - RenderableActor actor = RenderableActor::DownCast(handle); - if( actor ) - { - OptionalString str = constant.IsString( keyChild.second ); - if( str ) - { - ShaderEffect effect = GetShaderEffect( *str, constant ); - actor.SetShaderEffect(effect); - } - } - else - { - DALI_SCRIPT_WARNING("Could not find or set shader effect\n"); - } - - continue; - } - - Handle propertyObject( handle ); - - Dali::Property::Index index = propertyObject.GetPropertyIndex( key ); - - if( Property::INVALID_INDEX == index ) - { - RenderableActor actor = RenderableActor::DownCast(handle); - if( actor ) - { - if( ShaderEffect effect = actor.GetShaderEffect() ) - { - index = effect.GetPropertyIndex( key ); - if(index != Property::INVALID_INDEX) - { - propertyObject = effect; - } - } - } - } - - if( Property::INVALID_INDEX != index ) - { - Property::Type type = propertyObject.GetPropertyType(index); - Property::Value 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 - DALI_SCRIPT_VERBOSE("Could not convert property:%s\n", key.c_str()); - } - else - { - DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() ); +Builder::Builder() +: mSlotDelegate( this ) +{ + mParser = Dali::Toolkit::JsonParser::New(); - propertyObject.SetProperty( index, value ); - } - } - else - { - DALI_SCRIPT_VERBOSE("SetProperty INVALID '%s' Index=:%d\n", key.c_str(), index); - } + 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; - } // for property nodes - } - else - { - DALI_SCRIPT_WARNING("Style applied to empty handle\n"); - } + AddConstants( defaultDirs ); } -// Set properties from node on handle. -void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ) +void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format ) { - if( Actor actor = Actor::DownCast(handle) ) - { - SetProperties( node, actor, constant ); + // parser to get constants and includes only + Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New(); - if( actor ) - { - SetupActor( node, actor, constant ); + if( !parser.Parse( data ) ) + { + DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", + parser.GetErrorLineNumber(), + parser.GetErrorColumn(), + parser.GetErrorDescription().c_str() ); - // add signals - QuitAction quitAction( *this ); - SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, quitAction, this ); - SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, quitAction, this ); - } + DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); } else { - 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 ) ) + // load constant map (allows the user to override the constants in the json after loading) + LoadConstants( *parser.GetRoot(), mReplacementMap ); + // load configuration map + LoadConfiguration( *parser.GetRoot(), mConfigurationMap ); + // merge includes + if( OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES) ) { - // in a style the actor subtree properties referenced by actor name - for( TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter ) - { - Dali::Actor foundActor; + Replacement replacer( mReplacementMap ); - if( (*iter).first ) - { - foundActor = actor.FindChildByName( (*iter).first ); - } + for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter) + { + OptionalString filename = replacer.IsString( (*iter).second ); - 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( filename ) { #if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first); + DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str()); #endif - ApplyProperties( root, (*iter).second, foundActor, constant ); + LoadFromString( GetFileContents(*filename) ); } } } - } -} - - -void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node, - Dali::Handle& handle, const Replacement& constant ) -{ - OptionalChild styles = IsChild(root, KEYNAME_STYLES); - OptionalChild style = IsChild(node, KEYNAME_STYLES); - - if( styles && style ) - { - TreeNodeList additionalStyles; - - CollectAllStyles( *styles, *style, additionalStyles ); -#if defined(DEBUG_ENABLED) - for(TreeNode::ConstIterator iter = (*style).CBegin(); iter != (*style).CEnd(); ++iter) + if( mParser.Parse( data ) ) { - if( OptionalString styleName = IsString( (*iter).second ) ) - { - DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str()); - } + // Drop the styles and get them to be rebuilt against the new parse tree as required. + mStyles.Clear(); } -#endif - - // 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) + else { - ApplyProperties( root, *(*iter), handle, constant ); + DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", + mParser.GetErrorLineNumber(), + mParser.GetErrorColumn(), + mParser.GetErrorDescription().c_str() ); - ApplyStylesByActor( root, *(*iter), handle, constant ); + DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); } } - // applying given node last - ApplyProperties( root, node, handle, constant ); + DUMP_PARSE_TREE(mParser); // This macro only writes out if DEBUG is enabled and the "DUMP_TREE" constant is defined in the stylesheet. + DUMP_TEST_MAPPINGS(mParser); - ApplyStylesByActor( root, node, handle, constant ); + 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; +} -/* - * 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 ) +const Property::Map& Builder::GetConfigurations() const { - BaseHandle baseHandle; - TypeInfo typeInfo; - const TreeNode* templateNode = NULL; + return mConfigurationMap; +} - 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); - - if( OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE) ) - { - typeInfo = TypeRegistry::Get().GetTypeInfo( *templateTypeName ); - } - } - } - } - } +const Property::Map& Builder::GetConstants() const +{ + return mReplacementMap; +} - if(!typeInfo) +const Property::Value& Builder::GetConstant( const std::string& key ) const +{ + Property::Value* match = mReplacementMap.Find( key ); + if( match ) { - DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName()); + return (*match); } else { - baseHandle = typeInfo.CreateInstance(); - Handle handle = Handle::DownCast(baseHandle); - Actor actor = Actor::DownCast(handle); + static Property::Value invalid; + return invalid; + } +} - if(handle) - { +Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor ) +{ + Replacement replacement(map, mReplacementMap); + return CreateAnimation( animationName, replacement, sourceActor); +} - DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str()); +Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map ) +{ + Replacement replacement(map, mReplacementMap); + return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() ); +} -#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()); - } +Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor ) +{ + Replacement replacement( mReplacementMap ); - if(actor) - { - DALI_SCRIPT_VERBOSE(" Is Actor id=%d\n", actor.GetId()); - } + return CreateAnimation( animationName, replacement, sourceActor ); +} - Toolkit::Control control = Toolkit::Control::DownCast(handle); - if(control) - { - DALI_SCRIPT_VERBOSE(" Is Control id=%d\n", actor.GetId()); - } -#endif // DEBUG_ENABLED +Animation Builder::CreateAnimation( const std::string& animationName ) +{ + Replacement replacement( mReplacementMap ); - if( templateNode ) - { - ApplyProperties( root, *templateNode, handle, replacements ); + return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() ); +} - if( OptionalChild actors = IsChild( *templateNode, KEYNAME_ACTORS ) ) - { - for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) - { - DoCreate( root, (*iter).second, actor, replacements ); - } - } - } +BaseHandle Builder::Create( const std::string& templateName ) +{ + Replacement replacement( mReplacementMap ); + return Create( templateName, replacement ); +} - if( actor ) - { - // TEMP: Assume all script created actors are not using size negotiation for now - actor.SetRelayoutEnabled( false ); +BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map ) +{ + Replacement replacement( map, mReplacementMap ); + return Create( templateName, replacement ); +} - // 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 ); - } - } +BaseHandle Builder::CreateFromJson( const std::string& json ) +{ + BaseHandle ret; - // apply style on top as they need the children to exist - ApplyAllStyleProperties( root, node, actor, replacements ); + // merge in new template, hoping no one else has one named '@temp@' + std::string newTemplate = + std::string("{\"templates\":{\"@temp@\":") + \ + json + \ + std::string("}}"); - // 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()); - } + if( mParser.Parse(newTemplate) ) + { + Replacement replacement( mReplacementMap ); + ret = Create( "@temp@", replacement ); } - return baseHandle; + return ret; } -void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant ) +bool Builder::ApplyFromJson( Handle& handle, const std::string& json ) { - const Stage& stage = Stage::GetCurrent(); - Layer root = stage.GetRootLayer(); + bool ret = false; + + // merge new style, hoping no one else has one named '@temp@' + std::string newStyle = + std::string("{\"styles\":{\"@temp@\":") + \ + json + \ + std::string("}}"); - if( OptionalString s = constant.IsString( IsChild(node, "source-actor") ) ) + if( mParser.Parse(newStyle) ) { - 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() ); - } + Replacement replacement( mReplacementMap ); + ret = ApplyStyle( "@temp@", handle, replacement ); } - if( OptionalString s = constant.IsString( IsChild(node, "camera-actor") ) ) + return ret; +} + +bool Builder::ApplyStyle( const std::string& styleName, Handle& handle ) +{ + Replacement replacer( mReplacementMap ); + return ApplyStyle( styleName, handle, replacer ); +} + +bool Builder::LookupStyleName( const std::string& styleName ) +{ + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + + OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES ); + OptionalChild style = IsChildIgnoreCase( *styles, styleName ); + + if( styles && style ) { - 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() ); - } + return true; } + return false; +} + +const StylePtr Builder::GetStyle( const std::string& styleName ) +{ + const StylePtr* style = mStyles.FindConst( styleName ); - if( OptionalString s = constant.IsString( IsChild(node, "target-frame-buffer") ) ) + if( style==NULL ) { - FrameBufferImage fb = GetFrameBufferImage( *s, constant ); - if(fb) - { - task.SetTargetFrameBuffer( fb ); - } - else - { - DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() ); - } + return StylePtr(NULL); + } + else + { + return *style; } +} + +void Builder::AddActors( Actor toActor ) +{ + // 'stage' is the default/by convention section to add from + AddActors( "stage", toActor ); +} + +void Builder::AddActors( const std::string §ionName, Actor toActor ) +{ + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + + Property::Map overrideMap; + Replacement replacements(overrideMap, mReplacementMap); + + OptionalChild add = IsChild(*mParser.GetRoot(), sectionName); - if( OptionalString s = constant.IsString( IsChild(node, "screen-to-frame-buffer-function") ) ) + if( add ) { - if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s) - { - task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ); - } - else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s) + for( TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter ) { - task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION ); + // 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 ); + } } - 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 ); // @ todo, remove 'source-actor', 'camera-actor'? - } void Builder::CreateRenderTask( const std::string &name ) @@ -642,7 +419,7 @@ void Builder::CreateRenderTask( const std::string &name ) const Stage& stage = Stage::GetCurrent(); - OptionalChild tasks = IsChild(*mParser.GetRoot(), "render-tasks"); + OptionalChild tasks = IsChild(*mParser.GetRoot(), "renderTasks"); if(tasks) { @@ -681,71 +458,40 @@ void Builder::CreateRenderTask( const std::string &name ) } } -ShaderEffect Builder::GetShaderEffect( const std::string &name) +FrameBufferImage Builder::GetFrameBufferImage( const std::string &name ) { Replacement constant( mReplacementMap ); - return GetShaderEffect( name, constant ); + return GetFrameBufferImage(name, constant); } -ShaderEffect Builder::GetShaderEffect( const std::string &name, const Replacement& constant ) +FrameBufferImage Builder::GetFrameBufferImage( const std::string &name, const Replacement& constant ) { DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - ShaderEffect ret; + FrameBufferImage ret; - ShaderEffectLut::const_iterator iter( mShaderEffectLut.find( name ) ); - if( iter != mShaderEffectLut.end() ) + ImageLut::const_iterator iter( mFrameBufferImageLut.find( name ) ); + if( iter != mFrameBufferImageLut.end() ) { ret = iter->second; } else { - if( OptionalChild effects = IsChild( *mParser.GetRoot(), "shader-effects") ) - { - if( OptionalChild effect = IsChild( *effects, name ) ) - { - Dali::Property::Value propertyMap(Property::MAP); - if( SetPropertyFromNode( *effect, Property::MAP, propertyMap, constant ) ) - { - ret = Dali::Scripting::NewShaderEffect( propertyMap ); - mShaderEffectLut[ name ] = ret; - } - } - } - } - - return ret; -} - -FrameBufferImage Builder::GetFrameBufferImage( const std::string &name ) -{ - Replacement constant( mReplacementMap ); - return GetFrameBufferImage(name, constant); -} - -FrameBufferImage Builder::GetFrameBufferImage( const std::string &name, const Replacement& constant ) -{ - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - - FrameBufferImage ret; - - ImageLut::const_iterator iter( mFrameBufferImageLut.find( name ) ); - if( iter != mFrameBufferImageLut.end() ) - { - ret = iter->second; - } - else - { - if( OptionalChild images = IsChild( *mParser.GetRoot(), "frame-buffer-images") ) + if( OptionalChild images = IsChild( *mParser.GetRoot(), "frameBufferImages") ) { if( OptionalChild image = IsChild( *images, name ) ) { - Dali::Property::Value propertyMap(Property::MAP); - if( SetPropertyFromNode( *image, Property::MAP, propertyMap, constant ) ) + Dali::Property::Value property(Property::MAP); + if( DeterminePropertyFromNode( *image, Property::MAP, property, constant ) ) { - propertyMap.SetValue(KEYNAME_TYPE, Property::Value(std::string("FrameBufferImage"))); - ret = FrameBufferImage::DownCast( Dali::Scripting::NewImage( propertyMap ) ); - mFrameBufferImageLut[ name ] = ret; + Property::Map* map = property.GetMap(); + + if( map ) + { + (*map)[ KEYNAME_TYPE ] = Property::Value(std::string("FrameBufferImage") ); + ret = FrameBufferImage::DownCast( Dali::Scripting::NewImage( property ) ); + mFrameBufferImageLut[ name ] = ret; + } } } } @@ -775,16 +521,16 @@ Path Builder::GetPath( const std::string& name ) if( OptionalChild pointsProperty = IsChild( *path, "points") ) { Dali::Property::Value points(Property::ARRAY); - if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) ) + if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) ) { ret = Path::New(); ret.SetProperty( Path::Property::POINTS, points); - //control-points property - if( OptionalChild pointsProperty = IsChild( *path, "control-points") ) + //controlPoints property + if( OptionalChild pointsProperty = IsChild( *path, "controlPoints") ) { Dali::Property::Value points(Property::ARRAY); - if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) ) + if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) ) { ret.SetProperty( Path::Property::CONTROL_POINTS, points); } @@ -817,198 +563,232 @@ Path Builder::GetPath( const std::string& name ) return ret; } -Toolkit::Builder::BuilderSignalType& Builder::QuitSignal() -{ - return mQuitSignal; -} - -void Builder::EmitQuitSignal() -{ - mQuitSignal.Emit(); -} - -void Builder::AddActors( Actor toActor ) -{ - // 'stage' is the default/by convention section to add from - AddActors( "stage", toActor ); -} - -void Builder::AddActors( const std::string §ionName, Actor toActor ) +PathConstrainer Builder::GetPathConstrainer( const std::string& name ) { DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - Property::Map overrideMap; - Replacement replacements(overrideMap, mReplacementMap); - - OptionalChild add = IsChild(*mParser.GetRoot(), sectionName); - - if( add ) + //Search the pathConstrainer in the LUT + size_t count( mPathConstrainerLut.size() ); + for( size_t i(0); i!=count; ++i ) { - for( TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter ) + if( mPathConstrainerLut[i].name == name ) { - // 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 ); - } + //PathConstrainer has already been created + return mPathConstrainerLut[i].pathConstrainer; } + } - // if were adding the 'stage' section then also check for a render task called stage - // to add automatically - if( "stage" == sectionName ) + //Create a new PathConstrainer + PathConstrainer ret; + if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") ) + { + if( OptionalChild pathConstrainer = IsChild( *constrainers, name ) ) { - if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "render-tasks") ) + OptionalString constrainerType(IsString(IsChild(*pathConstrainer, "type"))); + if(!constrainerType) { - if( OptionalChild tasks = IsChild(*renderTasks, "stage") ) + DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str() ); + } + else if( *constrainerType == "PathConstrainer") + { + //points property + if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "points") ) { - CreateRenderTask( "stage" ); + Dali::Property::Value points(Property::ARRAY); + if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) ) + { + ret = PathConstrainer::New(); + ret.SetProperty( PathConstrainer::Property::POINTS, points); + + //controlPoints property + if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "controlPoints") ) + { + Dali::Property::Value points(Property::ARRAY); + if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) ) + { + ret.SetProperty( PathConstrainer::Property::CONTROL_POINTS, points); + } + + //Forward vector + OptionalVector3 forward( IsVector3( IsChild(*pathConstrainer, "forward" ) ) ); + if( forward ) + { + ret.SetProperty( PathConstrainer::Property::FORWARD, *forward); + } + + //Add the new constrainer to the vector of PathConstrainer + PathConstrainerEntry entry = {name,ret}; + mPathConstrainerLut.push_back( entry ); + } + else + { + //Control points not specified + DALI_SCRIPT_WARNING("Control points not specified for pathConstrainer '%s'\n", name.c_str() ); + } + } + } + else + { + //Interpolation points not specified + DALI_SCRIPT_WARNING("Interpolation points not specified for pathConstrainer '%s'\n", name.c_str() ); } } + else + { + DALI_SCRIPT_WARNING("Constrainer '%s' is not a PathConstrainer\n", name.c_str() ); + } } } -} -Animation Builder::CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor ) -{ - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + return ret; +} - Animation anim; - if( OptionalChild animations = IsChild(*mParser.GetRoot(), "animations") ) +bool Builder::IsPathConstrainer( const std::string& name ) +{ + size_t count( mPathConstrainerLut.size() ); + for( size_t i(0); i!=count; ++i ) { - if( OptionalChild animation = IsChild(*animations, animationName) ) - { - anim = Dali::Toolkit::Internal::CreateAnimation( *animation, replacement, sourceActor, this ); - } - else + if( mPathConstrainerLut[i].name == name ) { - DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed\n", animationName.c_str() ); + return true; } } - else + + if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") ) { - DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed (no animation section)\n", animationName.c_str() ); + if( OptionalChild constrainer = IsChild( *constrainers, name ) ) + { + OptionalString constrainerType(IsString(IsChild(*constrainer, "type"))); + if(!constrainerType) + { + return false; + } + else + { + return *constrainerType == "PathConstrainer"; + } + } } - - return anim; -} - -Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor ) -{ - Replacement replacement(map, mReplacementMap); - return CreateAnimation( animationName, replacement, sourceActor); -} - -Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map ) -{ - Replacement replacement(map, mReplacementMap); - return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() ); -} - -Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor ) -{ - Replacement replacement( mReplacementMap ); - - return CreateAnimation( animationName, replacement, sourceActor ); -} - -Animation Builder::CreateAnimation( const std::string& animationName ) -{ - Replacement replacement( mReplacementMap ); - - return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() ); + return false; } -void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format ) +Dali::LinearConstrainer Builder::GetLinearConstrainer( const std::string& name ) { - // parser to get constants and includes only - Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New(); + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - if( !parser.Parse( data ) ) + //Search the LinearConstrainer in the LUT + size_t count( mLinearConstrainerLut.size() ); + for( size_t i(0); i!=count; ++i ) { - DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", - parser.GetErrorLineNumber(), - parser.GetErrorColumn(), - parser.GetErrorDescription().c_str() ); - - DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); - + if( mLinearConstrainerLut[i].name == name ) + { + //LinearConstrainer has already been created + return mLinearConstrainerLut[i].linearConstrainer; + } } - 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) ) + //Create a new LinearConstrainer + LinearConstrainer ret; + if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") ) + { + if( OptionalChild linearConstrainer = IsChild( *constrainers, name ) ) { - Replacement replacer( mReplacementMap ); - - for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter) + OptionalString constrainerType(IsString(IsChild(*linearConstrainer, "type"))); + if(!constrainerType) { - OptionalString filename = replacer.IsString( (*iter).second ); + DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str() ); + } + else if( *constrainerType == "LinearConstrainer") + { + //points property + if( OptionalChild pointsProperty = IsChild( *linearConstrainer, "value") ) + { + Dali::Property::Value points(Property::ARRAY); + if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) ) + { + ret = Dali::LinearConstrainer::New(); + ret.SetProperty( LinearConstrainer::Property::VALUE, points); - if( filename ) + //controlPoints property + if( OptionalChild pointsProperty = IsChild( *linearConstrainer, "progress") ) + { + Dali::Property::Value points(Property::ARRAY); + if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) ) + { + ret.SetProperty( LinearConstrainer::Property::PROGRESS, points); + } + } + //Add the new constrainer to vector of LinearConstrainer + LinearConstrainerEntry entry = {name,ret}; + mLinearConstrainerLut.push_back( entry ); + } + } + else { -#if defined(DEBUG_ENABLED) - DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str()); -#endif - LoadFromString( GetFileContents(*filename) ); + //Interpolation points not specified + DALI_SCRIPT_WARNING("Values not specified for LinearConstrainer '%s'\n", name.c_str() ); } } - } - - if( !mParser.Parse( data ) ) - { - DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n", - mParser.GetErrorLineNumber(), - mParser.GetErrorColumn(), - mParser.GetErrorDescription().c_str() ); - - DALI_ASSERT_ALWAYS(!"Cannot parse JSON"); + else + { + DALI_SCRIPT_WARNING("Constrainer '%s' is not a LinearConstrainer\n", name.c_str() ); + } } } - DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON"); - + return ret; } -void Builder::AddConstants( const Property::Map& map ) +bool Builder::IsLinearConstrainer( const std::string& name ) { - mReplacementMap.Merge( map ); + // Search the LinearConstrainer in the LUT + size_t count( mLinearConstrainerLut.size() ); + for( size_t i(0); i!=count; ++i ) + { + if( mLinearConstrainerLut[i].name == name ) + { + return true; + } + } + + if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") ) + { + if( OptionalChild constrainer = IsChild( *constrainers, name ) ) + { + OptionalString constrainerType(IsString(IsChild(*constrainer, "type"))); + if(!constrainerType) + { + return false; + } + else + { + return *constrainerType == "LinearConstrainer"; + } + } + } + return false; } -void Builder::AddConstant( const std::string& key, const Property::Value& value ) +Toolkit::Builder::BuilderSignalType& Builder::QuitSignal() { - mReplacementMap[key] = value; + return mQuitSignal; } -const Property::Map& Builder::GetConstants() const +void Builder::EmitQuitSignal() { - return mReplacementMap; + mQuitSignal.Emit(); } -const Property::Value& Builder::GetConstant( const std::string& key ) const +Builder::~Builder() { - Property::Value* match = mReplacementMap.Find( key ); - if( match ) - { - return (*match); - } - else - { - static Property::Value invalid; - return invalid; - } } -void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap ) +void Builder::LoadConfiguration( const TreeNode& root, Property::Map& intoMap ) { Replacement replacer(intoMap); - if( OptionalChild constants = IsChild(root, "constants") ) + if( OptionalChild constants = IsChild(root, "config") ) { for(TreeNode::ConstIterator iter = (*constants).CBegin(); iter != (*constants).CEnd(); ++iter) @@ -1016,18 +796,85 @@ void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap ) 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 ) ) - { - intoMap[ (*iter).second.GetName() ] = property; - } - else + DeterminePropertyFromNode( (*iter).second, property, replacer ); + + // If config is string, find constant and replace it to original value. + if( (*iter).second.GetType() == TreeNode::STRING ) { - DALI_SCRIPT_WARNING("Cannot convert property for constant %s\n", - (*iter).second.GetName() == NULL ? "no name?" : (*iter).second.GetName()); - } + std::string stringConfigValue; + if( property.Get( stringConfigValue ) ) + { + std::size_t pos = 0; + + while( pos < stringConfigValue.size() ) + { + // If we can't find "{","}" pair in stringConfigValue, will out loop. + std::size_t leftPos = stringConfigValue.find( "{", pos ); + if( leftPos != std::string::npos ) + { + std::size_t rightPos = stringConfigValue.find( "}", pos+1 ); + + if( rightPos != std::string::npos ) + { + // If we find "{","}" pair but can't find matched constant + // try to find other "{","}" pair after current left position. + pos = leftPos+1; + + for( uint32_t i = 0; i < mReplacementMap.Count() ; i++ ) + { + Property::Key constant = mReplacementMap.GetKeyAt(i); + + // Compare string which is between "{" and "}" with constant string + // If they are same, change string in stringConfigValue to mapped constant value. + if ( 0 == stringConfigValue.compare( leftPos+1, rightPos-leftPos-1, constant.stringKey ) ) + { + std::string replaceString; + mReplacementMap.GetValue(i).Get( replaceString ); + + stringConfigValue.replace( leftPos, rightPos-leftPos+1, replaceString ); + pos = leftPos + replaceString.size(); + break; + } + } + } + else + { + // If we cannot find constant in const value, will out loop. + pos = stringConfigValue.size(); + } + } + else + { + // If we cannot find constant in const value, will out loop. + pos = stringConfigValue.size(); + } + } + property = Property::Value( stringConfigValue ); + } + } + intoMap[ (*iter).second.GetName() ] = property; + } + } + } +} + +void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap ) +{ + Replacement replacer(intoMap); + + if( OptionalChild constants = IsChild(root, "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 + DeterminePropertyFromNode( (*iter).second, property, replacer ); + intoMap[ (*iter).second.GetName() ] = property; } } } @@ -1055,37 +902,31 @@ void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap ) } } #endif - -} - -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 ) +Animation Builder::CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor ) { DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); - OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES ); - OptionalChild style = IsChild( *styles, styleName ); + Animation anim; - if( styles && style ) + if( OptionalChild animations = IsChild(*mParser.GetRoot(), "animations") ) { - ApplyAllStyleProperties( *mParser.GetRoot(), *style, handle, replacement ); - return true; + if( OptionalChild animation = IsChild(*animations, animationName) ) + { + anim = Dali::Toolkit::Internal::CreateAnimation( *animation, replacement, sourceActor, this ); + } + else + { + DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed\n", animationName.c_str() ); + } } else { - return false; + DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed (no animation section)\n", animationName.c_str() ); } -} -BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map ) -{ - Replacement replacement( map, mReplacementMap ); - return Create( templateName, replacement ); + return anim; } BaseHandle Builder::Create( const std::string& templateName, const Replacement& constant ) @@ -1125,60 +966,730 @@ BaseHandle Builder::Create( const std::string& templateName, const Replacement& return baseHandle; } -BaseHandle Builder::CreateFromJson( const std::string& json ) +/* + * 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 ret; + BaseHandle baseHandle; + TypeInfo typeInfo; + const TreeNode* templateNode = NULL; - // merge in new template, hoping no one else has one named '@temp@' - std::string newTemplate = - std::string("{\"templates\":{\"@temp@\":") + \ - json + \ - std::string("}}"); + if( OptionalString typeName = IsString(node, KEYNAME_TYPE) ) + { + typeInfo = TypeRegistry::Get().GetTypeInfo( *typeName ); - if( mParser.Parse(newTemplate) ) + 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); + + if( OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE) ) + { + typeInfo = TypeRegistry::Get().GetTypeInfo( *templateTypeName ); + } + } + } + } + } + + if(!typeInfo) { - Replacement replacement( mReplacementMap ); - ret = Create( "@temp@", replacement ); + 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); - return ret; + 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 + + if( templateNode ) + { + ApplyProperties( root, *templateNode, handle, replacements ); + + if( OptionalChild actors = IsChild( *templateNode, KEYNAME_ACTORS ) ) + { + for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter ) + { + DoCreate( root, (*iter).second, actor, replacements ); + } + } + } + + 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 ); + } + } + + // 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 + { + ApplyProperties( root, node, handle, replacements ); + } + } + else + { + DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str()); + } + } + + return baseHandle; } -bool Builder::ApplyFromJson( Handle& handle, const std::string& json ) +void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant ) { - bool ret = false; + const Stage& stage = Stage::GetCurrent(); + Layer root = stage.GetRootLayer(); - // merge new style, hoping no one else has one named '@temp@' - std::string newStyle = - std::string("{\"styles\":{\"@temp@\":") + \ - json + \ - std::string("}}"); + 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() ); + } + } - if( mParser.Parse(newStyle) ) + if( OptionalString s = constant.IsString( IsChild(node, "cameraActor") ) ) { - Replacement replacement( mReplacementMap ); - ret = ApplyStyle( "@temp@", handle, replacement ); + 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() ); + } } - return ret; -} + if( OptionalString s = constant.IsString( IsChild(node, "targetFrameBuffer") ) ) + { + FrameBufferImage fb = GetFrameBufferImage( *s, constant ); + if(fb) + { + task.SetTargetFrameBuffer( fb ); + } + else + { + DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() ); + } + } + 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 + { + DALI_SCRIPT_WARNING("todo"); + } + } -BaseHandle Builder::Create( const std::string& templateName ) -{ - Replacement replacement( mReplacementMap ); - return Create( templateName, replacement ); + // other setup is via the property system + SetProperties( node, task, constant ); } -Builder::Builder() -: mSlotDelegate( this ) +bool Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement ) { - mParser = Dali::Toolkit::JsonParser::New(); -} + DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded"); + + OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES ); + + std::string styleNameLower(styleName); + OptionalChild style = IsChildIgnoreCase( *styles, styleNameLower ); + + if( styles && style ) + { + ApplyAllStyleProperties( *mParser.GetRoot(), *style, handle, replacement ); + return true; + } + else + { + return false; + } +} + +void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node, + Dali::Handle& handle, const Replacement& constant ) +{ + const char* styleName = node.GetName(); + + StylePtr style = Style::New(); + + StylePtr* matchedStyle = NULL; + if( styleName ) + { + matchedStyle = mStyles.Find( styleName ); + if( ! matchedStyle ) + { + OptionalChild styleNodes = IsChild(root, KEYNAME_STYLES); + OptionalChild inheritFromNode = IsChild(node, KEYNAME_INHERIT); + if( !inheritFromNode ) + { + inheritFromNode = IsChild( node, KEYNAME_STYLES ); + } + + if( styleNodes ) + { + if( inheritFromNode ) + { + TreeNodeList additionalStyleNodes; + + CollectAllStyles( *styleNodes, *inheritFromNode, additionalStyleNodes ); + +#if defined(DEBUG_ENABLED) + for(TreeNode::ConstIterator iter = (*inheritFromNode).CBegin(); iter != (*inheritFromNode).CEnd(); ++iter) + { + if( OptionalString styleName = IsString( (*iter).second ) ) + { + DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str()); + } + } +#endif + + // a style may have other styles, which has other styles etc so we apply in reverse by convention. + for(TreeNodeList::reverse_iterator iter = additionalStyleNodes.rbegin(); iter != additionalStyleNodes.rend(); ++iter) + { + RecordStyle( style, *(*iter), handle, constant ); + ApplySignals( root, *(*iter), handle ); + ApplyStylesByActor( root, *(*iter), handle, constant ); + } + } + + RecordStyle( style, node, handle, constant ); + mStyles.Add( styleName, style ); // shallow copy + matchedStyle = &style; + } + } + } + + if( matchedStyle ) + { + StylePtr style( *matchedStyle ); + Dictionary instancedProperties; + style->ApplyVisualsAndPropertiesRecursively( handle, instancedProperties ); + } + else // If there were no styles, instead set properties + { + SetProperties( node, handle, constant ); + } + ApplySignals( root, node, handle ); + ApplyStylesByActor( root, node, handle, constant ); +} + +void Builder::RecordStyle( StylePtr style, + const TreeNode& node, + Dali::Handle& handle, + const Replacement& replacements ) +{ + // With repeated calls, accumulate inherited states, visuals and properties + // but override any with same name + + for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter ) + { + const TreeNode::KeyNodePair& keyValue = *iter; + std::string key( keyValue.first ); + if( key == KEYNAME_STATES ) + { + const TreeNode& states = keyValue.second; + if( states.GetType() != TreeNode::OBJECT ) + { + DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", key.c_str() ); + continue; + } + + for( TreeNode::ConstIterator iter = states.CBegin(); iter != states.CEnd(); ++iter ) + { + const TreeNode& stateNode = (*iter).second; + const char* stateName = stateNode.GetName(); + if( stateNode.GetType() != TreeNode::OBJECT ) + { + DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", stateName ); + continue; + } + + StylePtr* stylePtr = style->subStates.Find( stateName ); + if( stylePtr ) + { + StylePtr style(*stylePtr); + RecordStyle( style, stateNode, handle, replacements ); + } + else + { + StylePtr subState = Style::New(); + RecordStyle( subState, stateNode, handle, replacements ); + style->subStates.Add( stateName, subState ); + } + } + } + else if( key == KEYNAME_VISUALS ) + { + for( TreeNode::ConstIterator iter = keyValue.second.CBegin(); iter != keyValue.second.CEnd(); ++iter ) + { + // Each key in this table should be a property name matching a visual. + const TreeNode::KeyNodePair& visual = *iter; + Dali::Property::Value property(Property::MAP); + if( DeterminePropertyFromNode( visual.second, Property::MAP, property, replacements ) ) + { + Property::Map* mapPtr = style->visuals.Find( visual.first ); + if( mapPtr ) + { + // Override existing visuals + mapPtr->Clear(); + mapPtr->Merge( *property.GetMap() ); + } + else + { + Property::Map* map = property.GetMap(); + if( map ) + { + style->visuals.Add( visual.first, *map ); + } + } + } + } + } + else if( key == KEYNAME_ENTRY_TRANSITION ) + { + RecordTransitionData( keyValue, style->entryTransition, replacements ); + } + else if( key == KEYNAME_EXIT_TRANSITION ) + { + RecordTransitionData( keyValue, style->exitTransition, replacements ); + } + else if( key == KEYNAME_TRANSITIONS ) + { + RecordTransitions( keyValue, style->transitions, replacements ); + } + else if( key == KEYNAME_TYPE || + key == KEYNAME_ACTORS || + key == KEYNAME_SIGNALS || + key == KEYNAME_STYLES || + key == KEYNAME_MAPPINGS || + key == KEYNAME_INHERIT ) + { + continue; + } + else // It's a property + { + Property::Index index; + Property::Value value; + if( MapToTargetProperty( handle, key, keyValue.second, replacements, index, value ) ) + { + Property::Value* existingValuePtr = style->properties.Find( index ); + if( existingValuePtr != NULL ) + { + *existingValuePtr = value; // Overwrite existing property. + } + else + { + style->properties.Add( index, value ); + } + } + } + } +} + +void Builder::RecordTransitions( + const TreeNode::KeyNodePair& keyValue, + Property::Array& value, + const Replacement& replacements ) +{ + //@todo add new transitions to style.transitions + // override existing transitions. A transition matches on target & property name + const TreeNode& node = keyValue.second; + if( node.GetType() == TreeNode::ARRAY ) + { + Dali::Property::Value property(Property::ARRAY); + if( DeterminePropertyFromNode( node, Property::ARRAY, property, replacements ) ) + { + value = *property.GetArray(); + } + } + else if( node.GetType() == TreeNode::OBJECT ) + { + Dali::Property::Value property(Property::MAP); + if( DeterminePropertyFromNode( node, Property::MAP, property, replacements ) ) + { + Property::Array propertyArray; + propertyArray.Add( property ); + value = propertyArray; + } + } + else + { + DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON array or object\n", keyValue.first ); + } +} + +void Builder::RecordTransitionData( + const TreeNode::KeyNodePair& keyValue, + Toolkit::TransitionData& transitionData, + const Replacement& replacements ) +{ + const TreeNode& node = keyValue.second; + if( node.GetType() == TreeNode::ARRAY ) + { + Dali::Property::Value property(Property::ARRAY); + if( DeterminePropertyFromNode( keyValue.second, Property::ARRAY, property, replacements ) ) + { + transitionData = Toolkit::TransitionData::New( *property.GetArray() ); + } + } + else if( node.GetType() == TreeNode::OBJECT ) + { + Dali::Property::Value property(Property::MAP); + if( DeterminePropertyFromNode( keyValue.second, Property::MAP, property, replacements ) ) + { + transitionData = Toolkit::TransitionData::New( *property.GetMap() ); + } + } +} + + +// Set properties from node on handle. +void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node, + Dali::Handle& handle, const Replacement& constant ) +{ + SetProperties( node, handle, constant ); + ApplySignals( root, node, handle ); +} + +void Builder::ApplySignals(const TreeNode& root, const TreeNode& node, Dali::Handle& handle ) +{ + Actor actor = Actor::DownCast(handle); + if( actor ) + { + // add signals + SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); + SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this ); + } +} + + +// 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 ) ) + { + // 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 ) + { + DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first); + } + else + { + DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first); + ApplyProperties( root, (*iter).second, foundActor, constant ); + } + } + } + } +} + +/* + * 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 ) + { + const TreeNode::KeyNodePair& keyChild = *iter; + + std::string key( keyChild.first ); + + // ignore special fields; + if( key == KEYNAME_TYPE || + key == KEYNAME_ACTORS || + key == KEYNAME_SIGNALS || + key == KEYNAME_STYLES || + key == KEYNAME_MAPPINGS || + key == KEYNAME_INHERIT || + key == KEYNAME_STATES || + key == KEYNAME_VISUALS || + key == KEYNAME_ENTRY_TRANSITION || + key == KEYNAME_EXIT_TRANSITION || + key == KEYNAME_TRANSITIONS ) + { + continue; + } + + Property::Index index; + Property::Value value; + + bool mapped = MapToTargetProperty( handle, key, keyChild.second, constant, index, value ); + 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() ); + + handle.SetProperty( index, value ); + } + + // 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"); + } +} + +bool Builder::MapToTargetProperty( + Handle& propertyObject, + const std::string& key, + const TreeNode& node, + const Replacement& constant, + Property::Index& index, + Property::Value& value ) +{ + bool mapped = false; + + index = propertyObject.GetPropertyIndex( key ); + if( Property::INVALID_INDEX != index ) + { + Property::Type type = propertyObject.GetPropertyType(index); + + // if node.value is a mapping, get the property value from the "mappings" table + if( node.GetType() == TreeNode::STRING ) + { + std::string mappingKey; + if( GetMappingKey( node.GetString(), mappingKey) ) + { + OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS ); + mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value ); + } + } + if( ! mapped ) + { + mapped = DeterminePropertyFromNode( node, type, value, constant ); + if( ! mapped ) + { + // Just determine the property from the node and if it's valid, let the property object handle it + DeterminePropertyFromNode( node, value, constant ); + mapped = ( value.GetType() != Property::NONE ); + } + } + } + else + { + DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str()); + } + return mapped; +} + +bool Builder::GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value ) +{ + KeyStack keyStack; + return RecursePropertyMap( mappingRoot, keyStack, theKey, propertyType, value ); +} + +bool Builder::RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value ) +{ + Replacement replacer( mReplacementMap ); + bool result = false; + + keyStack.push_back( theKey ); + + for( TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter ) + { + std::string aKey( (*iter).first ); + if( aKey.compare( theKey ) == 0 ) + { + if( propertyType == Property::NONE ) + { + DeterminePropertyFromNode( (*iter).second, value, replacer ); + result = true; + } + else + { + result = DeterminePropertyFromNode( (*iter).second, propertyType, value, replacer ); + } + + if( result ) + { + ConvertChildValue(mappingRoot, keyStack, value); + } + break; + } + } + keyStack.pop_back(); + + return result; +} + +bool Builder::ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child ) +{ + bool result = false; + + switch( child.GetType() ) + { + case Property::STRING: + { + std::string value; + if( child.Get( value ) ) + { + std::string key; + if( GetMappingKey( value, key ) ) + { + // Check key for cycles: + result=true; + for( KeyStack::iterator iter = keyStack.begin() ; iter != keyStack.end(); ++iter ) + { + if( key.compare(*iter) == 0 ) + { + // key is already in stack; stop. + DALI_LOG_WARNING("Detected cycle in stylesheet mapping table:%s\n", key.c_str()); + child = Property::Value(""); + result=false; + break; + } + } + + if( result ) + { + // The following call will overwrite the child with the value + // from the mapping. + RecursePropertyMap( mappingRoot, keyStack, key.c_str(), Property::NONE, child ); + result = true; + } + } + } + break; + } + + case Property::MAP: + { + Property::Map* map = child.GetMap(); + if( map ) + { + for( Property::Map::SizeType i=0; i < map->Count(); ++i ) + { + Property::Value& child = map->GetValue(i); + ConvertChildValue(mappingRoot, keyStack, child); + } + } + break; + } + + case Property::ARRAY: + { + Property::Array* array = child.GetArray(); + if( array ) + { + for( Property::Array::SizeType i=0; i < array->Count(); ++i ) + { + Property::Value& child = array->GetElementAt(i); + ConvertChildValue(mappingRoot, keyStack, child); + } + } + break; + } + + default: + // Ignore other types. + break; + } + + return result; +} + +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 ); + } + } +} -Builder::~Builder() -{ -} } // namespace Internal