2 * Copyright (c) 2014 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 <boost/function.hpp>
20 #include <dali/public-api/actors/layer.h>
21 #include <dali/public-api/common/vector-wrapper.h>
22 #include <dali/public-api/object/type-info.h>
23 #include <dali/public-api/object/property-notification.h>
24 #include <dali/integration-api/debug.h>
28 #include <dali-toolkit/internal/builder/builder-impl.h>
29 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
37 extern Animation CreateAnimation( const TreeNode& child, Dali::Toolkit::Internal::Builder* const builder );
38 extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
51 // Action on child actor. The child is found by name
52 struct ChildActorAction
54 std::string actorName;
55 std::string actionName;
56 std::string childName;
57 PropertyValueContainer parameters;
61 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
65 Actor child_actor = actor.FindChildByName(childName);
69 child_actor.DoAction(actionName, parameters);
73 DALI_SCRIPT_WARNING("Could not find child by name '%s'\n", childName.c_str());
79 // Action to set a property
80 struct PropertySetAction
82 std::string actorName;
83 std::string propertyName;
84 Property::Value value;
88 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
92 Property::Index idx = actor.GetPropertyIndex(propertyName);
94 if( idx != Property::INVALID_INDEX )
96 if( actor.GetPropertyType(idx) != value.GetType() )
98 DALI_SCRIPT_WARNING("Set property action has different type for property '%s'\n", propertyName.c_str());
102 actor.SetProperty( idx, value );
107 DALI_SCRIPT_WARNING("Set property action cannot find property '%s'\n", propertyName.c_str());
113 // Generic action on a handle (Animation & Actor)
116 std::string actorName;
117 std::string actionName;
118 PropertyValueContainer parameters;
120 void operator()(void)
122 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
125 actor.DoAction(actionName, parameters);
131 // Delay an animation play; ie wait as its not on stage yet
132 struct DelayedAnimationPlay
134 OptionalChild animNode;
135 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
137 void operator()(void)
139 Animation anim = Toolkit::Internal::CreateAnimation(*animNode, builder.Get() );
147 // Delay a pathConstrainer apply
148 struct DelayedConstrainerApply
150 std::string constrainerName;
152 std::vector<std::string> targetActorNames;
153 std::vector<std::string> sourceActorNames;
154 std::vector<std::string> targetPropertyNames;
155 std::vector<std::string> sourcePropertyNames;
156 std::vector<Vector2> ranges;
157 std::vector<Vector2> wrapRanges;
159 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
162 * Helper function to get the parameters to apply each constraint
163 * @param[in] i i-essim element
164 * @param[out] tagetActor Target actor for the constraint
165 * @param[out] tagetPropertyIndex Target property index for the constraint
166 * @param[out] sourceActor Source actor for the constraint
167 * @param[out] sourcePropertyIndex Source property index for the constraint
169 bool GetApplyParameters( size_t i,
170 Actor& targetActor, Property::Index& targetPropertyIndex,
171 Actor& sourceActor, Property::Index& sourcePropertyIndex)
174 targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
175 targetPropertyIndex = Property::INVALID_INDEX;
178 targetPropertyIndex = targetActor.GetPropertyIndex(targetPropertyNames[i]);
179 if( targetPropertyIndex == Property::INVALID_INDEX )
181 DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", targetPropertyNames[i].c_str(), targetActorNames[i].c_str() );
187 DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
192 sourceActor = Stage::GetCurrent().GetRootLayer().FindChildByName(sourceActorNames[i]);
193 sourcePropertyIndex = Property::INVALID_INDEX;
196 sourcePropertyIndex = sourceActor.GetPropertyIndex(sourcePropertyNames[i]);
197 if( sourcePropertyIndex == Property::INVALID_INDEX )
199 DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", sourcePropertyNames[i].c_str(), sourceActorNames[i].c_str() );
205 DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
211 void operator()(void)
213 Actor sourceActor, targetActor;
214 Property::Index targetPropertyIndex(Property::INVALID_INDEX);
215 Property::Index sourcePropertyIndex(Property::INVALID_INDEX);
216 size_t actorCount( targetActorNames.size() );
217 if( builder.Get()->IsPathConstrainer( constrainerName ))
219 PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
222 for(size_t i(0); i<actorCount; ++i )
225 if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
227 constrainer.Apply( Property(targetActor,targetPropertyIndex),
228 Property(sourceActor,sourcePropertyIndex),
236 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
239 else if( builder.Get()->IsLinearConstrainer( constrainerName ) )
241 Dali::LinearConstrainer constrainer( builder.Get()->GetLinearConstrainer(constrainerName));
244 for(size_t i(0); i<actorCount; ++i )
247 if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
249 constrainer.Apply( Property(targetActor,targetPropertyIndex),
250 Property(sourceActor,sourcePropertyIndex),
258 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
263 DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
268 // Delay a pathConstrainer remove
269 struct DelayedConstrainerRemove
271 std::string constrainerName;
272 std::vector<std::string> targetActorNames;
273 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
275 void operator()(void)
277 size_t actorCount( targetActorNames.size() );
278 if( builder.Get()->IsPathConstrainer( constrainerName ))
280 PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
283 for(size_t i(0); i<actorCount; ++i )
285 Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
288 constrainer.Remove( targetActor );
294 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
297 else if(builder.Get()->IsLinearConstrainer( constrainerName ))
299 LinearConstrainer constrainer = builder.Get()->GetLinearConstrainer(constrainerName);
302 for(size_t i(0); i<actorCount; ++i )
304 Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
307 constrainer.Remove( targetActor );
313 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
318 DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
324 * Gets Property::Value from child
326 Property::Value GetPropertyValue(const TreeNode &child)
328 size_t nChildren = child.Size();
334 // cast away unused return for static analyzers
335 static_cast<void>( Dali::Toolkit::Internal::SetPropertyFromNode( child, ret ) );
337 else if(1 == nChildren)
339 // {"property": {"quaternion":[1,2,3,4]} }
340 // {"property": {"angle":22, "axis": [1,2,3]} }
342 OptionalChild quaternion = IsChild(&child, "quaternion");
343 OptionalChild axis = IsChild(&child, "axis");
344 OptionalChild angle = IsChild(&child, "angle");
348 ret = Property::Value(Quaternion(GetVector4(*quaternion)));
350 else if(axis && angle)
352 ret = Property::Value(AngleAxis(Degree(GetFloat(*angle)), GetVector3(*axis)));
355 else if(2 == nChildren)
357 // {"property": [1,2]}
358 ret = Property::Value(GetVector2(child));
360 else if(3 == nChildren)
362 // {"property": [1,2,3]}
363 ret = Property::Value(GetVector3(child));
365 else if(4 == nChildren)
367 // {"property": [1,2,3,4]}
368 ret = Property::Value(GetVector4(child));
376 * Gets Parmeter list from child
377 * params is be cleared before insertion
379 void GetParameters(const TreeNode& child, PropertyValueContainer& params)
381 if( OptionalChild c = IsChild(child, "parameters") )
383 const TreeNode& node = *c;
387 GetPropertyValue(node);
392 params.reserve(node.Size());
394 for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
396 params.push_back( GetPropertyValue( (*iter).second ) );
402 void DoNothing(void) {};
405 * Get an action as boost function callback
407 boost::function<void (void)> GetAction(const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder)
409 OptionalString childActorName(IsString( IsChild(&child, "child-actor")) );
410 OptionalString actorName(IsString( IsChild(&child, "actor")) );
411 OptionalString propertyName(IsString( IsChild(&child, "property")) );
412 OptionalChild valueChild( IsChild(&child, "value") );
414 OptionalString actionName = IsString( IsChild(&child, "action") );
415 DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
417 boost::function<void(void)> callback = DoNothing;
421 ChildActorAction action;
422 action.actorName = *actorName;
423 action.childName = *childActorName;
424 action.actionName = *actionName;
425 GetParameters(child, action.parameters);
430 if(propertyName && valueChild && ("set" == *actionName) )
432 PropertySetAction action;
433 action.actorName = *actorName;
434 action.propertyName = *propertyName;
435 // actor may not exist yet so we can't check the property type
436 if( !Dali::Toolkit::Internal::SetPropertyFromNode( *valueChild, action.value ) )
438 DALI_SCRIPT_WARNING("Cannot set property for set property action\n");
444 GenericAction action;
445 action.actorName = *actorName;
446 action.actionName = *actionName;
447 GetParameters(child, action.parameters);
451 else if("quit" == *actionName)
453 callback = quitAction;
455 else if("play" == *actionName)
457 OptionalChild animations = IsChild( root, "animations" );
458 OptionalString animationName = IsString( IsChild(child, "animation") );
459 if( animations && animationName )
461 if( OptionalChild animNode = IsChild(*animations, *animationName) )
463 DelayedAnimationPlay action;
464 action.animNode = animNode;
465 action.builder = builder;
466 // @todo; put constants into the map
471 DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
476 DALI_SCRIPT_WARNING("Cannot find animations section\n");
479 else if("applyConstraint" == *actionName )
481 OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
482 if( !constrainerName )
484 DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
488 DelayedConstrainerApply action;
489 action.constrainerName = *constrainerName;
490 action.builder = builder;
491 OptionalChild propertiesNode = IsChild(child, "properties");
494 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
495 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
497 const TreeNode::KeyNodePair& pKeyChild = *iter;
498 OptionalString sourceActorName(IsString(IsChild(pKeyChild.second, "source")));
501 DALI_SCRIPT_WARNING("Need to specify source actor to apply the constraint\n");
504 OptionalString sourcePropertyName( IsString( IsChild(pKeyChild.second, "sourceProperty" ) ) );
505 if(!sourcePropertyName)
507 DALI_SCRIPT_WARNING("Need to specify source property to apply the constraint\n");
511 OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
514 DALI_SCRIPT_WARNING("Need to specify target actor to apply the constraint\n");
518 OptionalString targetPropertyName( IsString( IsChild(pKeyChild.second, "targetProperty" ) ) );
519 if(!targetPropertyName)
521 DALI_SCRIPT_WARNING("Need to specify target property name to apply the constraint\n");
525 OptionalVector2 range(IsVector2(IsChild(pKeyChild.second, "range")));
528 DALI_SCRIPT_WARNING("Constrainer range not specified\n");
532 Vector2 wrap(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
533 OptionalVector2 wrapRange(IsVector2(IsChild(pKeyChild.second, "wrap")));
539 action.sourceActorNames.push_back(*sourceActorName);
540 action.sourcePropertyNames.push_back(*sourcePropertyName);
541 action.targetActorNames.push_back(*targetActorName);
542 action.targetPropertyNames.push_back(*targetPropertyName);
543 action.ranges.push_back(*range);
544 action.wrapRanges.push_back(wrap);
553 else if("removeConstraints" == *actionName )
555 OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
556 if( !constrainerName )
558 DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
563 DelayedConstrainerRemove action;
564 action.constrainerName = *constrainerName;
565 action.builder = builder;
566 OptionalChild propertiesNode = IsChild(child, "properties");
569 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
570 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
572 const TreeNode::KeyNodePair& pKeyChild = *iter;
573 OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
576 action.targetActorNames.push_back(*targetActorName);
580 DALI_SCRIPT_WARNING("Need to specify target actor to remove the constraint\n");
590 // no named actor; presume self
591 GenericAction action;
592 action.actorName = actor.GetName();
593 action.actionName = *actionName;
594 GetParameters(child, action.parameters);
603 * Get a notification condition argument0 as 'arg0' 'value' or 'min'
605 float GetConditionArg0(const TreeNode &child)
607 OptionalFloat f = IsFloat( IsChild(child, "arg0") );
608 // allowing some human preferable alternatives
611 f = IsFloat( IsChild(child, "value") );
615 f = IsFloat( IsChild(child, "min") );
618 DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
624 * Get a notification condition argument1 as 'arg1' or 'max'
626 float GetConditionArg1(const TreeNode &child)
628 OptionalFloat f = IsFloat( IsChild(child, "arg1") );
629 // allowing some human preferable alternatives
632 f = IsFloat( IsChild(child, "max") );
635 DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
651 Actor SetupSignalAction(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
652 Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
655 * Setup signals and actions on an actor
657 Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
659 DALI_ASSERT_ALWAYS(actor);
661 if(OptionalChild signalsChild = IsChild(child, "signals"))
663 const TreeNode& signalsNode = *signalsChild;
664 const TreeConstIter endIter = signalsNode.CEnd();
665 for( TreeConstIter iter = signalsNode.CBegin(); endIter != iter; ++iter )
667 const TreeNode::KeyNodePair& key_child = *iter;
669 DALI_SCRIPT_INFO(" Creating Signal for: %s\n", actor.GetName().c_str());
671 OptionalString name( IsString( IsChild( key_child.second, "name")) );
672 DALI_ASSERT_ALWAYS(name && "Signal must have a name");
674 boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction, builder );
676 actor.ConnectSignal(tracker, *name, callback);
684 * Setup Property notifications for an actor
686 Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
688 DALI_ASSERT_ALWAYS(actor);
690 if(OptionalChild notificationsChild = IsChild(child,"notifications"))
692 const TreeNode& notificationsNode = *notificationsChild;
693 const TreeNode::ConstIterator endIter = notificationsNode.CEnd();
694 for( TreeNode::ConstIterator iter = notificationsNode.CBegin(); endIter != iter; ++iter )
696 const TreeNode::KeyNodePair& key_child = *iter;
698 // Actor actions reference by pointer because of circular reference actor->signal
699 // So this callback should only go onto the actor maintained list.
700 boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction, builder );
702 OptionalString prop(IsString( IsChild(key_child.second, "property")) );
703 DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
705 Property::Index prop_index = actor.GetPropertyIndex(*prop);
706 DALI_ASSERT_ALWAYS(prop_index != Property::INVALID_INDEX && "Notification signal specifies an unknown property");
708 OptionalString cond(IsString( IsChild(key_child.second, "condition")));
709 DALI_ASSERT_ALWAYS(cond && "Notification signal must specify a condition");
713 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
714 LessThanCondition(1.f) );
715 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
717 else if("LessThan" == *cond)
719 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
720 LessThanCondition(GetConditionArg0(key_child.second)) );
721 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
723 else if("GreaterThan" == *cond)
725 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
726 GreaterThanCondition(GetConditionArg0(key_child.second)) );
727 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
729 else if("Inside" == *cond)
731 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
732 InsideCondition(GetConditionArg0(key_child.second),
733 GetConditionArg1(key_child.second)) );
734 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
736 else if("Outside" == *cond)
738 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
739 OutsideCondition(GetConditionArg0(key_child.second),
740 GetConditionArg1(key_child.second)) );
741 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
745 DALI_ASSERT_ALWAYS(!"Unknown condition");
748 } // if notifications
752 } // AddPropertyNotification
755 } // namespace Internal
756 } // namespace Toolkit