2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://floralicense.org/license/
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 #include <dali-toolkit/internal/builder/builder-impl.h>
24 #include <dali/dali.h>
25 #include <dali/integration-api/debug.h>
27 #include <dali-toolkit/public-api/controls/control.h>
29 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
30 #include <dali-toolkit/internal/builder/builder-filesystem.h>
31 #include <dali-toolkit/internal/builder/builder-declarations.h>
42 extern Animation CreateAnimation(const TreeNode& child);
43 extern bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value );
44 extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor);
45 extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor);
46 extern Actor SetupActor( const TreeNode& node, Actor& actor );
47 extern Control SetupControl( const TreeNode& node, Control& actor );
49 #if defined(DEBUG_ENABLED)
50 Integration::Log::Filter* gFilterScript = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT");
56 typedef std::vector<const TreeNode*> TreeNodeList;
59 * Sets the handle properties found in the tree node
61 void SetProperties( const TreeNode& node, Handle& handle, Builder& builder )
65 for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
67 const TreeNode::KeyNodePair& keyChild = *iter;
69 std::string key( keyChild.first );
71 // ignore special fields; type,actors,signals
72 if(key == "type" || key == "actors" || key == "signals")
77 // special field 'image' usually contains an json object description
78 // although sometimes refers to a framebuffer
79 if( 0 == keyChild.second.Size() )
83 ImageActor imageActor = ImageActor::DownCast(handle);
86 if( OptionalString s = IsString( keyChild.second ) )
88 FrameBufferImage fb = builder.GetFrameBufferImage(*s);
91 imageActor.SetImage( fb );
98 // special field 'effect' references the shader effect instances
101 Actor actor = Actor::DownCast(handle);
102 OptionalString s = IsString( keyChild.second );
105 ShaderEffect e = builder.GetShaderEffect(*s);
106 actor.SetShaderEffect(e);
110 DALI_SCRIPT_WARNING("Could not find or set shader effect\n");
116 Property::Index index = handle.GetPropertyIndex(key);
118 if( Property::INVALID_INDEX != index )
120 Property::Type type = handle.GetPropertyType(index);
122 Property::Value value;
123 if( !SetPropertyFromNode( keyChild.second, type, value ) )
125 // verbose as this might not be a problem
126 // eg parent-origin can be a string which is picked up later
127 DALI_SCRIPT_VERBOSE("Could not convert property:%s\n", key.c_str());
131 DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d\n", key.c_str(), index, value.GetType());
133 handle.SetProperty( index, value );
138 DALI_SCRIPT_VERBOSE("SetProperty INVALID '%s' Index=:%d\n", key.c_str(), index);
141 } // for property nodes
145 DALI_SCRIPT_WARNING("Style applied to empty handle\n");
150 * Split a string by delimiter
152 std::vector<std::string> SplitString(const std::string &s, char delim, std::vector<std::string> &elems)
154 std::stringstream ss(s);
156 while(std::getline(ss, item, delim))
158 elems.push_back(item);
164 * Recursively collects all styles listed in a json node 'type' field. (Could be a comma separated list).
165 * It also returns the first found base typeInfo from the TypeRegistry. This is the concrete object to instance.
166 * i.e. the type field can name a json style section or a TypeRegistry base type.
168 void CollectAllStyles( const TreeNode& styles, const std::string& typeStyleString, TreeNodeList& additionalStyles, TypeInfo& typeInfo )
170 typedef std::vector<std::string> StyleNames;
171 StyleNames styleNames;
173 SplitString(typeStyleString, ',', styleNames);
175 for(StyleNames::iterator iter = styleNames.begin(); iter != styleNames.end(); ++iter)
177 const std::string typeName(*iter);
179 OptionalChild style = IsChild(styles, typeName);
182 additionalStyles.push_back(&(*style));
184 OptionalString styleType = IsString( IsChild(*style, "type") );
187 CollectAllStyles(styles, *styleType, additionalStyles, typeInfo);
193 // if its not a style then check for a type but only the first found
194 typeInfo = TypeRegistry::Get().GetTypeInfo( typeName );
200 DALI_ASSERT_DEBUG(!typeInfo);
201 typeInfo = TypeRegistry::Get().GetTypeInfo( typeName );
207 * Recursively collects all styles listed in a json node 'type' field. (Could be a comma separated list).
208 * Adds the given node to the end of the additional styles list.
209 * It also returns the first found base typeInfo from the TypeRegistry. This is the concrete object to instance.
210 * i.e. the type field can name a json style section or a TypeRegistry base type.
212 void CollectAllStyles( const OptionalChild& optionalStyles, const TreeNode& node, TreeNodeList& additionalStyles, TypeInfo& typeInfo )
214 OptionalString type = IsString( IsChild(node, "type") );
218 DALI_SCRIPT_WARNING("Cannot create style as type section is missing\n");
222 additionalStyles.push_back(&node);
226 CollectAllStyles( *optionalStyles, *type, additionalStyles, typeInfo );
230 typeInfo = TypeRegistry::Get().GetTypeInfo( *type );
237 * Create a dali type from a node.
238 * If parent given and an actor type was created then add it to the parent and
239 * recursively add nodes children.
241 BaseHandle Create( ConnectionTracker* tracker, const OptionalChild& optionalStyles, const TreeNode& node, const TreeNode& root, Actor parent, Builder& builder )
243 BaseHandle baseHandle;
244 TreeNodeList allStyles;
247 CollectAllStyles( optionalStyles, node, allStyles, typeInfo );
251 DALI_SCRIPT_WARNING("Unable to create Dali type from node\n");
255 baseHandle = typeInfo.CreateInstance();
256 Handle handle = Handle::DownCast(baseHandle);
257 Actor actor = Actor::DownCast(handle);
258 Control control = Control::DownCast(handle);
263 DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str());
264 DALI_SCRIPT_VERBOSE(" %d style sections\n", allStyles.size());
266 #if defined(DEBUG_ENABLED)
269 DALI_SCRIPT_VERBOSE(" Is Handle Object=%d\n", (long*)handle.GetObjectPtr());
270 DALI_SCRIPT_VERBOSE(" Is Handle Property Count=%d\n", handle.GetPropertyCount());
275 DALI_SCRIPT_VERBOSE(" Is Actor id=%d\n", actor.GetId());
280 DALI_SCRIPT_VERBOSE(" Is Control id=%d\n", actor.GetId());
282 #endif // DEBUG_ENABLED
284 for(TreeNodeList::reverse_iterator iter = allStyles.rbegin(); iter != allStyles.rend(); ++iter)
286 SetProperties( *(*iter), handle, builder );
288 if( actor ) // if we created an actor
290 SetupActor( *(*iter), actor);
294 SetupControl( *(*iter), control);
297 // add children of all the styles
298 if( OptionalChild actors = IsChild( *(*iter), "actors" ) )
300 for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter )
302 Create( tracker, optionalStyles, (*iter).second, root, actor, builder );
311 SetupSignalAction( tracker, root, node, actor );
312 SetupPropertyNotification( tracker, root, node, actor );
314 // then add to parent
324 DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str());
335 ActorContainer Builder::GetTopLevelActors() const
337 // deprecated function.
338 return ActorContainer();
341 Animation Builder::GetAnimation( const std::string &name ) const
347 void Builder::SetupTask( RenderTask& task, const TreeNode& node )
349 const Stage& stage = Stage::GetCurrent();
350 Layer root = stage.GetRootLayer();
352 if( OptionalString s = IsString( IsChild(node, "source-actor") ) )
354 Actor actor = root.FindChildByName(*s);
357 task.SetSourceActor( actor );
361 DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str() );
365 if( OptionalString s = IsString( IsChild(node, "camera-actor") ) )
367 CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) );
370 task.SetCameraActor( actor );
374 DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str() );
378 if( OptionalString s = IsString( IsChild(node, "target-frame-buffer") ) )
380 FrameBufferImage fb = GetFrameBufferImage( *s );
383 task.SetTargetFrameBuffer( fb );
387 DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() );
391 if( OptionalString s = IsString( IsChild(node, "screen-to-frame-buffer-function") ) )
393 if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s)
395 task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION );
397 else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s)
399 task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
403 DALI_SCRIPT_WARNING("todo");
407 // other setup is via the property system
408 SetProperties( node, task, *this ); // @ todo, remove 'source-actor', 'camera-actor'?
412 void Builder::CreateRenderTask( const std::string &name )
414 const Stage& stage = Stage::GetCurrent();
416 OptionalChild tasks = IsChild(*mParser.GetRoot(), "render-tasks");
421 // Create the tasks from the current task as generally we want
422 // to setup task zero and onwards. Although this does overwrite
423 // the properties of the current task.
425 if( OptionalChild renderTask = IsChild(*tasks, name ) )
427 RenderTaskList list = stage.GetRenderTaskList();
428 unsigned int start = list.GetTaskCount();
433 // zero should have already been created by the stage so really
434 // this case should never happen
435 task = list.CreateTask();
439 TreeNode::ConstIterator iter = (*renderTask).CBegin();
440 task = list.GetTask( start - 1 );
442 SetupTask( task, (*iter).second );
446 for(; iter != (*renderTask).CEnd(); ++iter )
448 task = list.CreateTask();
449 SetupTask( task, (*iter).second );
455 ShaderEffect Builder::GetShaderEffect( const std::string &name )
459 ShaderEffectLut::const_iterator iter( mShaderEffectLut.find( name ) );
460 if( iter != mShaderEffectLut.end() )
466 if( OptionalChild effects = IsChild( *mParser.GetRoot(), "shader-effects") )
468 if( OptionalChild effect = IsChild( *effects, name ) )
470 Dali::Property::Value propertyMap(Property::MAP);
471 if( SetPropertyFromNode( *effect, Property::MAP, propertyMap ) )
473 ret = Dali::Scripting::NewShaderEffect( propertyMap );
474 mShaderEffectLut[ name ] = ret;
483 FrameBufferImage Builder::GetFrameBufferImage( const std::string &name )
485 FrameBufferImage ret;
487 ImageLut::const_iterator iter( mFrameBufferImageLut.find( name ) );
488 if( iter != mFrameBufferImageLut.end() )
494 if( OptionalChild images = IsChild( *mParser.GetRoot(), "frame-buffer-images") )
496 if( OptionalChild image = IsChild( *images, name ) )
498 Dali::Property::Value propertyMap(Property::MAP);
499 if( SetPropertyFromNode( *image, Property::MAP, propertyMap ) )
501 propertyMap.SetValue("type", Property::Value(std::string("FrameBufferImage")));
502 ret = Dali::Scripting::NewImage( propertyMap );
503 mFrameBufferImageLut[ name ] = ret;
512 Font Builder::GetFont( const std::string& name ) const
514 // deprecated function.
519 TextStyle Builder::GetTextStyle( const std::string& name ) const
525 Image Builder::GetImage( const std::string& name) const
527 // deprecated function.
531 Actor Builder::GetActor( const std::string &name ) const
533 // deprecated function.
537 void Builder::AddActors( Actor toActor )
539 // 'stage' is the default/by convention section to add from
540 AddActors( "stage", toActor );
543 void Builder::AddActors( const std::string §ionName, Actor toActor )
545 OptionalChild addToStage = IsChild(*mParser.GetRoot(), sectionName);
549 OptionalChild styles = IsChild(*mParser.GetRoot(), "styles");
551 for( TreeNode::ConstIterator iter = (*addToStage).CBegin(); iter != (*addToStage).CEnd(); ++iter )
553 // empty actor adds directly to the stage
554 BaseHandle baseHandle = Create( mSlotDelegate.GetConnectionTracker(), styles, (*iter).second, *mParser.GetRoot(), Actor(), *this);
555 Actor actor = Actor::DownCast(baseHandle);
558 toActor.Add( actor );
562 // if were adding the 'stage' section then also check for a render task called stage
563 // to add automatically
564 if( "stage" == sectionName )
566 if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "render-tasks") )
568 if( OptionalChild tasks = IsChild(*renderTasks, "stage") )
570 CreateRenderTask( "stage" );
578 Animation Builder::CreateAnimation( const std::string& animationName )
582 if( OptionalChild animations = IsChild(*mParser.GetRoot(), "animations") )
584 if( OptionalChild animation = IsChild(*animations, animationName) )
586 anim = Dali::Toolkit::Internal::CreateAnimation( *animation );
591 DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed\n", animationName.c_str() );
597 void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format )
599 DALI_ASSERT_ALWAYS( format == Dali::Toolkit::Builder::JSON && "Currently only JSON is supported" );
601 if( !mParser.Parse(data) )
603 DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n",
604 mParser.GetErrorLineNumber(),
605 mParser.GetErrorColumn(),
606 mParser.GetErrorDescription().c_str() );
608 DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
611 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
615 void Builder::ApplyStyle( const std::string& styleName, Handle& handle )
617 OptionalChild styles = IsChild(*mParser.GetRoot(), "styles");
621 if( OptionalChild style = IsChild(*styles, styleName) )
623 TreeNodeList allStyles;
626 CollectAllStyles( styles, *style, allStyles, typeInfo );
628 for(TreeNodeList::reverse_iterator iter = allStyles.rbegin(); iter != allStyles.rend(); ++iter)
630 SetProperties( *style, handle, *this );
635 DALI_SCRIPT_WARNING("Could not find style:%s\n", styleName.c_str());
640 DALI_SCRIPT_WARNING("No style section available for style:%s\n", styleName.c_str());
644 BaseHandle Builder::CreateFromStyle( const std::string& styleName )
646 BaseHandle baseHandle;
648 OptionalChild styles = IsChild(*mParser.GetRoot(), "styles");
652 DALI_SCRIPT_WARNING("No style section found to CreateFromStyle\n");
656 OptionalChild style = IsChild(*styles, styleName);
659 DALI_SCRIPT_WARNING("Style '%s' does not exist in style section\n", styleName.c_str());
663 OptionalString type = IsString( IsChild(*style, "type") );
667 DALI_SCRIPT_WARNING("Cannot create style '%s' as style section is missing 'type'\n", styleName.c_str());
671 baseHandle = Create( mSlotDelegate.GetConnectionTracker(), styles, *style, *mParser.GetRoot(), Actor(), *this );
680 : mSlotDelegate( this )
682 mParser = Dali::Toolkit::JsonParser::New();
689 } // namespace Internal
691 } // namespace Toolkit