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