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 Property::Map 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 Property::Map 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, Property::Map& params)
381 if( OptionalChild c = IsChild(child, "parameters") )
383 const TreeNode& node = *c;
387 for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
389 params[ (*iter).first ] = GetPropertyValue( (*iter).second );
394 void DoNothing(void) {};
397 * Get an action as boost function callback
399 boost::function<void (void)> GetAction(const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder)
401 OptionalString childActorName(IsString( IsChild(&child, "child-actor")) );
402 OptionalString actorName(IsString( IsChild(&child, "actor")) );
403 OptionalString propertyName(IsString( IsChild(&child, "property")) );
404 OptionalChild valueChild( IsChild(&child, "value") );
406 OptionalString actionName = IsString( IsChild(&child, "action") );
407 DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
409 boost::function<void(void)> callback = DoNothing;
413 ChildActorAction action;
414 action.actorName = *actorName;
415 action.childName = *childActorName;
416 action.actionName = *actionName;
417 GetParameters(child, action.parameters);
422 if(propertyName && valueChild && ("set" == *actionName) )
424 PropertySetAction action;
425 action.actorName = *actorName;
426 action.propertyName = *propertyName;
427 // actor may not exist yet so we can't check the property type
428 if( !Dali::Toolkit::Internal::SetPropertyFromNode( *valueChild, action.value ) )
430 DALI_SCRIPT_WARNING("Cannot set property for set property action\n");
436 GenericAction action;
437 action.actorName = *actorName;
438 action.actionName = *actionName;
439 GetParameters(child, action.parameters);
443 else if("quit" == *actionName)
445 callback = quitAction;
447 else if("play" == *actionName)
449 OptionalChild animations = IsChild( root, "animations" );
450 OptionalString animationName = IsString( IsChild(child, "animation") );
451 if( animations && animationName )
453 if( OptionalChild animNode = IsChild(*animations, *animationName) )
455 DelayedAnimationPlay action;
456 action.animNode = animNode;
457 action.builder = builder;
458 // @todo; put constants into the map
463 DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
468 DALI_SCRIPT_WARNING("Cannot find animations section\n");
471 else if("applyConstraint" == *actionName )
473 OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
474 if( !constrainerName )
476 DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
480 DelayedConstrainerApply action;
481 action.constrainerName = *constrainerName;
482 action.builder = builder;
483 OptionalChild propertiesNode = IsChild(child, "properties");
486 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
487 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
489 const TreeNode::KeyNodePair& pKeyChild = *iter;
490 OptionalString sourceActorName(IsString(IsChild(pKeyChild.second, "source")));
493 DALI_SCRIPT_WARNING("Need to specify source actor to apply the constraint\n");
496 OptionalString sourcePropertyName( IsString( IsChild(pKeyChild.second, "sourceProperty" ) ) );
497 if(!sourcePropertyName)
499 DALI_SCRIPT_WARNING("Need to specify source property to apply the constraint\n");
503 OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
506 DALI_SCRIPT_WARNING("Need to specify target actor to apply the constraint\n");
510 OptionalString targetPropertyName( IsString( IsChild(pKeyChild.second, "targetProperty" ) ) );
511 if(!targetPropertyName)
513 DALI_SCRIPT_WARNING("Need to specify target property name to apply the constraint\n");
517 OptionalVector2 range(IsVector2(IsChild(pKeyChild.second, "range")));
520 DALI_SCRIPT_WARNING("Constrainer range not specified\n");
524 Vector2 wrap(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
525 OptionalVector2 wrapRange(IsVector2(IsChild(pKeyChild.second, "wrap")));
531 action.sourceActorNames.push_back(*sourceActorName);
532 action.sourcePropertyNames.push_back(*sourcePropertyName);
533 action.targetActorNames.push_back(*targetActorName);
534 action.targetPropertyNames.push_back(*targetPropertyName);
535 action.ranges.push_back(*range);
536 action.wrapRanges.push_back(wrap);
545 else if("removeConstraints" == *actionName )
547 OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
548 if( !constrainerName )
550 DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
555 DelayedConstrainerRemove action;
556 action.constrainerName = *constrainerName;
557 action.builder = builder;
558 OptionalChild propertiesNode = IsChild(child, "properties");
561 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
562 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
564 const TreeNode::KeyNodePair& pKeyChild = *iter;
565 OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
568 action.targetActorNames.push_back(*targetActorName);
572 DALI_SCRIPT_WARNING("Need to specify target actor to remove the constraint\n");
582 // no named actor; presume self
583 GenericAction action;
584 action.actorName = actor.GetName();
585 action.actionName = *actionName;
586 GetParameters(child, action.parameters);
595 * Get a notification condition argument0 as 'arg0' 'value' or 'min'
597 float GetConditionArg0(const TreeNode &child)
599 OptionalFloat f = IsFloat( IsChild(child, "arg0") );
600 // allowing some human preferable alternatives
603 f = IsFloat( IsChild(child, "value") );
607 f = IsFloat( IsChild(child, "min") );
610 DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
616 * Get a notification condition argument1 as 'arg1' or 'max'
618 float GetConditionArg1(const TreeNode &child)
620 OptionalFloat f = IsFloat( IsChild(child, "arg1") );
621 // allowing some human preferable alternatives
624 f = IsFloat( IsChild(child, "max") );
627 DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
643 Actor SetupSignalAction(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
644 Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
647 * Setup signals and actions on an actor
649 Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
651 DALI_ASSERT_ALWAYS(actor);
653 if(OptionalChild signalsChild = IsChild(child, "signals"))
655 const TreeNode& signalsNode = *signalsChild;
656 const TreeConstIter endIter = signalsNode.CEnd();
657 for( TreeConstIter iter = signalsNode.CBegin(); endIter != iter; ++iter )
659 const TreeNode::KeyNodePair& key_child = *iter;
661 DALI_SCRIPT_INFO(" Creating Signal for: %s\n", actor.GetName().c_str());
663 OptionalString name( IsString( IsChild( key_child.second, "name")) );
664 DALI_ASSERT_ALWAYS(name && "Signal must have a name");
666 boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction, builder );
668 actor.ConnectSignal(tracker, *name, callback);
676 * Setup Property notifications for an actor
678 Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
680 DALI_ASSERT_ALWAYS(actor);
682 if(OptionalChild notificationsChild = IsChild(child,"notifications"))
684 const TreeNode& notificationsNode = *notificationsChild;
685 const TreeNode::ConstIterator endIter = notificationsNode.CEnd();
686 for( TreeNode::ConstIterator iter = notificationsNode.CBegin(); endIter != iter; ++iter )
688 const TreeNode::KeyNodePair& key_child = *iter;
690 // Actor actions reference by pointer because of circular reference actor->signal
691 // So this callback should only go onto the actor maintained list.
692 boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction, builder );
694 OptionalString prop(IsString( IsChild(key_child.second, "property")) );
695 DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
697 Property::Index prop_index = actor.GetPropertyIndex(*prop);
698 DALI_ASSERT_ALWAYS(prop_index != Property::INVALID_INDEX && "Notification signal specifies an unknown property");
700 OptionalString cond(IsString( IsChild(key_child.second, "condition")));
701 DALI_ASSERT_ALWAYS(cond && "Notification signal must specify a condition");
705 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
706 LessThanCondition(1.f) );
707 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
709 else if("LessThan" == *cond)
711 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
712 LessThanCondition(GetConditionArg0(key_child.second)) );
713 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
715 else if("GreaterThan" == *cond)
717 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
718 GreaterThanCondition(GetConditionArg0(key_child.second)) );
719 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
721 else if("Inside" == *cond)
723 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
724 InsideCondition(GetConditionArg0(key_child.second),
725 GetConditionArg1(key_child.second)) );
726 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
728 else if("Outside" == *cond)
730 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
731 OutsideCondition(GetConditionArg0(key_child.second),
732 GetConditionArg1(key_child.second)) );
733 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
737 DALI_ASSERT_ALWAYS(!"Unknown condition");
740 } // if notifications
744 } // AddPropertyNotification
747 } // namespace Internal
748 } // namespace Toolkit