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