[SRUK] Initial copy from Tizen 2.2 version
[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 Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali-toolkit/internal/builder/builder-impl.h>
19
20 // EXTERNAL INCLUDES
21 #include <sys/stat.h>
22
23 // INTERNAL INCLUDES
24 #include <dali/dali.h>
25 #include <dali/integration-api/debug.h>
26
27 #include <dali-toolkit/public-api/controls/control.h>
28
29 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
30 #include <dali-toolkit/internal/builder/builder-filesystem.h>
31 #include <dali-toolkit/internal/builder/builder-declarations.h>
32
33 namespace Dali
34 {
35
36 namespace Toolkit
37 {
38
39 namespace Internal
40 {
41
42 extern Animation CreateAnimation(const TreeNode& child);
43 extern bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value );
44 extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor);
45 extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor);
46 extern Actor SetupActor( const TreeNode& node, Actor& actor );
47 extern Control SetupControl( const TreeNode& node, Control& actor );
48
49 #if defined(DEBUG_ENABLED)
50 Integration::Log::Filter* gFilterScript  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT");
51 #endif
52
53 namespace
54 {
55
56 typedef std::vector<const TreeNode*> TreeNodeList;
57
58 /*
59  * Sets the handle properties found in the tree node
60  */
61 void SetProperties( const TreeNode& node, Handle& handle, Builder& builder )
62 {
63   if( handle )
64   {
65     for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
66     {
67       const TreeNode::KeyNodePair& keyChild = *iter;
68
69       std::string key( keyChild.first );
70
71       // ignore special fields; type,actors,signals
72       if(key == "type" || key == "actors" || key == "signals")
73       {
74         continue;
75       }
76
77       // special field 'image' usually contains an json object description
78       // although sometimes refers to a framebuffer
79       if( 0 == keyChild.second.Size() )
80       {
81         if(key == "image")
82         {
83           ImageActor imageActor = ImageActor::DownCast(handle);
84           if(imageActor)
85           {
86             if( OptionalString s = IsString( keyChild.second ) )
87             {
88               FrameBufferImage fb = builder.GetFrameBufferImage(*s);
89               if(fb)
90               {
91                 imageActor.SetImage( fb );
92               }
93             }
94           }
95         }
96       }
97
98       // special field 'effect' references the shader effect instances
99       if(key == "effect")
100       {
101         Actor actor = Actor::DownCast(handle);
102         OptionalString s = IsString( keyChild.second );
103         if(actor && s)
104         {
105           ShaderEffect e = builder.GetShaderEffect(*s);
106           actor.SetShaderEffect(e);
107         }
108         else
109         {
110           DALI_SCRIPT_WARNING("Could not find or set shader effect\n");
111         }
112
113         continue;
114       }
115
116       Property::Index index = handle.GetPropertyIndex(key);
117
118       if( Property::INVALID_INDEX != index )
119       {
120         Property::Type type = handle.GetPropertyType(index);
121
122         Property::Value value;
123         if( !SetPropertyFromNode( keyChild.second, type, value ) )
124         {
125           // verbose as this might not be a problem
126           // eg parent-origin can be a string which is picked up later
127           DALI_SCRIPT_VERBOSE("Could not convert property:%s\n", key.c_str());
128         }
129         else
130         {
131           DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d\n", key.c_str(), index, value.GetType());
132
133           handle.SetProperty( index, value );
134         }
135       }
136       else
137       {
138         DALI_SCRIPT_VERBOSE("SetProperty INVALID '%s' Index=:%d\n", key.c_str(), index);
139       }
140
141     } // for property nodes
142   }
143   else
144   {
145     DALI_SCRIPT_WARNING("Style applied to empty handle\n");
146   }
147 }
148
149 /*
150  * Split a string by delimiter
151  */
152 std::vector<std::string> SplitString(const std::string &s, char delim, std::vector<std::string> &elems)
153 {
154   std::stringstream ss(s);
155   std::string item;
156   while(std::getline(ss, item, delim))
157   {
158     elems.push_back(item);
159   }
160   return elems;
161 }
162
163 /*
164  * Recursively collects all styles listed in a json node 'type' field. (Could be a comma separated list).
165  * It also returns the first found base typeInfo from the TypeRegistry. This is the concrete object to instance.
166  * i.e. the type field can name a json style section or a TypeRegistry base type.
167  */
168 void CollectAllStyles( const TreeNode& styles, const std::string& typeStyleString, TreeNodeList& additionalStyles, TypeInfo& typeInfo )
169 {
170   typedef std::vector<std::string> StyleNames;
171   StyleNames styleNames;
172
173   SplitString(typeStyleString, ',', styleNames);
174
175   for(StyleNames::iterator iter = styleNames.begin(); iter != styleNames.end(); ++iter)
176   {
177     const std::string typeName(*iter);
178
179     OptionalChild style = IsChild(styles, typeName);
180     if(style)
181     {
182       additionalStyles.push_back(&(*style));
183
184       OptionalString styleType = IsString( IsChild(*style, "type") );
185       if( styleType )
186       {
187         CollectAllStyles(styles, *styleType, additionalStyles, typeInfo);
188       }
189       else
190       {
191         if(!typeInfo)
192         {
193           // if its not a style then check for a type but only the first found
194           typeInfo = TypeRegistry::Get().GetTypeInfo( typeName );
195         }
196       }
197     }
198     else
199     {
200       DALI_ASSERT_DEBUG(!typeInfo);
201       typeInfo = TypeRegistry::Get().GetTypeInfo( typeName );
202     }
203   }
204 }
205
206 /*
207  * Recursively collects all styles listed in a json node 'type' field. (Could be a comma separated list).
208  * Adds the given node to the end of the additional styles list.
209  * It also returns the first found base typeInfo from the TypeRegistry. This is the concrete object to instance.
210  * i.e. the type field can name a json style section or a TypeRegistry base type.
211  */
212 void CollectAllStyles( const OptionalChild& optionalStyles, const TreeNode& node, TreeNodeList& additionalStyles, TypeInfo& typeInfo )
213 {
214   OptionalString type = IsString( IsChild(node, "type") );
215
216   if(!type)
217   {
218     DALI_SCRIPT_WARNING("Cannot create style as type section is missing\n");
219   }
220   else
221   {
222     additionalStyles.push_back(&node);
223
224     if( optionalStyles )
225     {
226       CollectAllStyles( *optionalStyles, *type, additionalStyles, typeInfo );
227     }
228     else
229     {
230       typeInfo = TypeRegistry::Get().GetTypeInfo( *type );
231     }
232
233   }
234 }
235
236 /*
237  * Create a dali type from a node.
238  * If parent given and an actor type was created then add it to the parent and
239  * recursively add nodes children.
240  */
241 BaseHandle Create( ConnectionTracker* tracker, const OptionalChild& optionalStyles, const TreeNode& node, const TreeNode& root, Actor parent, Builder& builder )
242 {
243   BaseHandle baseHandle;
244   TreeNodeList allStyles;
245   TypeInfo typeInfo;
246
247   CollectAllStyles( optionalStyles, node, allStyles, typeInfo );
248
249   if(!typeInfo)
250   {
251     DALI_SCRIPT_WARNING("Unable to create Dali type from node\n");
252   }
253   else
254   {
255     baseHandle       = typeInfo.CreateInstance();
256     Handle handle    = Handle::DownCast(baseHandle);
257     Actor actor      = Actor::DownCast(handle);
258     Control control  = Control::DownCast(handle);
259
260     if(handle)
261     {
262
263       DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str());
264       DALI_SCRIPT_VERBOSE("  %d style sections\n", allStyles.size());
265
266 #if defined(DEBUG_ENABLED)
267       if(handle)
268       {
269         DALI_SCRIPT_VERBOSE("  Is Handle Object=%d\n", (long*)handle.GetObjectPtr());
270         DALI_SCRIPT_VERBOSE("  Is Handle Property Count=%d\n", handle.GetPropertyCount());
271       }
272
273       if(actor)
274       {
275         DALI_SCRIPT_VERBOSE("  Is Actor id=%d\n", actor.GetId());
276       }
277
278       if(control)
279       {
280         DALI_SCRIPT_VERBOSE("  Is Control id=%d\n", actor.GetId());
281       }
282 #endif // DEBUG_ENABLED
283
284       for(TreeNodeList::reverse_iterator iter = allStyles.rbegin(); iter != allStyles.rend(); ++iter)
285       {
286         SetProperties( *(*iter), handle, builder );
287
288         if( actor ) // if we created an actor
289         {
290           SetupActor( *(*iter), actor);
291
292           if( control )
293           {
294             SetupControl( *(*iter), control);
295           }
296
297           // add children of all the styles
298           if( OptionalChild actors = IsChild( *(*iter), "actors" ) )
299           {
300             for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter )
301             {
302               Create( tracker, optionalStyles, (*iter).second, root, actor, builder );
303             }
304           }
305         }
306       }
307
308       if( actor )
309       {
310         // add signals first
311         SetupSignalAction( tracker, root, node, actor );
312         SetupPropertyNotification( tracker, root, node, actor );
313
314         // then add to parent
315         if( parent )
316         {
317           parent.Add( actor );
318         }
319
320       }
321     }
322     else
323     {
324       DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str());
325     }
326   }
327
328   return baseHandle;
329 }
330
331
332 } // namespace anon
333
334
335 ActorContainer Builder::GetTopLevelActors() const
336 {
337   // deprecated function.
338   return ActorContainer();
339 }
340
341 Animation Builder::GetAnimation( const std::string &name ) const
342 {
343   // deprecated
344   return Animation();
345 }
346
347 void Builder::SetupTask( RenderTask& task, const TreeNode& node )
348 {
349   const Stage& stage = Stage::GetCurrent();
350   Layer root  = stage.GetRootLayer();
351
352   if( OptionalString s = IsString( IsChild(node, "source-actor") ) )
353   {
354     Actor actor = root.FindChildByName(*s);
355     if(actor)
356     {
357       task.SetSourceActor( actor );
358     }
359     else
360     {
361       DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str() );
362     }
363   }
364
365   if( OptionalString s = IsString( IsChild(node, "camera-actor") ) )
366   {
367     CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) );
368     if(actor)
369     {
370       task.SetCameraActor( actor );
371     }
372     else
373     {
374       DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str() );
375     }
376   }
377
378   if( OptionalString s = IsString( IsChild(node, "target-frame-buffer") ) )
379   {
380     FrameBufferImage fb = GetFrameBufferImage( *s );
381     if(fb)
382     {
383       task.SetTargetFrameBuffer( fb );
384     }
385     else
386     {
387       DALI_SCRIPT_WARNING("Cannot find target frame buffer '%s'\n", (*s).c_str() );
388     }
389   }
390
391   if( OptionalString s = IsString( IsChild(node, "screen-to-frame-buffer-function") ) )
392   {
393     if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s)
394     {
395       task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION );
396     }
397     else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s)
398     {
399       task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
400     }
401     else
402     {
403       DALI_SCRIPT_WARNING("todo");
404     }
405   }
406
407   // other setup is via the property system
408   SetProperties( node, task, *this ); // @ todo, remove 'source-actor', 'camera-actor'?
409
410 }
411
412 void Builder::CreateRenderTask( const std::string &name )
413 {
414   const Stage& stage = Stage::GetCurrent();
415
416   OptionalChild tasks = IsChild(*mParser.GetRoot(), "render-tasks");
417
418   if(tasks)
419   {
420     //
421     // Create the tasks from the current task as generally we want
422     // to setup task zero and onwards. Although this does overwrite
423     // the properties of the current task.
424     //
425     if( OptionalChild renderTask = IsChild(*tasks, name ) )
426     {
427       RenderTaskList list = stage.GetRenderTaskList();
428       unsigned int start = list.GetTaskCount();
429
430       RenderTask task;
431       if(0 == start)
432       {
433         // zero should have already been created by the stage so really
434         // this case should never happen
435         task = list.CreateTask();
436         start++;
437       }
438
439       TreeNode::ConstIterator iter = (*renderTask).CBegin();
440       task = list.GetTask( start - 1 );
441
442       SetupTask( task, (*iter).second );
443
444       ++iter;
445
446       for(; iter != (*renderTask).CEnd(); ++iter )
447       {
448         task = list.CreateTask();
449         SetupTask( task, (*iter).second );
450       }
451     }
452   }
453 }
454
455 ShaderEffect Builder::GetShaderEffect( const std::string &name )
456 {
457   ShaderEffect ret;
458
459   ShaderEffectLut::const_iterator iter( mShaderEffectLut.find( name ) );
460   if( iter != mShaderEffectLut.end() )
461   {
462     ret = iter->second;
463   }
464   else
465   {
466     if( OptionalChild effects = IsChild( *mParser.GetRoot(), "shader-effects") )
467     {
468       if( OptionalChild effect = IsChild( *effects, name ) )
469       {
470         Dali::Property::Value propertyMap(Property::MAP);
471         if( SetPropertyFromNode( *effect, Property::MAP, propertyMap ) )
472         {
473           ret = Dali::Scripting::NewShaderEffect( propertyMap );
474           mShaderEffectLut[ name ] = ret;
475         }
476       }
477     }
478   }
479
480   return ret;
481 }
482
483 FrameBufferImage Builder::GetFrameBufferImage( const std::string &name )
484 {
485   FrameBufferImage ret;
486
487   ImageLut::const_iterator iter( mFrameBufferImageLut.find( name ) );
488   if( iter != mFrameBufferImageLut.end() )
489   {
490     ret = iter->second;
491   }
492   else
493   {
494     if( OptionalChild images = IsChild( *mParser.GetRoot(), "frame-buffer-images") )
495     {
496       if( OptionalChild image = IsChild( *images, name ) )
497       {
498         Dali::Property::Value propertyMap(Property::MAP);
499         if( SetPropertyFromNode( *image, Property::MAP, propertyMap ) )
500         {
501           propertyMap.SetValue("type", Property::Value(std::string("FrameBufferImage")));
502           ret = Dali::Scripting::NewImage( propertyMap );
503           mFrameBufferImageLut[ name ] = ret;
504         }
505       }
506     }
507   }
508
509   return ret;
510 }
511
512 Font Builder::GetFont( const std::string& name ) const
513 {
514   // deprecated function.
515   Font font;
516   return font;
517 }
518
519 TextStyle Builder::GetTextStyle( const std::string& name ) const
520 {
521   // deprecated
522   return TextStyle();
523 }
524
525 Image Builder::GetImage( const std::string& name) const
526 {
527   // deprecated function.
528   return Image();
529 }
530
531 Actor Builder::GetActor( const std::string &name ) const
532 {
533   // deprecated function.
534   return Actor();
535 }
536
537 void Builder::AddActors( Actor toActor )
538 {
539   // 'stage' is the default/by convention section to add from
540   AddActors( "stage", toActor );
541 }
542
543 void Builder::AddActors( const std::string &sectionName, Actor toActor )
544 {
545   OptionalChild addToStage = IsChild(*mParser.GetRoot(), sectionName);
546
547   if( addToStage )
548   {
549     OptionalChild styles = IsChild(*mParser.GetRoot(), "styles");
550
551     for( TreeNode::ConstIterator iter = (*addToStage).CBegin(); iter != (*addToStage).CEnd(); ++iter )
552     {
553       // empty actor adds directly to the stage
554       BaseHandle baseHandle = Create( mSlotDelegate.GetConnectionTracker(), styles, (*iter).second, *mParser.GetRoot(), Actor(), *this);
555       Actor actor = Actor::DownCast(baseHandle);
556       if(actor)
557       {
558         toActor.Add( actor );
559       }
560     }
561
562     // if were adding the 'stage' section then also check for a render task called stage
563     // to add automatically
564     if( "stage" == sectionName )
565     {
566       if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "render-tasks") )
567       {
568         if( OptionalChild tasks = IsChild(*renderTasks, "stage") )
569         {
570           CreateRenderTask( "stage" );
571         }
572       }
573     }
574
575   }
576 }
577
578 Animation Builder::CreateAnimation( const std::string& animationName )
579 {
580   Animation anim;
581
582   if( OptionalChild animations = IsChild(*mParser.GetRoot(), "animations") )
583   {
584     if( OptionalChild animation = IsChild(*animations, animationName) )
585     {
586       anim = Dali::Toolkit::Internal::CreateAnimation( *animation );
587     }
588   }
589   else
590   {
591     DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed\n", animationName.c_str() );
592   }
593
594   return anim;
595 }
596
597 void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format )
598 {
599   DALI_ASSERT_ALWAYS( format == Dali::Toolkit::Builder::JSON && "Currently only JSON is supported" );
600
601   if( !mParser.Parse(data) )
602   {
603     DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n",
604                       mParser.GetErrorLineNumber(),
605                       mParser.GetErrorColumn(),
606                       mParser.GetErrorDescription().c_str() );
607
608     DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
609   }
610
611   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
612
613 }
614
615 void Builder::ApplyStyle( const std::string& styleName, Handle& handle )
616 {
617   OptionalChild styles = IsChild(*mParser.GetRoot(), "styles");
618
619   if( styles )
620   {
621     if( OptionalChild style = IsChild(*styles, styleName) )
622     {
623       TreeNodeList allStyles;
624       TypeInfo typeInfo;
625
626       CollectAllStyles( styles, *style, allStyles, typeInfo );
627
628       for(TreeNodeList::reverse_iterator iter = allStyles.rbegin(); iter != allStyles.rend(); ++iter)
629       {
630         SetProperties( *style, handle, *this );
631       }
632     }
633     else
634     {
635       DALI_SCRIPT_WARNING("Could not find style:%s\n", styleName.c_str());
636     }
637   }
638   else
639   {
640     DALI_SCRIPT_WARNING("No style section available for style:%s\n", styleName.c_str());
641   }
642 }
643
644 BaseHandle Builder::CreateFromStyle( const std::string& styleName )
645 {
646   BaseHandle baseHandle;
647
648   OptionalChild styles = IsChild(*mParser.GetRoot(), "styles");
649
650   if( !styles )
651   {
652     DALI_SCRIPT_WARNING("No style section found to CreateFromStyle\n");
653   }
654   else
655   {
656     OptionalChild style = IsChild(*styles, styleName);
657     if(!style)
658     {
659       DALI_SCRIPT_WARNING("Style '%s' does not exist in style section\n", styleName.c_str());
660     }
661     else
662     {
663       OptionalString type = IsString( IsChild(*style, "type") );
664
665       if(!type)
666       {
667         DALI_SCRIPT_WARNING("Cannot create style '%s' as style section is missing 'type'\n", styleName.c_str());
668       }
669       else
670       {
671         baseHandle = Create( mSlotDelegate.GetConnectionTracker(), styles, *style, *mParser.GetRoot(), Actor(), *this );
672       }
673     }
674   }
675
676   return baseHandle;
677 }
678
679 Builder::Builder()
680 : mSlotDelegate( this )
681 {
682   mParser = Dali::Toolkit::JsonParser::New();
683 }
684
685 Builder::~Builder()
686 {
687 }
688
689 } // namespace Internal
690
691 } // namespace Toolkit
692
693 } // namespace Dali