2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/builder/builder-impl.h>
25 #include <dali-toolkit/devel-api/controls/control-devel.h>
26 #include <dali/devel-api/common/stage.h>
27 #include <dali/devel-api/scripting/scripting.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/public-api/actors/camera-actor.h>
30 #include <dali/public-api/actors/layer.h>
31 #include <dali/public-api/object/property-array.h>
32 #include <dali/public-api/object/type-info.h>
33 #include <dali/public-api/object/type-registry.h>
34 #include <dali/public-api/render-tasks/render-task-list.h>
35 #include <dali/public-api/rendering/shader.h>
36 #include <dali/public-api/signals/functor-delegate.h>
39 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
40 #include <dali-toolkit/devel-api/builder/json-parser.h>
41 #include <dali-toolkit/public-api/controls/control.h>
43 #include <dali-toolkit/internal/builder/builder-declarations.h>
44 #include <dali-toolkit/internal/builder/builder-filesystem.h>
45 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
46 #include <dali-toolkit/internal/builder/builder-impl-debug.h>
47 #include <dali-toolkit/internal/builder/builder-set-property.h>
48 #include <dali-toolkit/internal/builder/replacement.h>
49 #include <dali-toolkit/internal/builder/tree-node-manipulator.h>
59 extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot, Builder* const builder);
61 extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode& root, const TreeNode& child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
63 extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode& root, const TreeNode& child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
65 #if defined(DEBUG_ENABLED)
66 Integration::Log::Filter* gFilterScript = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT");
71 #define TOKEN_STRING(x) #x
73 const char* KEYNAME_ACTORS = "actors";
74 const char* KEYNAME_ENTRY_TRANSITION = "entryTransition";
75 const char* KEYNAME_EXIT_TRANSITION = "exitTransition";
76 const char* KEYNAME_INCLUDES = "includes";
77 const char* KEYNAME_INHERIT = "inherit";
78 const char* KEYNAME_MAPPINGS = "mappings";
79 const char* KEYNAME_SIGNALS = "signals";
80 const char* KEYNAME_STATES = "states";
81 const char* KEYNAME_STYLES = "styles";
82 const char* KEYNAME_TEMPLATES = "templates";
83 const char* KEYNAME_TRANSITIONS = "transitions";
84 const char* KEYNAME_TYPE = "type";
85 const char* KEYNAME_VISUALS = "visuals";
87 const char* PROPERTIES = "properties";
88 const char* ANIMATABLE_PROPERTIES = "animatableProperties";
90 typedef std::vector<const TreeNode*> TreeNodeList;
92 bool GetMappingKey(const std::string& str, std::string& key)
95 std::string test(str);
100 if(test.at(test.length() - 1) == '>')
102 key = test.substr(1, test.length() - 2);
111 * Recursively collects all styles in a node (An array of style names).
113 * stylesCollection The set of styles from the json file (a json object of named styles)
114 * style The style array to begin the collection from
115 * styleList The style list to add nodes to apply
117 void CollectAllStyles(const TreeNode& stylesCollection, const TreeNode& style, TreeNodeList& styleList)
119 // style is an array of style names
120 if(TreeNode::ARRAY == style.GetType())
122 for(TreeNode::ConstIterator iter = style.CBegin(); iter != style.CEnd(); ++iter)
124 if(OptionalString styleName = IsString((*iter).second))
126 if(OptionalChild node = IsChildIgnoreCase(stylesCollection, *styleName))
128 styleList.push_back(&(*node));
130 OptionalChild subStyle = IsChild(*node, KEYNAME_INHERIT);
133 subStyle = IsChild(*node, KEYNAME_STYLES);
137 CollectAllStyles(stylesCollection, *subStyle, styleList);
148 : mSlotDelegate(this)
150 mParser = Dali::Toolkit::JsonParser::New();
152 Property::Map defaultConstants;
153 defaultConstants[TOKEN_STRING(DALI_IMAGE_DIR)] = AssetManager::GetDaliImagePath();
154 defaultConstants[TOKEN_STRING(DALI_SOUND_DIR)] = AssetManager::GetDaliSoundPath();
155 defaultConstants[TOKEN_STRING(DALI_STYLE_DIR)] = AssetManager::GetDaliStylePath();
156 defaultConstants[TOKEN_STRING(DALI_STYLE_IMAGE_DIR)] = AssetManager::GetDaliStyleImagePath();
157 defaultConstants[TOKEN_STRING(DALI_SHADER_VERSION_PREFIX)] = Shader::GetShaderVersionPrefix();
158 defaultConstants[TOKEN_STRING(DALI_VERTEX_SHADER_PREFIX)] = Shader::GetVertexShaderPrefix();
159 defaultConstants[TOKEN_STRING(DALI_FRAGMENT_SHADER_PREFIX)] = Shader::GetFragmentShaderPrefix();
161 AddConstants(defaultConstants);
164 void Builder::LoadFromString(std::string const& data, Dali::Toolkit::Builder::UIFormat format)
166 // parser to get constants and includes only
167 Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New();
169 if(!parser.Parse(data))
171 DALI_LOG_WARNING("JSON Parse Error:%d:%d:'%s'\n",
172 parser.GetErrorLineNumber(),
173 parser.GetErrorColumn(),
174 parser.GetErrorDescription().c_str());
176 DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
180 // load constant map (allows the user to override the constants in the json after loading)
181 LoadConstants(*parser.GetRoot(), mReplacementMap);
182 // load configuration map
183 LoadConfiguration(*parser.GetRoot(), mConfigurationMap);
185 if(OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES))
187 Replacement replacer(mReplacementMap);
189 for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter)
191 OptionalString filename = replacer.IsString((*iter).second);
195 #if defined(DEBUG_ENABLED)
196 DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str());
198 LoadFromString(GetFileContents(*filename));
203 if(mParser.Parse(data))
205 // Drop the styles and get them to be rebuilt against the new parse tree as required.
210 DALI_LOG_WARNING("JSON Parse Error:%d:%d:'%s'\n",
211 mParser.GetErrorLineNumber(),
212 mParser.GetErrorColumn(),
213 mParser.GetErrorDescription().c_str());
215 DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
219 DUMP_PARSE_TREE(mParser); // This macro only writes out if DEBUG is enabled and the "DUMP_TREE" constant is defined in the stylesheet.
220 DUMP_TEST_MAPPINGS(mParser);
222 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
225 void Builder::AddConstants(const Property::Map& map)
227 mReplacementMap.Merge(map);
230 void Builder::AddConstant(const std::string& key, const Property::Value& value)
232 mReplacementMap[key] = value;
235 const Property::Map& Builder::GetConfigurations() const
237 return mConfigurationMap;
240 const Property::Map& Builder::GetConstants() const
242 return mReplacementMap;
245 const Property::Value& Builder::GetConstant(const std::string& key) const
247 Property::Value* match = mReplacementMap.Find(key);
254 static Property::Value invalid;
259 Animation Builder::CreateAnimation(const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor)
261 Replacement replacement(map, mReplacementMap);
262 return CreateAnimation(animationName, replacement, sourceActor);
265 Animation Builder::CreateAnimation(const std::string& animationName, const Property::Map& map)
267 Replacement replacement(map, mReplacementMap);
268 return CreateAnimation(animationName, replacement, Stage::GetCurrent().GetRootLayer());
271 Animation Builder::CreateAnimation(const std::string& animationName, Dali::Actor sourceActor)
273 Replacement replacement(mReplacementMap);
275 return CreateAnimation(animationName, replacement, sourceActor);
278 Animation Builder::CreateAnimation(const std::string& animationName)
280 Replacement replacement(mReplacementMap);
282 return CreateAnimation(animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer());
285 BaseHandle Builder::Create(const std::string& templateName)
287 Replacement replacement(mReplacementMap);
288 return Create(templateName, replacement);
291 BaseHandle Builder::Create(const std::string& templateName, const Property::Map& map)
293 Replacement replacement(map, mReplacementMap);
294 return Create(templateName, replacement);
297 BaseHandle Builder::CreateFromJson(const std::string& json)
301 // merge in new template, hoping no one else has one named '@temp@'
302 std::string newTemplate =
303 std::string("{\"templates\":{\"@temp@\":") +
307 if(mParser.Parse(newTemplate))
309 Replacement replacement(mReplacementMap);
310 ret = Create("@temp@", replacement);
316 bool Builder::ApplyFromJson(Handle& handle, const std::string& json)
320 // merge new style, hoping no one else has one named '@temp@'
321 std::string newStyle =
322 std::string("{\"styles\":{\"@temp@\":") +
326 if(mParser.Parse(newStyle))
328 Replacement replacement(mReplacementMap);
329 ret = ApplyStyle("@temp@", handle, replacement);
335 bool Builder::ApplyStyle(const std::string& styleName, Handle& handle)
337 Replacement replacer(mReplacementMap);
338 return ApplyStyle(styleName, handle, replacer);
341 bool Builder::LookupStyleName(const std::string& styleName)
343 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
345 OptionalChild styles = IsChild(*mParser.GetRoot(), KEYNAME_STYLES);
346 OptionalChild style = IsChildIgnoreCase(*styles, styleName);
355 const StylePtr Builder::GetStyle(const std::string& styleName)
357 const StylePtr* style = mStyles.FindConst(styleName);
361 return StylePtr(NULL);
369 void Builder::AddActors(Actor toActor)
371 // 'stage' is the default/by convention section to add from
372 AddActors("stage", toActor);
375 void Builder::AddActors(const std::string& sectionName, Actor toActor)
377 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
379 Property::Map overrideMap;
380 Replacement replacements(overrideMap, mReplacementMap);
382 OptionalChild add = IsChild(*mParser.GetRoot(), sectionName);
386 for(TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter)
388 // empty actor adds directly to the stage
389 BaseHandle baseHandle = DoCreate(*mParser.GetRoot(), (*iter).second, Actor(), replacements);
390 Actor actor = Actor::DownCast(baseHandle);
397 // if were adding the 'stage' section then also check for a render task called stage
398 // to add automatically
399 if("stage" == sectionName)
401 if(OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "renderTasks"))
403 if(OptionalChild tasks = IsChild(*renderTasks, "stage"))
405 CreateRenderTask("stage");
412 void Builder::CreateRenderTask(const std::string& name)
414 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
416 Replacement constant(mReplacementMap);
418 const Stage& stage = Stage::GetCurrent();
420 OptionalChild tasks = IsChild(*mParser.GetRoot(), "renderTasks");
425 // Create the tasks from the current task as generally we want
426 // to setup task zero and onwards. Although this does overwrite
427 // the properties of the current task.
429 if(OptionalChild renderTask = IsChild(*tasks, name))
431 RenderTaskList list = stage.GetRenderTaskList();
432 unsigned int start = list.GetTaskCount();
437 // zero should have already been created by the stage so really
438 // this case should never happen
439 task = list.CreateTask();
443 TreeNode::ConstIterator iter = (*renderTask).CBegin();
444 task = list.GetTask(start - 1);
446 SetupTask(task, (*iter).second, constant);
450 for(; iter != (*renderTask).CEnd(); ++iter)
452 task = list.CreateTask();
453 SetupTask(task, (*iter).second, constant);
459 Path Builder::GetPath(const std::string& name)
461 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
465 PathLut::const_iterator iter(mPathLut.find(name));
466 if(iter != mPathLut.end())
472 if(OptionalChild paths = IsChild(*mParser.GetRoot(), "paths"))
474 if(OptionalChild path = IsChild(*paths, name))
477 if(OptionalChild pointsProperty = IsChild(*path, "points"))
479 Dali::Property::Value points(Property::ARRAY);
480 if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
483 ret.SetProperty(Path::Property::POINTS, points);
485 //controlPoints property
486 if(OptionalChild pointsProperty = IsChild(*path, "controlPoints"))
488 Dali::Property::Value points(Property::ARRAY);
489 if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
491 ret.SetProperty(Path::Property::CONTROL_POINTS, points);
497 float curvature(0.25f);
498 if(OptionalFloat pointsProperty = IsFloat(*path, "curvature"))
500 curvature = *pointsProperty;
502 ret.GenerateControlPoints(curvature);
505 //Add the new path to the hash table for paths
506 mPathLut[name] = ret;
511 //Interpolation points not specified
512 DALI_SCRIPT_WARNING("Interpolation points not specified for path '%s'\n", name.c_str());
521 PathConstrainer Builder::GetPathConstrainer(const std::string& name)
523 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
525 //Search the pathConstrainer in the LUT
526 size_t count(mPathConstrainerLut.size());
527 for(size_t i(0); i != count; ++i)
529 if(mPathConstrainerLut[i].name == name)
531 //PathConstrainer has already been created
532 return mPathConstrainerLut[i].pathConstrainer;
536 //Create a new PathConstrainer
538 if(OptionalChild constrainers = IsChild(*mParser.GetRoot(), "constrainers"))
540 if(OptionalChild pathConstrainer = IsChild(*constrainers, name))
542 OptionalString constrainerType(IsString(IsChild(*pathConstrainer, "type")));
545 DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str());
547 else if(*constrainerType == "PathConstrainer")
550 if(OptionalChild pointsProperty = IsChild(*pathConstrainer, "points"))
552 Dali::Property::Value points(Property::ARRAY);
553 if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
555 ret = PathConstrainer::New();
556 ret.SetProperty(PathConstrainer::Property::POINTS, points);
558 //controlPoints property
559 if(OptionalChild pointsProperty = IsChild(*pathConstrainer, "controlPoints"))
561 Dali::Property::Value points(Property::ARRAY);
562 if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
564 ret.SetProperty(PathConstrainer::Property::CONTROL_POINTS, points);
568 OptionalVector3 forward(IsVector3(IsChild(*pathConstrainer, "forward")));
571 ret.SetProperty(PathConstrainer::Property::FORWARD, *forward);
574 //Add the new constrainer to the vector of PathConstrainer
575 PathConstrainerEntry entry = {name, ret};
576 mPathConstrainerLut.push_back(entry);
580 //Control points not specified
581 DALI_SCRIPT_WARNING("Control points not specified for pathConstrainer '%s'\n", name.c_str());
587 //Interpolation points not specified
588 DALI_SCRIPT_WARNING("Interpolation points not specified for pathConstrainer '%s'\n", name.c_str());
593 DALI_SCRIPT_WARNING("Constrainer '%s' is not a PathConstrainer\n", name.c_str());
601 bool Builder::IsPathConstrainer(const std::string& name)
603 size_t count(mPathConstrainerLut.size());
604 for(size_t i(0); i != count; ++i)
606 if(mPathConstrainerLut[i].name == name)
612 if(OptionalChild constrainers = IsChild(*mParser.GetRoot(), "constrainers"))
614 if(OptionalChild constrainer = IsChild(*constrainers, name))
616 OptionalString constrainerType(IsString(IsChild(*constrainer, "type")));
623 return *constrainerType == "PathConstrainer";
630 Dali::LinearConstrainer Builder::GetLinearConstrainer(const std::string& name)
632 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
634 //Search the LinearConstrainer in the LUT
635 size_t count(mLinearConstrainerLut.size());
636 for(size_t i(0); i != count; ++i)
638 if(mLinearConstrainerLut[i].name == name)
640 //LinearConstrainer has already been created
641 return mLinearConstrainerLut[i].linearConstrainer;
645 //Create a new LinearConstrainer
646 LinearConstrainer ret;
647 if(OptionalChild constrainers = IsChild(*mParser.GetRoot(), "constrainers"))
649 if(OptionalChild linearConstrainer = IsChild(*constrainers, name))
651 OptionalString constrainerType(IsString(IsChild(*linearConstrainer, "type")));
654 DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str());
656 else if(*constrainerType == "LinearConstrainer")
659 if(OptionalChild pointsProperty = IsChild(*linearConstrainer, "value"))
661 Dali::Property::Value points(Property::ARRAY);
662 if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
664 ret = Dali::LinearConstrainer::New();
665 ret.SetProperty(LinearConstrainer::Property::VALUE, points);
667 //controlPoints property
668 if(OptionalChild pointsProperty = IsChild(*linearConstrainer, "progress"))
670 Dali::Property::Value points(Property::ARRAY);
671 if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
673 ret.SetProperty(LinearConstrainer::Property::PROGRESS, points);
676 //Add the new constrainer to vector of LinearConstrainer
677 LinearConstrainerEntry entry = {name, ret};
678 mLinearConstrainerLut.push_back(entry);
683 //Interpolation points not specified
684 DALI_SCRIPT_WARNING("Values not specified for LinearConstrainer '%s'\n", name.c_str());
689 DALI_SCRIPT_WARNING("Constrainer '%s' is not a LinearConstrainer\n", name.c_str());
697 bool Builder::IsLinearConstrainer(const std::string& name)
699 // Search the LinearConstrainer in the LUT
700 size_t count(mLinearConstrainerLut.size());
701 for(size_t i(0); i != count; ++i)
703 if(mLinearConstrainerLut[i].name == name)
709 if(OptionalChild constrainers = IsChild(*mParser.GetRoot(), "constrainers"))
711 if(OptionalChild constrainer = IsChild(*constrainers, name))
713 OptionalString constrainerType(IsString(IsChild(*constrainer, "type")));
720 return *constrainerType == "LinearConstrainer";
727 Toolkit::Builder::BuilderSignalType& Builder::QuitSignal()
732 void Builder::EmitQuitSignal()
741 void Builder::LoadConfiguration(const TreeNode& root, Property::Map& intoMap)
743 Replacement replacer(intoMap);
745 if(OptionalChild constants = IsChild(root, "config"))
747 for(TreeNode::ConstIterator iter = (*constants).CBegin();
748 iter != (*constants).CEnd();
751 Dali::Property::Value property;
752 if((*iter).second.GetName())
754 DeterminePropertyFromNode((*iter).second, property, replacer);
756 // If config is string, find constant and replace it to original value.
757 if((*iter).second.GetType() == TreeNode::STRING)
759 std::string stringConfigValue;
760 if(property.Get(stringConfigValue))
764 while(pos < stringConfigValue.size())
766 // If we can't find "{","}" pair in stringConfigValue, will out loop.
767 std::size_t leftPos = stringConfigValue.find("{", pos);
768 if(leftPos != std::string::npos)
770 std::size_t rightPos = stringConfigValue.find("}", pos + 1);
772 if(rightPos != std::string::npos)
774 // If we find "{","}" pair but can't find matched constant
775 // try to find other "{","}" pair after current left position.
778 for(uint32_t i = 0; i < mReplacementMap.Count(); i++)
780 Property::Key constant = mReplacementMap.GetKeyAt(i);
782 // Compare string which is between "{" and "}" with constant string
783 // If they are same, change string in stringConfigValue to mapped constant value.
784 if(0 == stringConfigValue.compare(leftPos + 1, rightPos - leftPos - 1, constant.stringKey))
786 std::string replaceString;
787 if(DALI_LIKELY(mReplacementMap.GetValue(i).Get(replaceString)))
789 stringConfigValue.replace(leftPos, rightPos - leftPos + 1, replaceString);
790 pos = leftPos + replaceString.size();
798 // If we cannot find constant in const value, will out loop.
799 pos = stringConfigValue.size();
804 // If we cannot find constant in const value, will out loop.
805 pos = stringConfigValue.size();
808 property = Property::Value(stringConfigValue);
811 intoMap[(*iter).second.GetName()] = property;
817 void Builder::LoadConstants(const TreeNode& root, Property::Map& intoMap)
819 Replacement replacer(intoMap);
821 if(OptionalChild constants = IsChild(root, "constants"))
823 for(TreeNode::ConstIterator iter = (*constants).CBegin();
824 iter != (*constants).CEnd();
827 Dali::Property::Value property;
828 if((*iter).second.GetName())
830 #if defined(DEBUG_ENABLED)
831 DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName());
833 DeterminePropertyFromNode((*iter).second, property, replacer);
834 intoMap[(*iter).second.GetName()] = property;
839 #if defined(DEBUG_ENABLED)
840 Property::Value* iter = intoMap.Find("CONFIG_SCRIPT_LOG_LEVEL");
841 if(iter && iter->GetType() == Property::STRING)
843 std::string logLevel(iter->Get<std::string>());
844 if(logLevel == "NoLogging")
846 gFilterScript->SetLogLevel(Integration::Log::NoLogging);
848 else if(logLevel == "Concise")
850 gFilterScript->SetLogLevel(Integration::Log::Concise);
852 else if(logLevel == "General")
854 gFilterScript->SetLogLevel(Integration::Log::General);
856 else if(logLevel == "Verbose")
858 gFilterScript->SetLogLevel(Integration::Log::Verbose);
864 Animation Builder::CreateAnimation(const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor)
866 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
870 if(OptionalChild animations = IsChild(*mParser.GetRoot(), "animations"))
872 if(OptionalChild animation = IsChild(*animations, animationName))
874 anim = Dali::Toolkit::Internal::CreateAnimation(*animation, replacement, sourceActor, this);
878 DALI_SCRIPT_WARNING("Request for Animation called '%s' failed\n", animationName.c_str());
883 DALI_SCRIPT_WARNING("Request for Animation called '%s' failed (no animation section)\n", animationName.c_str());
889 BaseHandle Builder::Create(const std::string& templateName, const Replacement& constant)
891 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
893 BaseHandle baseHandle;
895 OptionalChild templates = IsChild(*mParser.GetRoot(), KEYNAME_TEMPLATES);
899 DALI_SCRIPT_WARNING("No template section found to CreateFromTemplate\n");
903 OptionalChild childTemplate = IsChild(*templates, templateName);
906 DALI_SCRIPT_WARNING("Template '%s' does not exist in template section\n", templateName.c_str());
910 OptionalString type = constant.IsString(IsChild(*childTemplate, KEYNAME_TYPE));
914 DALI_SCRIPT_WARNING("Cannot create template '%s' as template section is missing 'type'\n", templateName.c_str());
918 baseHandle = DoCreate(*mParser.GetRoot(), *childTemplate, Actor(), constant);
927 * Create a dali type from a node.
928 * If parent given and an actor type was created then add it to the parent and
929 * recursively add nodes children.
931 BaseHandle Builder::DoCreate(const TreeNode& root, const TreeNode& node, Actor parent, const Replacement& replacements)
933 BaseHandle baseHandle;
935 const TreeNode* templateNode = NULL;
937 if(OptionalString typeName = IsString(node, KEYNAME_TYPE))
939 typeInfo = TypeRegistry::Get().GetTypeInfo(*typeName);
943 // a template name is also allowed inplace of the type name
944 OptionalChild templates = IsChild(root, KEYNAME_TEMPLATES);
948 if(OptionalChild isTemplate = IsChild(*templates, *typeName))
950 templateNode = &(*isTemplate);
952 if(OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE))
954 typeInfo = TypeRegistry::Get().GetTypeInfo(*templateTypeName);
963 DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName());
967 baseHandle = typeInfo.CreateInstance();
968 Handle handle = Handle::DownCast(baseHandle);
969 Actor actor = Actor::DownCast(handle);
973 DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str());
975 #if defined(DEBUG_ENABLED)
978 DALI_SCRIPT_VERBOSE(" Is Handle Object=%d\n", (long*)handle.GetObjectPtr());
979 DALI_SCRIPT_VERBOSE(" Is Handle Property Count=%d\n", handle.GetPropertyCount());
984 DALI_SCRIPT_VERBOSE(" Is Actor id=%d\n", actor.GetProperty<int>(Actor::Property::ID));
987 Toolkit::Control control = Toolkit::Control::DownCast(handle);
990 DALI_SCRIPT_VERBOSE(" Is Control id=%d\n", actor.GetProperty<int>(Actor::Property::ID));
992 #endif // DEBUG_ENABLED
996 ApplyProperties(root, *templateNode, handle, replacements);
998 if(OptionalChild actors = IsChild(*templateNode, KEYNAME_ACTORS))
1000 for(TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter)
1002 DoCreate(root, (*iter).second, actor, replacements);
1009 // add children of all the styles
1010 if(OptionalChild actors = IsChild(node, KEYNAME_ACTORS))
1012 for(TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter)
1014 DoCreate(root, (*iter).second, actor, replacements);
1018 // apply style on top as they need the children to exist
1019 ApplyAllStyleProperties(root, node, actor, replacements);
1021 // then add to parent
1029 ApplyProperties(root, node, handle, replacements);
1034 DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str());
1041 void Builder::SetupTask(RenderTask& task, const TreeNode& node, const Replacement& constant)
1043 const Stage& stage = Stage::GetCurrent();
1044 Layer root = stage.GetRootLayer();
1046 if(OptionalString s = constant.IsString(IsChild(node, "sourceActor")))
1048 Actor actor = root.FindChildByName(*s);
1051 task.SetSourceActor(actor);
1055 DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str());
1059 if(OptionalString s = constant.IsString(IsChild(node, "cameraActor")))
1061 CameraActor actor = CameraActor::DownCast(root.FindChildByName(*s));
1064 task.SetCameraActor(actor);
1068 DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str());
1072 if(OptionalString s = constant.IsString(IsChild(node, "screenToFrameBufferFunction")))
1074 if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s)
1076 task.SetScreenToFrameBufferFunction(RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION);
1078 else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s)
1080 task.SetScreenToFrameBufferFunction(RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
1084 DALI_SCRIPT_WARNING("todo");
1088 // other setup is via the property system
1089 SetProperties(node, task, constant);
1092 bool Builder::ApplyStyle(const std::string& styleName, Handle& handle, const Replacement& replacement)
1094 DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
1096 OptionalChild styles = IsChild(*mParser.GetRoot(), KEYNAME_STYLES);
1098 std::string styleNameLower(styleName);
1099 OptionalChild style = IsChildIgnoreCase(*styles, styleNameLower);
1103 ApplyAllStyleProperties(*mParser.GetRoot(), *style, handle, replacement);
1112 void Builder::ApplyAllStyleProperties(const TreeNode& root, const TreeNode& node, Dali::Handle& handle, const Replacement& constant)
1114 const char* styleName = node.GetName();
1116 StylePtr style = Style::New();
1118 StylePtr* matchedStyle = NULL;
1121 matchedStyle = mStyles.Find(styleName);
1124 OptionalChild styleNodes = IsChild(root, KEYNAME_STYLES);
1125 OptionalChild inheritFromNode = IsChild(node, KEYNAME_INHERIT);
1126 if(!inheritFromNode)
1128 inheritFromNode = IsChild(node, KEYNAME_STYLES);
1135 TreeNodeList additionalStyleNodes;
1137 CollectAllStyles(*styleNodes, *inheritFromNode, additionalStyleNodes);
1139 #if defined(DEBUG_ENABLED)
1140 for(TreeNode::ConstIterator iter = (*inheritFromNode).CBegin(); iter != (*inheritFromNode).CEnd(); ++iter)
1142 if(OptionalString styleName = IsString((*iter).second))
1144 DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str());
1149 // a style may have other styles, which has other styles etc so we apply in reverse by convention.
1150 for(TreeNodeList::reverse_iterator iter = additionalStyleNodes.rbegin(); iter != additionalStyleNodes.rend(); ++iter)
1152 RecordStyle(style, *(*iter), handle, constant);
1153 ApplySignals(root, *(*iter), handle);
1154 ApplyStylesByActor(root, *(*iter), handle, constant);
1158 RecordStyle(style, node, handle, constant);
1159 mStyles.Add(styleName, style); // shallow copy
1160 matchedStyle = &style;
1167 StylePtr style(*matchedStyle);
1168 Dictionary<Property::Map> instancedProperties;
1169 style->ApplyVisualsAndPropertiesRecursively(handle, instancedProperties);
1171 else // If there were no styles, instead set properties
1173 SetProperties(node, handle, constant);
1175 ApplySignals(root, node, handle);
1176 ApplyStylesByActor(root, node, handle, constant);
1179 void Builder::RecordStyle(StylePtr style,
1180 const TreeNode& node,
1181 Dali::Handle& handle,
1182 const Replacement& replacements)
1184 // With repeated calls, accumulate inherited states, visuals and properties
1185 // but override any with same name
1187 for(TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter)
1189 const TreeNode::KeyNodePair& keyValue = *iter;
1190 std::string key(keyValue.first);
1191 if(key == KEYNAME_STATES)
1193 const TreeNode& states = keyValue.second;
1194 if(states.GetType() != TreeNode::OBJECT)
1196 DALI_LOG_WARNING("RecordStyle() Node \"%s\" is not a JSON object\n", key.c_str());
1200 for(TreeNode::ConstIterator iter = states.CBegin(); iter != states.CEnd(); ++iter)
1202 const TreeNode& stateNode = (*iter).second;
1203 const char* stateName = stateNode.GetName();
1204 if(stateNode.GetType() != TreeNode::OBJECT)
1206 DALI_LOG_WARNING("RecordStyle() Node \"%s\" is not a JSON object\n", stateName);
1210 StylePtr* stylePtr = style->subStates.Find(stateName);
1213 StylePtr subState(*stylePtr);
1214 RecordStyle(subState, stateNode, handle, replacements);
1218 StylePtr subState = Style::New();
1219 RecordStyle(subState, stateNode, handle, replacements);
1220 style->subStates.Add(stateName, subState);
1224 else if(key == KEYNAME_VISUALS)
1226 for(TreeNode::ConstIterator iter = keyValue.second.CBegin(); iter != keyValue.second.CEnd(); ++iter)
1228 // Each key in this table should be a property name matching a visual.
1229 const TreeNode::KeyNodePair& visual = *iter;
1230 Dali::Property::Value property(Property::MAP);
1231 if(DeterminePropertyFromNode(visual.second, Property::MAP, property, replacements))
1233 Property::Map* mapPtr = style->visuals.Find(visual.first);
1236 // Override existing visuals
1238 mapPtr->Merge(*property.GetMap());
1242 Property::Map* map = property.GetMap();
1245 style->visuals.Add(visual.first, *map);
1251 else if(key == KEYNAME_ENTRY_TRANSITION)
1253 RecordTransitionData(keyValue, style->entryTransition, replacements);
1255 else if(key == KEYNAME_EXIT_TRANSITION)
1257 RecordTransitionData(keyValue, style->exitTransition, replacements);
1259 else if(key == KEYNAME_TRANSITIONS)
1261 RecordTransitions(keyValue, style->transitions, replacements);
1263 else if(key == KEYNAME_TYPE ||
1264 key == KEYNAME_ACTORS ||
1265 key == KEYNAME_SIGNALS ||
1266 key == KEYNAME_STYLES ||
1267 key == KEYNAME_MAPPINGS ||
1268 key == KEYNAME_INHERIT)
1272 else // It's a property
1274 Property::Index index;
1275 Property::Value value;
1276 if(MapToTargetProperty(handle, key, keyValue.second, replacements, index, value))
1278 Property::Value* existingValuePtr = style->properties.Find(index);
1279 if(existingValuePtr != NULL)
1281 *existingValuePtr = value; // Overwrite existing property.
1285 style->properties.Add(index, value);
1292 void Builder::RecordTransitions(
1293 const TreeNode::KeyNodePair& keyValue,
1294 Property::Array& value,
1295 const Replacement& replacements)
1297 //@todo add new transitions to style.transitions
1298 // override existing transitions. A transition matches on target & property name
1299 const TreeNode& node = keyValue.second;
1300 if(node.GetType() == TreeNode::ARRAY)
1302 Dali::Property::Value property(Property::ARRAY);
1303 if(DeterminePropertyFromNode(node, Property::ARRAY, property, replacements))
1305 value = *property.GetArray();
1308 else if(node.GetType() == TreeNode::OBJECT)
1310 Dali::Property::Value property(Property::MAP);
1311 if(DeterminePropertyFromNode(node, Property::MAP, property, replacements))
1313 Property::Array propertyArray;
1314 propertyArray.Add(property);
1315 value = propertyArray;
1320 DALI_LOG_WARNING("RecordStyle() Node \"%s\" is not a JSON array or object\n", keyValue.first);
1324 void Builder::RecordTransitionData(
1325 const TreeNode::KeyNodePair& keyValue,
1326 Toolkit::TransitionData& transitionData,
1327 const Replacement& replacements)
1329 const TreeNode& node = keyValue.second;
1330 if(node.GetType() == TreeNode::ARRAY)
1332 Dali::Property::Value property(Property::ARRAY);
1333 if(DeterminePropertyFromNode(keyValue.second, Property::ARRAY, property, replacements))
1335 transitionData = Toolkit::TransitionData::New(*property.GetArray());
1338 else if(node.GetType() == TreeNode::OBJECT)
1340 Dali::Property::Value property(Property::MAP);
1341 if(DeterminePropertyFromNode(keyValue.second, Property::MAP, property, replacements))
1343 transitionData = Toolkit::TransitionData::New(*property.GetMap());
1348 // Set properties from node on handle.
1349 void Builder::ApplyProperties(const TreeNode& root, const TreeNode& node, Dali::Handle& handle, const Replacement& constant)
1351 SetProperties(node, handle, constant);
1352 ApplySignals(root, node, handle);
1355 void Builder::ApplySignals(const TreeNode& root, const TreeNode& node, Dali::Handle& handle)
1357 Actor actor = Actor::DownCast(handle);
1361 SetupSignalAction(mSlotDelegate.GetConnectionTracker(), root, node, actor, this);
1362 SetupPropertyNotification(mSlotDelegate.GetConnectionTracker(), root, node, actor, this);
1366 // Appling by style helper
1367 // use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node
1368 void Builder::ApplyStylesByActor(const TreeNode& root, const TreeNode& node, Dali::Handle& handle, const Replacement& constant)
1370 if(Dali::Actor actor = Dali::Actor::DownCast(handle))
1372 if(const TreeNode* actors = node.GetChild(KEYNAME_ACTORS))
1374 // in a style the actor subtree properties referenced by actor name
1375 for(TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter)
1377 Dali::Actor foundActor;
1381 foundActor = actor.FindChildByName((*iter).first);
1386 DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first);
1390 DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first);
1391 ApplyProperties(root, (*iter).second, foundActor, constant);
1399 * Sets the handle properties found in the tree node
1401 void Builder::SetProperties(const TreeNode& node, Handle& handle, const Replacement& constant)
1405 for(TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter)
1407 const TreeNode::KeyNodePair& keyChild = *iter;
1409 std::string key(keyChild.first);
1411 // ignore special fields;
1412 if(key == KEYNAME_TYPE ||
1413 key == KEYNAME_ACTORS ||
1414 key == KEYNAME_SIGNALS ||
1415 key == KEYNAME_STYLES ||
1416 key == KEYNAME_MAPPINGS ||
1417 key == KEYNAME_INHERIT ||
1418 key == KEYNAME_STATES ||
1419 key == KEYNAME_VISUALS ||
1420 key == KEYNAME_ENTRY_TRANSITION ||
1421 key == KEYNAME_EXIT_TRANSITION ||
1422 key == KEYNAME_TRANSITIONS)
1427 Property::Index index;
1428 Property::Value value;
1430 bool mapped = MapToTargetProperty(handle, key, keyChild.second, constant, index, value);
1433 DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str());
1435 handle.SetProperty(index, value);
1438 // Add custom properties
1439 SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE);
1440 SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE);
1442 } // for property nodes
1446 DALI_SCRIPT_WARNING("Style applied to empty handle\n");
1450 bool Builder::MapToTargetProperty(
1451 Handle& propertyObject,
1452 const std::string& key,
1453 const TreeNode& node,
1454 const Replacement& constant,
1455 Property::Index& index,
1456 Property::Value& value)
1458 bool mapped = false;
1460 index = propertyObject.GetPropertyIndex(key);
1461 if(Property::INVALID_INDEX != index)
1463 Property::Type type = propertyObject.GetPropertyType(index);
1465 // if node.value is a mapping, get the property value from the "mappings" table
1466 if(node.GetType() == TreeNode::STRING)
1468 std::string mappingKey;
1469 if(GetMappingKey(node.GetString(), mappingKey))
1471 OptionalChild mappingRoot = IsChild(mParser.GetRoot(), KEYNAME_MAPPINGS);
1472 mapped = GetPropertyMap(*mappingRoot, mappingKey.c_str(), type, value);
1477 mapped = DeterminePropertyFromNode(node, type, value, constant);
1480 // Just determine the property from the node and if it's valid, let the property object handle it
1481 DeterminePropertyFromNode(node, value, constant);
1482 mapped = (value.GetType() != Property::NONE);
1488 DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str());
1493 bool Builder::GetPropertyMap(const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value)
1496 return RecursePropertyMap(mappingRoot, keyStack, theKey, propertyType, value);
1499 bool Builder::RecursePropertyMap(const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value)
1501 Replacement replacer(mReplacementMap);
1502 bool result = false;
1504 keyStack.push_back(theKey);
1506 for(TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter)
1508 std::string aKey((*iter).first);
1509 if(aKey.compare(theKey) == 0)
1511 if(propertyType == Property::NONE)
1513 DeterminePropertyFromNode((*iter).second, value, replacer);
1518 result = DeterminePropertyFromNode((*iter).second, propertyType, value, replacer);
1523 ConvertChildValue(mappingRoot, keyStack, value);
1528 keyStack.pop_back();
1533 bool Builder::ConvertChildValue(const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child)
1535 bool result = false;
1537 switch(child.GetType())
1539 case Property::STRING:
1542 if(child.Get(value))
1545 if(GetMappingKey(value, key))
1547 // Check key for cycles:
1549 for(KeyStack::iterator iter = keyStack.begin(); iter != keyStack.end(); ++iter)
1551 if(key.compare(*iter) == 0)
1553 // key is already in stack; stop.
1554 DALI_LOG_WARNING("Detected cycle in stylesheet mapping table:%s\n", key.c_str());
1555 child = Property::Value("");
1563 // The following call will overwrite the child with the value
1564 // from the mapping.
1565 RecursePropertyMap(mappingRoot, keyStack, key.c_str(), Property::NONE, child);
1575 Property::Map* map = child.GetMap();
1578 for(Property::Map::SizeType i = 0; i < map->Count(); ++i)
1580 Property::Value& currentChild = map->GetValue(i);
1581 ConvertChildValue(mappingRoot, keyStack, currentChild);
1587 case Property::ARRAY:
1589 Property::Array* array = child.GetArray();
1592 for(Property::Array::SizeType i = 0; i < array->Count(); ++i)
1594 Property::Value& currentChild = array->GetElementAt(i);
1595 ConvertChildValue(mappingRoot, keyStack, currentChild);
1602 // Ignore other types.
1609 void Builder::SetCustomProperties(const TreeNode& node, Handle& handle, const Replacement& constant, const std::string& childName, Property::AccessMode accessMode)
1611 // Add custom properties
1612 if(OptionalChild customPropertiesChild = IsChild(node, childName))
1614 const TreeNode& customPropertiesNode = *customPropertiesChild;
1615 const TreeConstIter endIter = customPropertiesNode.CEnd();
1616 for(TreeConstIter iter = customPropertiesNode.CBegin(); endIter != iter; ++iter)
1618 const TreeNode::KeyNodePair& keyChild = *iter;
1619 std::string key(keyChild.first);
1620 Property::Value value;
1621 DeterminePropertyFromNode(keyChild.second, value, constant);
1623 // Register/Set property.
1624 handle.RegisterProperty(key, value, accessMode);
1629 } // namespace Internal
1631 } // namespace Toolkit