11b92f6ceec734f7c621ece4f9577b9a042452d4
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / builder-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/builder/builder-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <sys/stat.h>
23 #include <sstream>
24 #include <dali/public-api/render-tasks/render-task-list.h>
25 #include <dali/public-api/object/type-info.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/property-array.h>
28 #include <dali/public-api/actors/layer.h>
29 #include <dali/public-api/actors/image-actor.h>
30 #include <dali/public-api/actors/camera-actor.h>
31 #include <dali/devel-api/scripting/scripting.h>
32 #include <dali/public-api/signals/functor-delegate.h>
33 #include <dali/integration-api/debug.h>
34
35 // INTERNAL INCLUDES
36 #include <dali-toolkit/public-api/controls/control.h>
37 #include <dali-toolkit/devel-api/builder/json-parser.h>
38
39 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
40 #include <dali-toolkit/internal/builder/builder-filesystem.h>
41 #include <dali-toolkit/internal/builder/builder-declarations.h>
42 #include <dali-toolkit/internal/builder/replacement.h>
43
44 namespace Dali
45 {
46
47 namespace Toolkit
48 {
49
50 namespace Internal
51 {
52 class Replacement;
53
54 extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot, Builder* const builder );
55 extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
56 extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value, const Replacement& replacements );
57 extern bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value );
58 extern bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value, const Replacement& replacements );
59 extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
60 extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
61 extern Actor SetupActor( const TreeNode& node, Actor& actor, const Replacement& constant );
62
63 #if defined(DEBUG_ENABLED)
64 Integration::Log::Filter* gFilterScript  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT");
65 #endif
66
67 namespace
68 {
69
70 #define TOKEN_STRING(x) #x
71
72 const std::string KEYNAME_STYLES    = "styles";
73 const std::string KEYNAME_TYPE      = "type";
74 const std::string KEYNAME_ACTORS    = "actors";
75 const std::string KEYNAME_SIGNALS   = "signals";
76 const std::string KEYNAME_NAME      = "name";
77 const std::string KEYNAME_TEMPLATES = "templates";
78 const std::string KEYNAME_INCLUDES  = "includes";
79
80 typedef std::vector<const TreeNode*> TreeNodeList;
81
82 template <typename T>
83 std::string ToString(const T& value)
84 {
85   std::stringstream ss;
86   ss << value;
87   return ss.str();
88 }
89
90 template <>
91 std::string ToString(const Rect<int>& value)
92 {
93   std::stringstream ss;
94   ss << value.x << "," << value.y << "," << value.width << "," << value.height;
95   return ss.str();
96 }
97
98 #if defined(DEBUG_ENABLED)
99
100 std::string PropertyValueToString( const Property::Value& value )
101 {
102   std::string ret;
103
104   switch( value.GetType() )
105   {
106     case Property::NONE:
107     {
108       ret = "NONE";
109       break;
110     }            ///< No type
111     case Property::BOOLEAN:
112     {
113       ret = value.Get<bool>() ? "True" : "False";
114       break;
115     }
116     case Property::FLOAT:
117     {
118
119       ret = ToString( value.Get<float>() );
120       break;
121     }
122     case Property::INTEGER:
123     {
124       ret = ToString( value.Get<int>() );
125       break;
126     }
127     case Property::VECTOR2:
128     {
129       ret = ToString( value.Get<Vector2>() );
130       break;
131     }
132     case Property::VECTOR3:
133     {
134       ret = ToString( value.Get<Vector3>() );
135       break;
136     }
137     case Property::VECTOR4:
138     {
139       ret = ToString( value.Get<Vector4>() );
140       break;
141     }
142     case Property::MATRIX3:
143     {
144       ret = ToString( value.Get<Matrix3>() );
145       break;
146     }
147     case Property::MATRIX:
148     {
149       ret = ToString( value.Get<Matrix>() );
150       break;
151     }
152     case Property::RECTANGLE:
153     {
154       ret = ToString( value.Get< Rect<int> >() );
155       break;
156     }
157     case Property::ROTATION:
158     {
159       break;
160     }
161     case Property::STRING:
162     {
163       ret = value.Get<std::string>();
164       break;
165     }
166     case Property::ARRAY:
167     {
168       ret = std::string("Array Size=") + ToString( value.Get<Property::Array>().Size() );
169       break;
170     }
171     case Property::MAP:
172     {
173       ret = std::string("Map Size=") + ToString( value.Get<Property::Map>().Count() );
174       break;
175     }
176   }
177
178   return ret;
179 }
180 #endif // DEBUG_ENABLED
181
182 /*
183  * Recursively collects all stylesin a node (An array of style names).
184  *
185  * stylesCollection The set of styles from the json file (a json object of named styles)
186  * style The style array to begin the collection from
187  * styleList The style list to add nodes to apply
188  */
189 void CollectAllStyles( const TreeNode& stylesCollection, const TreeNode& style, TreeNodeList& styleList )
190 {
191   // style is an array of style names
192   if( TreeNode::ARRAY == style.GetType() )
193   {
194     for(TreeNode::ConstIterator iter = style.CBegin(); iter != style.CEnd(); ++iter)
195     {
196       if( OptionalString styleName = IsString( (*iter).second ) )
197       {
198         if( OptionalChild node = IsChild( stylesCollection, *styleName) )
199         {
200           styleList.push_back( &(*node) );
201
202           if( OptionalChild subStyle = IsChild( *node, KEYNAME_STYLES ) )
203           {
204             CollectAllStyles( stylesCollection, *subStyle, styleList );
205           }
206         }
207       }
208     }
209   }
210 }
211
212
213 } // namespace anon
214
215 /*
216  * Sets the handle properties found in the tree node
217  */
218 void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant )
219 {
220   if( handle )
221   {
222     for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
223     {
224       const TreeNode::KeyNodePair& keyChild = *iter;
225
226       std::string key( keyChild.first );
227
228       // ignore special fields; type,actors,signals,styles
229       if(key == KEYNAME_TYPE || key == KEYNAME_ACTORS || key == KEYNAME_SIGNALS || key == KEYNAME_STYLES)
230       {
231         continue;
232       }
233
234       // special field 'image' usually contains an json object description
235       // although sometimes refers to a framebuffer
236       if( 0 == keyChild.second.Size() )
237       {
238         if(key == "image")
239         {
240           ImageActor imageActor = ImageActor::DownCast(handle);
241           if(imageActor)
242           {
243             if( OptionalString s = constant.IsString( keyChild.second ) )
244             {
245               FrameBufferImage fb = GetFrameBufferImage(*s, constant);
246               if(fb)
247               {
248                 imageActor.SetImage( fb );
249               }
250             }
251           }
252         }
253       }
254
255       // special field 'effect' references the shader effect instances
256       if(key == "effect")
257       {
258         ImageActor actor = ImageActor::DownCast(handle);
259         if( actor )
260         {
261           OptionalString str = constant.IsString( keyChild.second );
262           if( str )
263           {
264             ShaderEffect effect = GetShaderEffect( *str, constant );
265             actor.SetShaderEffect(effect);
266           }
267         }
268         else
269         {
270           DALI_SCRIPT_WARNING("Could not find or set shader effect\n");
271         }
272
273         continue;
274       }
275
276       Handle propertyObject( handle );
277
278       Dali::Property::Index index = propertyObject.GetPropertyIndex( key );
279
280       if( Property::INVALID_INDEX == index )
281       {
282         ImageActor actor = ImageActor::DownCast(handle);
283         if( actor )
284         {
285           if( ShaderEffect effect = actor.GetShaderEffect() )
286           {
287             index = effect.GetPropertyIndex( key );
288             if(index != Property::INVALID_INDEX)
289             {
290               propertyObject = effect;
291             }
292           }
293         }
294       }
295
296       if( Property::INVALID_INDEX != index )
297       {
298         Property::Type type = propertyObject.GetPropertyType(index);
299
300         Property::Value value;
301         if( !SetPropertyFromNode( keyChild.second, type, value, constant ) )
302         {
303           // verbose as this might not be a problem
304           // eg parent-origin can be a string which is picked up later
305           DALI_SCRIPT_VERBOSE("Could not convert property:%s\n", key.c_str());
306         }
307         else
308         {
309           DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() );
310
311           propertyObject.SetProperty( index, value );
312         }
313       }
314       else
315       {
316         DALI_SCRIPT_VERBOSE("SetProperty INVALID '%s' Index=:%d\n", key.c_str(), index);
317       }
318
319     } // for property nodes
320   }
321   else
322   {
323     DALI_SCRIPT_WARNING("Style applied to empty handle\n");
324   }
325 }
326
327 // Set properties from node on handle.
328 void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node,
329                                Dali::Handle& handle, const Replacement& constant )
330 {
331   if( Actor actor = Actor::DownCast(handle) )
332   {
333     SetProperties( node, actor, constant );
334
335     if( actor )
336     {
337       SetupActor( node, actor, constant );
338
339       // add signals
340       SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
341       SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
342    }
343   }
344   else
345   {
346     SetProperties( node, handle, constant );
347   }
348 }
349
350 // Appling by style helper
351 // use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node
352 void Builder::ApplyStylesByActor(  const TreeNode& root, const TreeNode& node,
353                                    Dali::Handle& handle, const Replacement& constant )
354 {
355   if( Dali::Actor actor = Dali::Actor::DownCast( handle ) )
356   {
357     if( const TreeNode* actors = node.GetChild( KEYNAME_ACTORS ) )
358     {
359       // in a style the actor subtree properties referenced by actor name
360       for( TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter )
361       {
362         Dali::Actor foundActor;
363
364         if( (*iter).first )
365         {
366           foundActor = actor.FindChildByName( (*iter).first );
367         }
368
369         if( !foundActor )
370         {
371           // debug log cannot find searched for actor
372 #if defined(DEBUG_ENABLED)
373           DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first);
374 #endif
375         }
376         else
377         {
378 #if defined(DEBUG_ENABLED)
379           DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first);
380 #endif
381           ApplyProperties( root, (*iter).second, foundActor, constant );
382         }
383       }
384     }
385   }
386 }
387
388
389 void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node,
390                                        Dali::Handle& handle, const Replacement& constant )
391 {
392   OptionalChild styles = IsChild(root, KEYNAME_STYLES);
393   OptionalChild style  = IsChild(node, KEYNAME_STYLES);
394
395   if( styles && style )
396   {
397     TreeNodeList additionalStyles;
398
399     CollectAllStyles( *styles, *style, additionalStyles );
400
401 #if defined(DEBUG_ENABLED)
402     for(TreeNode::ConstIterator iter = (*style).CBegin(); iter != (*style).CEnd(); ++iter)
403     {
404       if( OptionalString styleName = IsString( (*iter).second ) )
405       {
406         DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str());
407       }
408     }
409 #endif
410
411     // a style may have other styles, which has other styles etc so we apply in reverse by convention.
412     for(TreeNodeList::reverse_iterator iter = additionalStyles.rbegin(); iter != additionalStyles.rend(); ++iter)
413     {
414       ApplyProperties( root, *(*iter), handle, constant );
415
416       ApplyStylesByActor( root, *(*iter), handle, constant );
417     }
418   }
419
420   // applying given node last
421   ApplyProperties( root, node, handle, constant );
422
423   ApplyStylesByActor( root, node, handle, constant );
424
425 }
426
427
428 /*
429  * Create a dali type from a node.
430  * If parent given and an actor type was created then add it to the parent and
431  * recursively add nodes children.
432  */
433 BaseHandle Builder::DoCreate( const TreeNode& root, const TreeNode& node,
434                               Actor parent, const Replacement& replacements )
435 {
436   BaseHandle baseHandle;
437   TypeInfo typeInfo;
438   const TreeNode* templateNode = NULL;
439
440   if( OptionalString typeName = IsString(node, KEYNAME_TYPE) )
441   {
442     typeInfo = TypeRegistry::Get().GetTypeInfo( *typeName );
443
444     if( !typeInfo )
445     {
446       // a template name is also allowed inplace of the type name
447       OptionalChild templates = IsChild( root, KEYNAME_TEMPLATES);
448
449       if( templates )
450       {
451         if( OptionalChild isTemplate = IsChild( *templates, *typeName ) )
452         {
453           templateNode = &(*isTemplate);
454
455           if( OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE) )
456           {
457             typeInfo = TypeRegistry::Get().GetTypeInfo( *templateTypeName );
458           }
459         }
460       }
461     }
462   }
463
464   if(!typeInfo)
465   {
466     DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName());
467   }
468   else
469   {
470     baseHandle       = typeInfo.CreateInstance();
471     Handle handle    = Handle::DownCast(baseHandle);
472     Actor actor      = Actor::DownCast(handle);
473
474     if(handle)
475     {
476
477       DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str());
478
479 #if defined(DEBUG_ENABLED)
480       if(handle)
481       {
482         DALI_SCRIPT_VERBOSE("  Is Handle Object=%d\n", (long*)handle.GetObjectPtr());
483         DALI_SCRIPT_VERBOSE("  Is Handle Property Count=%d\n", handle.GetPropertyCount());
484       }
485
486       if(actor)
487       {
488         DALI_SCRIPT_VERBOSE("  Is Actor id=%d\n", actor.GetId());
489       }
490
491       Toolkit::Control control  = Toolkit::Control::DownCast(handle);
492       if(control)
493       {
494         DALI_SCRIPT_VERBOSE("  Is Control id=%d\n", actor.GetId());
495       }
496 #endif // DEBUG_ENABLED
497
498       if( templateNode )
499       {
500         ApplyProperties( root, *templateNode, handle, replacements );
501
502         if( OptionalChild actors = IsChild( *templateNode, KEYNAME_ACTORS ) )
503         {
504           for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter )
505           {
506             DoCreate( root, (*iter).second, actor, replacements );
507           }
508         }
509       }
510
511       if( actor )
512       {
513         // add children of all the styles
514         if( OptionalChild actors = IsChild( node, KEYNAME_ACTORS ) )
515         {
516           for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter )
517           {
518             DoCreate( root, (*iter).second, actor, replacements );
519           }
520         }
521
522         // apply style on top as they need the children to exist
523         ApplyAllStyleProperties( root, node, actor, replacements );
524
525         // then add to parent
526         if( parent )
527         {
528           parent.Add( actor );
529         }
530       }
531       else
532       {
533         ApplyProperties( root, node, handle, replacements );
534       }
535     }
536     else
537     {
538       DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str());
539     }
540   }
541
542   return baseHandle;
543 }
544
545 void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant )
546 {
547   const Stage& stage = Stage::GetCurrent();
548   Layer root  = stage.GetRootLayer();
549
550   if( OptionalString s = constant.IsString( IsChild(node, "source-actor") ) )
551   {
552     Actor actor = root.FindChildByName(*s);
553     if(actor)
554     {
555       task.SetSourceActor( actor );
556     }
557     else
558     {
559       DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str() );
560     }
561   }
562
563   if( OptionalString s = constant.IsString( IsChild(node, "camera-actor") ) )
564   {
565     CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) );
566     if(actor)
567     {
568       task.SetCameraActor( actor );
569     }
570     else
571     {
572       DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str() );
573     }
574   }
575
576   if( OptionalString s = constant.IsString( IsChild(node, "target-frame-buffer") ) )
577   {
578     FrameBufferImage fb = GetFrameBufferImage( *s, constant );
579     if(fb)
580     {
581       task.SetTargetFrameBuffer( fb );
582     }
583     else
584     {
585       DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() );
586     }
587   }
588
589   if( OptionalString s = constant.IsString( IsChild(node, "screen-to-frame-buffer-function") ) )
590   {
591     if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s)
592     {
593       task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION );
594     }
595     else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s)
596     {
597       task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
598     }
599     else
600     {
601       DALI_SCRIPT_WARNING("todo");
602     }
603   }
604
605   // other setup is via the property system
606   SetProperties( node, task, constant ); // @ todo, remove 'source-actor', 'camera-actor'?
607
608 }
609
610 void Builder::CreateRenderTask( const std::string &name )
611 {
612   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
613
614   Replacement constant(mReplacementMap);
615
616   const Stage& stage = Stage::GetCurrent();
617
618   OptionalChild tasks = IsChild(*mParser.GetRoot(), "render-tasks");
619
620   if(tasks)
621   {
622     //
623     // Create the tasks from the current task as generally we want
624     // to setup task zero and onwards. Although this does overwrite
625     // the properties of the current task.
626     //
627     if( OptionalChild renderTask = IsChild(*tasks, name ) )
628     {
629       RenderTaskList list = stage.GetRenderTaskList();
630       unsigned int start = list.GetTaskCount();
631
632       RenderTask task;
633       if(0 == start)
634       {
635         // zero should have already been created by the stage so really
636         // this case should never happen
637         task = list.CreateTask();
638         start++;
639       }
640
641       TreeNode::ConstIterator iter = (*renderTask).CBegin();
642       task = list.GetTask( start - 1 );
643
644       SetupTask( task, (*iter).second, constant  );
645
646       ++iter;
647
648       for(; iter != (*renderTask).CEnd(); ++iter )
649       {
650         task = list.CreateTask();
651         SetupTask( task, (*iter).second, constant );
652       }
653     }
654   }
655 }
656
657 ShaderEffect Builder::GetShaderEffect( const std::string &name)
658 {
659   Replacement constant( mReplacementMap );
660   return GetShaderEffect( name, constant );
661 }
662
663 ShaderEffect Builder::GetShaderEffect( const std::string &name, const Replacement& constant )
664 {
665   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
666
667   ShaderEffect ret;
668
669   ShaderEffectLut::const_iterator iter( mShaderEffectLut.find( name ) );
670   if( iter != mShaderEffectLut.end() )
671   {
672     ret = iter->second;
673   }
674   else
675   {
676     if( OptionalChild effects = IsChild( *mParser.GetRoot(), "shader-effects") )
677     {
678       if( OptionalChild effect = IsChild( *effects, name ) )
679       {
680         Dali::Property::Value propertyMap(Property::MAP);
681         if( SetPropertyFromNode( *effect, Property::MAP, propertyMap, constant ) )
682         {
683           ret = Dali::Scripting::NewShaderEffect( propertyMap );
684           mShaderEffectLut[ name ] = ret;
685         }
686       }
687     }
688   }
689
690   return ret;
691 }
692
693 FrameBufferImage Builder::GetFrameBufferImage( const std::string &name )
694 {
695   Replacement constant( mReplacementMap );
696   return GetFrameBufferImage(name, constant);
697 }
698
699 FrameBufferImage Builder::GetFrameBufferImage( const std::string &name, const Replacement& constant )
700 {
701   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
702
703   FrameBufferImage ret;
704
705   ImageLut::const_iterator iter( mFrameBufferImageLut.find( name ) );
706   if( iter != mFrameBufferImageLut.end() )
707   {
708     ret = iter->second;
709   }
710   else
711   {
712     if( OptionalChild images = IsChild( *mParser.GetRoot(), "frame-buffer-images") )
713     {
714       if( OptionalChild image = IsChild( *images, name ) )
715       {
716         Dali::Property::Value property(Property::MAP);
717         if( SetPropertyFromNode( *image, Property::MAP, property, constant ) )
718         {
719           Property::Map* map = property.GetMap();
720
721           if( map )
722           {
723             (*map)[ KEYNAME_TYPE ] = Property::Value(std::string("FrameBufferImage") );
724             ret = FrameBufferImage::DownCast( Dali::Scripting::NewImage( property ) );
725             mFrameBufferImageLut[ name ] = ret;
726           }
727         }
728       }
729     }
730   }
731
732   return ret;
733 }
734
735 Path Builder::GetPath( const std::string& name )
736 {
737   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
738
739   Path ret;
740
741   PathLut::const_iterator iter( mPathLut.find( name ) );
742   if( iter != mPathLut.end() )
743   {
744     ret = iter->second;
745   }
746   else
747   {
748     if( OptionalChild paths = IsChild( *mParser.GetRoot(), "paths") )
749     {
750       if( OptionalChild path = IsChild( *paths, name ) )
751       {
752         //points property
753         if( OptionalChild pointsProperty = IsChild( *path, "points") )
754         {
755           Dali::Property::Value points(Property::ARRAY);
756           if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
757           {
758             ret = Path::New();
759             ret.SetProperty( Path::Property::POINTS, points);
760
761             //control-points property
762             if( OptionalChild pointsProperty = IsChild( *path, "control-points") )
763             {
764               Dali::Property::Value points(Property::ARRAY);
765               if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
766               {
767                 ret.SetProperty( Path::Property::CONTROL_POINTS, points);
768               }
769             }
770             else
771             {
772               //Curvature
773               float curvature(0.25f);
774               if( OptionalFloat pointsProperty = IsFloat( *path, "curvature") )
775               {
776                 curvature = *pointsProperty;
777               }
778               ret.GenerateControlPoints(curvature);
779             }
780
781             //Add the new path to the hash table for paths
782             mPathLut[ name ] = ret;
783           }
784         }
785         else
786         {
787           //Interpolation points not specified
788           DALI_SCRIPT_WARNING("Interpolation points not specified for path '%s'\n", name.c_str() );
789         }
790       }
791
792     }
793   }
794
795   return ret;
796 }
797
798 PathConstrainer Builder::GetPathConstrainer( const std::string& name )
799 {
800   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
801
802   //Search the pathConstrainer in the LUT
803   size_t count( mPathConstrainerLut.size() );
804   for( size_t i(0); i!=count; ++i )
805   {
806     if( mPathConstrainerLut[i].name == name )
807     {
808       //PathConstrainer has already been created
809       return mPathConstrainerLut[i].pathConstrainer;
810     }
811   }
812
813   //Create a new PathConstrainer
814   PathConstrainer ret;
815   if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") )
816   {
817     if( OptionalChild pathConstrainer = IsChild( *constrainers, name ) )
818     {
819       OptionalString constrainerType(IsString(IsChild(*pathConstrainer, "type")));
820       if(!constrainerType)
821       {
822         DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str() );
823       }
824       else if( *constrainerType == "PathConstrainer")
825       {
826         //points property
827         if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "points") )
828         {
829           Dali::Property::Value points(Property::ARRAY);
830           if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
831           {
832             ret = PathConstrainer::New();
833             ret.SetProperty( PathConstrainer::Property::POINTS, points);
834
835             //control-points property
836             if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "control-points") )
837             {
838               Dali::Property::Value points(Property::ARRAY);
839               if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
840               {
841                 ret.SetProperty( PathConstrainer::Property::CONTROL_POINTS, points);
842               }
843
844               //Forward vector
845               OptionalVector3 forward( IsVector3( IsChild(*pathConstrainer, "forward" ) ) );
846               if( forward )
847               {
848                 ret.SetProperty( PathConstrainer::Property::FORWARD, *forward);
849               }
850
851               //Add the new constrainer to the vector of PathConstrainer
852               PathConstrainerEntry entry = {name,ret};
853               mPathConstrainerLut.push_back( entry );
854             }
855             else
856             {
857               //Control points not specified
858               DALI_SCRIPT_WARNING("Control points not specified for pathConstrainer '%s'\n", name.c_str() );
859             }
860           }
861         }
862         else
863         {
864           //Interpolation points not specified
865           DALI_SCRIPT_WARNING("Interpolation points not specified for pathConstrainer '%s'\n", name.c_str() );
866         }
867       }
868       else
869       {
870         DALI_SCRIPT_WARNING("Constrainer '%s' is not a PathConstrainer\n", name.c_str() );
871       }
872     }
873   }
874
875   return ret;
876 }
877
878 bool Builder::IsPathConstrainer( const std::string& name )
879 {
880   size_t count( mPathConstrainerLut.size() );
881   for( size_t i(0); i!=count; ++i )
882   {
883     if( mPathConstrainerLut[i].name == name )
884     {
885       return true;
886     }
887   }
888
889   if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") )
890   {
891     if( OptionalChild constrainer = IsChild( *constrainers, name ) )
892     {
893       OptionalString constrainerType(IsString(IsChild(*constrainer, "type")));
894       if(!constrainerType)
895       {
896         return false;
897       }
898       else
899       {
900          return *constrainerType == "PathConstrainer";
901       }
902     }
903   }
904   return false;
905 }
906
907 Dali::LinearConstrainer Builder::GetLinearConstrainer( const std::string& name )
908 {
909   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
910
911   //Search the LinearConstrainer in the LUT
912   size_t count( mLinearConstrainerLut.size() );
913   for( size_t i(0); i!=count; ++i )
914   {
915     if( mLinearConstrainerLut[i].name == name )
916     {
917       //LinearConstrainer has already been created
918       return mLinearConstrainerLut[i].linearConstrainer;
919     }
920   }
921
922   //Create a new LinearConstrainer
923   LinearConstrainer ret;
924   if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") )
925   {
926     if( OptionalChild linearConstrainer = IsChild( *constrainers, name ) )
927     {
928       OptionalString constrainerType(IsString(IsChild(*linearConstrainer, "type")));
929       if(!constrainerType)
930       {
931         DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str() );
932       }
933       else if( *constrainerType == "LinearConstrainer")
934       {
935         //points property
936         if( OptionalChild pointsProperty = IsChild( *linearConstrainer, "value") )
937         {
938           Dali::Property::Value points(Property::ARRAY);
939           if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
940           {
941             ret = Dali::LinearConstrainer::New();
942             ret.SetProperty( LinearConstrainer::Property::VALUE, points);
943
944             //control-points property
945             if( OptionalChild pointsProperty = IsChild( *linearConstrainer, "progress") )
946             {
947               Dali::Property::Value points(Property::ARRAY);
948               if( SetPropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
949               {
950                 ret.SetProperty( LinearConstrainer::Property::PROGRESS, points);
951               }
952             }
953             //Add the new constrainer to vector of LinearConstrainer
954             LinearConstrainerEntry entry = {name,ret};
955             mLinearConstrainerLut.push_back( entry );
956           }
957         }
958         else
959         {
960           //Interpolation points not specified
961           DALI_SCRIPT_WARNING("Values not specified for LinearConstrainer '%s'\n", name.c_str() );
962         }
963       }
964       else
965       {
966         DALI_SCRIPT_WARNING("Constrainer '%s' is not a LinearConstrainer\n", name.c_str() );
967       }
968     }
969   }
970
971   return ret;
972 }
973
974 bool Builder::IsLinearConstrainer( const std::string& name )
975 {
976   //Search the LinearConstrainer in the LUT
977   size_t count( mLinearConstrainerLut.size() );
978   for( size_t i(0); i!=count; ++i )
979   {
980     if( mLinearConstrainerLut[i].name == name )
981     {
982       return true;
983     }
984   }
985
986   if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") )
987   {
988     if( OptionalChild constrainer = IsChild( *constrainers, name ) )
989     {
990       OptionalString constrainerType(IsString(IsChild(*constrainer, "type")));
991       if(!constrainerType)
992       {
993         return false;
994       }
995       else
996       {
997          return *constrainerType == "LinearConstrainer";
998       }
999     }
1000   }
1001   return false;
1002 }
1003
1004 Toolkit::Builder::BuilderSignalType& Builder::QuitSignal()
1005 {
1006   return mQuitSignal;
1007 }
1008
1009 void Builder::EmitQuitSignal()
1010 {
1011   mQuitSignal.Emit();
1012 }
1013
1014 void Builder::AddActors( Actor toActor )
1015 {
1016   // 'stage' is the default/by convention section to add from
1017   AddActors( "stage", toActor );
1018 }
1019
1020 void Builder::AddActors( const std::string &sectionName, Actor toActor )
1021 {
1022   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
1023
1024   Property::Map overrideMap;
1025   Replacement replacements(overrideMap, mReplacementMap);
1026
1027   OptionalChild add = IsChild(*mParser.GetRoot(), sectionName);
1028
1029   if( add )
1030   {
1031     for( TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter )
1032     {
1033       // empty actor adds directly to the stage
1034       BaseHandle baseHandle = DoCreate( *mParser.GetRoot(), (*iter).second, Actor(), replacements );
1035       Actor actor = Actor::DownCast(baseHandle);
1036       if(actor)
1037       {
1038         toActor.Add( actor );
1039       }
1040     }
1041
1042     // if were adding the 'stage' section then also check for a render task called stage
1043     // to add automatically
1044     if( "stage" == sectionName )
1045     {
1046       if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "render-tasks") )
1047       {
1048         if( OptionalChild tasks = IsChild(*renderTasks, "stage") )
1049         {
1050           CreateRenderTask( "stage" );
1051         }
1052       }
1053     }
1054   }
1055 }
1056
1057 Animation Builder::CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor )
1058 {
1059   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
1060
1061   Animation anim;
1062
1063   if( OptionalChild animations = IsChild(*mParser.GetRoot(), "animations") )
1064   {
1065     if( OptionalChild animation = IsChild(*animations, animationName) )
1066     {
1067       anim = Dali::Toolkit::Internal::CreateAnimation( *animation, replacement, sourceActor, this );
1068     }
1069     else
1070     {
1071       DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed\n", animationName.c_str() );
1072     }
1073   }
1074   else
1075   {
1076     DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed (no animation section)\n", animationName.c_str() );
1077   }
1078
1079   return anim;
1080 }
1081
1082 Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor )
1083 {
1084   Replacement replacement(map, mReplacementMap);
1085   return CreateAnimation( animationName, replacement, sourceActor);
1086 }
1087
1088 Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map )
1089 {
1090   Replacement replacement(map, mReplacementMap);
1091   return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() );
1092 }
1093
1094 Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor )
1095 {
1096   Replacement replacement( mReplacementMap );
1097
1098   return CreateAnimation( animationName, replacement, sourceActor );
1099 }
1100
1101 Animation Builder::CreateAnimation( const std::string& animationName )
1102 {
1103   Replacement replacement( mReplacementMap );
1104
1105   return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() );
1106 }
1107
1108 void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format )
1109 {
1110   // parser to get constants and includes only
1111   Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New();
1112
1113   if( !parser.Parse( data ) )
1114   {
1115     DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n",
1116                       parser.GetErrorLineNumber(),
1117                       parser.GetErrorColumn(),
1118                       parser.GetErrorDescription().c_str() );
1119
1120     DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
1121
1122   }
1123   else
1124   {
1125     // load constant map (allows the user to override the constants in the json after loading)
1126     LoadConstants( *parser.GetRoot(), mReplacementMap );
1127
1128     // merge includes
1129     if( OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES) )
1130     {
1131       Replacement replacer( mReplacementMap );
1132
1133       for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter)
1134       {
1135         OptionalString filename = replacer.IsString( (*iter).second );
1136
1137         if( filename )
1138         {
1139 #if defined(DEBUG_ENABLED)
1140           DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str());
1141 #endif
1142           LoadFromString( GetFileContents(*filename) );
1143         }
1144       }
1145     }
1146
1147     if( !mParser.Parse( data ) )
1148     {
1149       DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n",
1150                         mParser.GetErrorLineNumber(),
1151                         mParser.GetErrorColumn(),
1152                         mParser.GetErrorDescription().c_str() );
1153
1154       DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
1155     }
1156   }
1157
1158   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
1159
1160 }
1161
1162 void Builder::AddConstants( const Property::Map& map )
1163 {
1164   mReplacementMap.Merge( map );
1165 }
1166
1167 void Builder::AddConstant( const std::string& key, const Property::Value& value )
1168 {
1169   mReplacementMap[key] = value;
1170 }
1171
1172 const Property::Map& Builder::GetConstants() const
1173 {
1174   return mReplacementMap;
1175 }
1176
1177 const Property::Value& Builder::GetConstant( const std::string& key ) const
1178 {
1179   Property::Value* match = mReplacementMap.Find( key );
1180   if( match )
1181   {
1182     return (*match);
1183   }
1184   else
1185   {
1186     static Property::Value invalid;
1187     return invalid;
1188   }
1189 }
1190
1191 void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap )
1192 {
1193   Replacement replacer(intoMap);
1194
1195   if( OptionalChild constants = IsChild(root, "constants") )
1196   {
1197     for(TreeNode::ConstIterator iter = (*constants).CBegin();
1198         iter != (*constants).CEnd(); ++iter)
1199     {
1200       Dali::Property::Value property;
1201       if( (*iter).second.GetName() )
1202       {
1203 #if defined(DEBUG_ENABLED)
1204         DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName());
1205 #endif
1206         if( SetPropertyFromNode( (*iter).second, property, replacer ) )
1207         {
1208           intoMap[ (*iter).second.GetName() ] = property;
1209         }
1210         else
1211         {
1212           DALI_SCRIPT_WARNING("Cannot convert property for constant %s\n",
1213                               (*iter).second.GetName() == NULL ? "no name?" : (*iter).second.GetName());
1214         }
1215       }
1216     }
1217   }
1218
1219 #if defined(DEBUG_ENABLED)
1220   Property::Value* iter = intoMap.Find( "CONFIG_SCRIPT_LOG_LEVEL" );
1221   if( iter && iter->GetType() == Property::STRING )
1222   {
1223     std::string logLevel( iter->Get< std::string >() );
1224     if( logLevel == "NoLogging" )
1225     {
1226       gFilterScript->SetLogLevel( Integration::Log::NoLogging );
1227     }
1228     else if( logLevel == "Concise" )
1229     {
1230       gFilterScript->SetLogLevel( Integration::Log::Concise );
1231     }
1232     else if( logLevel == "General" )
1233     {
1234       gFilterScript->SetLogLevel( Integration::Log::General );
1235     }
1236     else if( logLevel == "Verbose" )
1237     {
1238       gFilterScript->SetLogLevel( Integration::Log::Verbose );
1239     }
1240   }
1241 #endif
1242
1243 }
1244
1245 bool Builder::ApplyStyle( const std::string& styleName, Handle& handle )
1246 {
1247   Replacement replacer( mReplacementMap );
1248   return ApplyStyle( styleName, handle, replacer );
1249 }
1250
1251 bool Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement )
1252 {
1253   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
1254
1255   OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES );
1256   OptionalChild style  = IsChild( *styles, styleName );
1257
1258   if( styles && style )
1259   {
1260     ApplyAllStyleProperties( *mParser.GetRoot(), *style, handle, replacement );
1261     return true;
1262   }
1263   else
1264   {
1265     return false;
1266   }
1267 }
1268
1269 BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map )
1270 {
1271   Replacement replacement( map, mReplacementMap );
1272   return Create( templateName, replacement );
1273 }
1274
1275 BaseHandle Builder::Create( const std::string& templateName, const Replacement& constant )
1276 {
1277   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
1278
1279   BaseHandle baseHandle;
1280
1281   OptionalChild templates = IsChild(*mParser.GetRoot(), KEYNAME_TEMPLATES);
1282
1283   if( !templates )
1284   {
1285     DALI_SCRIPT_WARNING("No template section found to CreateFromTemplate\n");
1286   }
1287   else
1288   {
1289     OptionalChild childTemplate = IsChild(*templates, templateName);
1290     if(!childTemplate)
1291     {
1292       DALI_SCRIPT_WARNING("Template '%s' does not exist in template section\n", templateName.c_str());
1293     }
1294     else
1295     {
1296       OptionalString type = constant.IsString( IsChild(*childTemplate, KEYNAME_TYPE) );
1297
1298       if(!type)
1299       {
1300         DALI_SCRIPT_WARNING("Cannot create template '%s' as template section is missing 'type'\n", templateName.c_str());
1301       }
1302       else
1303       {
1304         baseHandle = DoCreate( *mParser.GetRoot(), *childTemplate, Actor(), constant );
1305       }
1306     }
1307   }
1308
1309   return baseHandle;
1310 }
1311
1312 BaseHandle Builder::CreateFromJson( const std::string& json )
1313 {
1314   BaseHandle ret;
1315
1316   // merge in new template, hoping no one else has one named '@temp@'
1317   std::string newTemplate =
1318     std::string("{\"templates\":{\"@temp@\":") +                      \
1319     json +                                                            \
1320     std::string("}}");
1321
1322   if( mParser.Parse(newTemplate) )
1323   {
1324     Replacement replacement( mReplacementMap );
1325     ret = Create( "@temp@", replacement );
1326   }
1327
1328   return ret;
1329 }
1330
1331 bool Builder::ApplyFromJson(  Handle& handle, const std::string& json )
1332 {
1333   bool ret = false;
1334
1335   // merge new style, hoping no one else has one named '@temp@'
1336   std::string newStyle =
1337     std::string("{\"styles\":{\"@temp@\":") +                           \
1338     json +                                                              \
1339     std::string("}}");
1340
1341   if( mParser.Parse(newStyle) )
1342   {
1343     Replacement replacement( mReplacementMap );
1344     ret = ApplyStyle( "@temp@", handle, replacement );
1345   }
1346
1347   return ret;
1348 }
1349
1350
1351 BaseHandle Builder::Create( const std::string& templateName )
1352 {
1353   Replacement replacement( mReplacementMap );
1354   return Create( templateName, replacement );
1355 }
1356
1357 Builder::Builder()
1358 : mSlotDelegate( this )
1359 {
1360   mParser = Dali::Toolkit::JsonParser::New();
1361
1362   Property::Map defaultDirs;
1363   defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ]  = DALI_IMAGE_DIR;
1364   defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ]  = DALI_SOUND_DIR;
1365   defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ] = DALI_STYLE_DIR;
1366   defaultDirs[ TOKEN_STRING(DALI_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR;
1367
1368   AddConstants( defaultDirs );
1369 }
1370
1371 Builder::~Builder()
1372 {
1373 }
1374
1375 } // namespace Internal
1376
1377 } // namespace Toolkit
1378
1379 } // namespace Dali