2 * Copyright (c) 2016 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/public-api/actors/layer.h>
20 #include <dali/public-api/common/vector-wrapper.h>
21 #include <dali/public-api/object/type-info.h>
22 #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 void DeterminePropertyFromNode( 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);
133 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
135 void operator()(void)
137 builder->EmitQuitSignal();
141 // Delay an animation play; ie wait as its not on stage yet
142 struct DelayedAnimationPlay
144 OptionalChild animNode;
145 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
147 void operator()(void)
149 Animation anim = Toolkit::Internal::CreateAnimation(*animNode, builder.Get() );
157 // Delay a pathConstrainer apply
158 struct DelayedConstrainerApply
160 std::string constrainerName;
162 std::vector<std::string> targetActorNames;
163 std::vector<std::string> sourceActorNames;
164 std::vector<std::string> targetPropertyNames;
165 std::vector<std::string> sourcePropertyNames;
166 std::vector<Vector2> ranges;
167 std::vector<Vector2> wrapRanges;
169 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
172 * Helper function to get the parameters to apply each constraint
173 * @param[in] i i-essim element
174 * @param[out] tagetActor Target actor for the constraint
175 * @param[out] tagetPropertyIndex Target property index for the constraint
176 * @param[out] sourceActor Source actor for the constraint
177 * @param[out] sourcePropertyIndex Source property index for the constraint
179 bool GetApplyParameters( size_t i,
180 Actor& targetActor, Property::Index& targetPropertyIndex,
181 Actor& sourceActor, Property::Index& sourcePropertyIndex)
184 targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
185 targetPropertyIndex = Property::INVALID_INDEX;
188 targetPropertyIndex = targetActor.GetPropertyIndex(targetPropertyNames[i]);
189 if( targetPropertyIndex == Property::INVALID_INDEX )
191 DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", targetPropertyNames[i].c_str(), targetActorNames[i].c_str() );
197 DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
202 sourceActor = Stage::GetCurrent().GetRootLayer().FindChildByName(sourceActorNames[i]);
203 sourcePropertyIndex = Property::INVALID_INDEX;
206 sourcePropertyIndex = sourceActor.GetPropertyIndex(sourcePropertyNames[i]);
207 if( sourcePropertyIndex == Property::INVALID_INDEX )
209 DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", sourcePropertyNames[i].c_str(), sourceActorNames[i].c_str() );
215 DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
221 void operator()(void)
223 Actor sourceActor, targetActor;
224 Property::Index targetPropertyIndex(Property::INVALID_INDEX);
225 Property::Index sourcePropertyIndex(Property::INVALID_INDEX);
226 size_t actorCount( targetActorNames.size() );
227 if( builder.Get()->IsPathConstrainer( constrainerName ))
229 PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
232 for(size_t i(0); i<actorCount; ++i )
235 if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
237 constrainer.Apply( Property(targetActor,targetPropertyIndex),
238 Property(sourceActor,sourcePropertyIndex),
246 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
249 else if( builder.Get()->IsLinearConstrainer( constrainerName ) )
251 Dali::LinearConstrainer constrainer( builder.Get()->GetLinearConstrainer(constrainerName));
254 for(size_t i(0); i<actorCount; ++i )
257 if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
259 constrainer.Apply( Property(targetActor,targetPropertyIndex),
260 Property(sourceActor,sourcePropertyIndex),
268 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
273 DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
278 // Delay a pathConstrainer remove
279 struct DelayedConstrainerRemove
281 std::string constrainerName;
282 std::vector<std::string> targetActorNames;
283 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
285 void operator()(void)
287 size_t actorCount( targetActorNames.size() );
288 if( builder.Get()->IsPathConstrainer( constrainerName ))
290 PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
293 for(size_t i(0); i<actorCount; ++i )
295 Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
298 constrainer.Remove( targetActor );
304 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
307 else if(builder.Get()->IsLinearConstrainer( constrainerName ))
309 LinearConstrainer constrainer = builder.Get()->GetLinearConstrainer(constrainerName);
312 for(size_t i(0); i<actorCount; ++i )
314 Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
317 constrainer.Remove( targetActor );
323 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
328 DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
334 * Gets Property::Value from child
336 Property::Value GetPropertyValue(const TreeNode &child)
338 size_t nChildren = child.Size();
344 // cast away unused return for static analyzers
345 static_cast<void>( Dali::Toolkit::Internal::DeterminePropertyFromNode( child, ret ) );
347 else if(1 == nChildren)
349 // {"property": {"quaternion":[1,2,3,4]} }
350 // {"property": {"angle":22, "axis": [1,2,3]} }
352 OptionalChild quaternion = IsChild(&child, "quaternion");
353 OptionalChild axis = IsChild(&child, "axis");
354 OptionalChild angle = IsChild(&child, "angle");
358 ret = Property::Value(Quaternion(GetVector4(*quaternion)));
360 else if(axis && angle)
362 ret = Property::Value(AngleAxis(Degree(GetFloat(*angle)), GetVector3(*axis)));
365 else if(2 == nChildren)
367 // {"property": [1,2]}
368 ret = Property::Value(GetVector2(child));
370 else if(3 == nChildren)
372 // {"property": [1,2,3]}
373 ret = Property::Value(GetVector3(child));
375 else if(4 == nChildren)
377 // {"property": [1,2,3,4]}
378 ret = Property::Value(GetVector4(child));
386 * Gets Parmeter list from child
387 * params is be cleared before insertion
389 void GetParameters(const TreeNode& child, Property::Map& params)
391 if( OptionalChild c = IsChild(child, "parameters") )
393 const TreeNode& node = *c;
397 for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
399 params[ (*iter).first ] = GetPropertyValue( (*iter).second );
404 // Shim for the property notifcation signal
405 template <typename T>
406 struct PropertyNotifcationSignalShim
410 PropertyNotifcationSignalShim(T& functor) : mFunctor(functor) {}
412 void operator()(PropertyNotification& /* source */)
418 // Specializations for the different signal connection calls between actor & PropertyNotification
419 template <typename T>
420 struct SignalConnector {};
422 // Actor specialization
424 struct SignalConnector<Actor> {
426 ConnectionTracker* mTracker;
427 const std::string& mName;
429 SignalConnector<Actor>(ConnectionTracker* tracker, Actor& actor, const std::string& name)
430 : mActor(actor), mTracker(tracker), mName(name) {}
432 template <typename T>
433 void Connect(T& functor)
435 mActor.ConnectSignal( mTracker, mName, functor);
439 // PropertyNotification specialization
441 struct SignalConnector<PropertyNotification>
443 PropertyNotification& mNotification;
444 ConnectionTracker* mTracker;
446 SignalConnector<PropertyNotification>(ConnectionTracker* tracker, PropertyNotification ¬ification)
447 : mNotification(notification), mTracker(tracker) {}
449 template <typename T>
450 void Connect(T& functor)
452 mNotification.NotifySignal().Connect( mTracker, PropertyNotifcationSignalShim<T>(functor) );
457 * Set an action functor on a signal
459 template <typename T>
460 void SetActionOnSignal(const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder, SignalConnector<T>& connector)
462 OptionalString childActorName(IsString( IsChild(&child, "childActor")) );
463 OptionalString actorName(IsString( IsChild(&child, "actor")) );
464 OptionalString propertyName(IsString( IsChild(&child, "property")) );
465 OptionalChild valueChild( IsChild(&child, "value") );
467 OptionalString actionName = IsString( IsChild(&child, "action") );
468 DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
472 ChildActorAction action;
473 action.actorName = *actorName;
474 action.childName = *childActorName;
475 action.actionName = *actionName;
476 GetParameters(child, action.parameters);
477 connector.Connect( action );
481 if(propertyName && valueChild && ("set" == *actionName) )
483 PropertySetAction action;
484 action.actorName = *actorName;
485 action.propertyName = *propertyName;
486 // actor may not exist yet so we can't check the property type
487 Dali::Toolkit::Internal::DeterminePropertyFromNode( *valueChild, action.value );
488 connector.Connect( action );
492 GenericAction action;
493 action.actorName = *actorName;
494 action.actionName = *actionName;
495 GetParameters(child, action.parameters);
496 connector.Connect( action );
499 else if("quit" == *actionName)
502 action.builder = builder;
503 connector.Connect( action );
505 else if("play" == *actionName)
507 OptionalChild animations = IsChild( root, "animations" );
508 OptionalString animationName = IsString( IsChild(child, "animation") );
509 if( animations && animationName )
511 if( OptionalChild animNode = IsChild(*animations, *animationName) )
513 DelayedAnimationPlay action;
514 action.animNode = animNode;
515 action.builder = builder;
516 // @todo; put constants into the map
517 connector.Connect( action );
521 DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
526 DALI_SCRIPT_WARNING("Cannot find animations section\n");
529 else if("applyConstraint" == *actionName )
531 OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
532 if( !constrainerName )
534 DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
538 DelayedConstrainerApply action;
539 action.constrainerName = *constrainerName;
540 action.builder = builder;
541 OptionalChild propertiesNode = IsChild(child, "properties");
544 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
545 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
547 const TreeNode::KeyNodePair& pKeyChild = *iter;
548 OptionalString sourceActorName(IsString(IsChild(pKeyChild.second, "source")));
551 DALI_SCRIPT_WARNING("Need to specify source actor to apply the constraint\n");
554 OptionalString sourcePropertyName( IsString( IsChild(pKeyChild.second, "sourceProperty" ) ) );
555 if(!sourcePropertyName)
557 DALI_SCRIPT_WARNING("Need to specify source property to apply the constraint\n");
561 OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
564 DALI_SCRIPT_WARNING("Need to specify target actor to apply the constraint\n");
568 OptionalString targetPropertyName( IsString( IsChild(pKeyChild.second, "targetProperty" ) ) );
569 if(!targetPropertyName)
571 DALI_SCRIPT_WARNING("Need to specify target property name to apply the constraint\n");
575 OptionalVector2 range(IsVector2(IsChild(pKeyChild.second, "range")));
578 DALI_SCRIPT_WARNING("Constrainer range not specified\n");
582 Vector2 wrap(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
583 OptionalVector2 wrapRange(IsVector2(IsChild(pKeyChild.second, "wrap")));
589 action.sourceActorNames.push_back(*sourceActorName);
590 action.sourcePropertyNames.push_back(*sourcePropertyName);
591 action.targetActorNames.push_back(*targetActorName);
592 action.targetPropertyNames.push_back(*targetPropertyName);
593 action.ranges.push_back(*range);
594 action.wrapRanges.push_back(wrap);
596 connector.Connect(action);
600 else if("removeConstraints" == *actionName )
602 OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
603 if( !constrainerName )
605 DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
610 DelayedConstrainerRemove action;
611 action.constrainerName = *constrainerName;
612 action.builder = builder;
613 OptionalChild propertiesNode = IsChild(child, "properties");
616 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
617 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
619 const TreeNode::KeyNodePair& pKeyChild = *iter;
620 OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
623 action.targetActorNames.push_back(*targetActorName);
627 DALI_SCRIPT_WARNING("Need to specify target actor to remove the constraint\n");
632 connector.Connect(action);
637 // no named actor; presume self
638 GenericAction action;
639 action.actorName = actor.GetName();
640 action.actionName = *actionName;
641 GetParameters(child, action.parameters);
642 connector.Connect( action );
648 * Get a notification condition argument0 as 'arg0' 'value' or 'min'
650 float GetConditionArg0(const TreeNode &child)
652 OptionalFloat f = IsFloat( IsChild(child, "arg0") );
653 // allowing some human preferable alternatives
656 f = IsFloat( IsChild(child, "value") );
660 f = IsFloat( IsChild(child, "min") );
663 DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
669 * Get a notification condition argument1 as 'arg1' or 'max'
671 float GetConditionArg1(const TreeNode &child)
673 OptionalFloat f = IsFloat( IsChild(child, "arg1") );
674 // allowing some human preferable alternatives
677 f = IsFloat( IsChild(child, "max") );
680 DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
696 Actor SetupSignalAction(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
697 Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
700 * Setup signals and actions on an actor
702 Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder )
704 DALI_ASSERT_ALWAYS(actor);
706 if(OptionalChild signalsChild = IsChild(child, "signals"))
708 const TreeNode& signalsNode = *signalsChild;
709 const TreeConstIter endIter = signalsNode.CEnd();
710 for( TreeConstIter iter = signalsNode.CBegin(); endIter != iter; ++iter )
712 const TreeNode::KeyNodePair& key_child = *iter;
714 DALI_SCRIPT_INFO(" Creating Signal for: %s\n", actor.GetName().c_str());
716 OptionalString name( IsString( IsChild( key_child.second, "name")) );
717 DALI_ASSERT_ALWAYS(name && "Signal must have a name");
719 SignalConnector<Actor> connector(tracker, actor, *name);
720 SetActionOnSignal(root, key_child.second, actor, builder, connector);
728 * Setup Property notifications for an actor
730 Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder )
732 DALI_ASSERT_ALWAYS(actor);
734 if(OptionalChild notificationsChild = IsChild(child,"notifications"))
736 const TreeNode& notificationsNode = *notificationsChild;
737 const TreeNode::ConstIterator endIter = notificationsNode.CEnd();
738 for( TreeNode::ConstIterator iter = notificationsNode.CBegin(); endIter != iter; ++iter )
740 const TreeNode::KeyNodePair& key_child = *iter;
742 OptionalString prop(IsString( IsChild(key_child.second, "property")) );
743 DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
745 Property::Index prop_index = actor.GetPropertyIndex(*prop);
746 DALI_ASSERT_ALWAYS(prop_index != Property::INVALID_INDEX && "Notification signal specifies an unknown property");
748 OptionalString cond(IsString( IsChild(key_child.second, "condition")));
749 DALI_ASSERT_ALWAYS(cond && "Notification signal must specify a condition");
753 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
754 LessThanCondition(1.f) );
755 SignalConnector<PropertyNotification> connector(tracker, notification);
756 SetActionOnSignal(root, key_child.second, actor, builder, connector);
758 else if("LessThan" == *cond)
760 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
761 LessThanCondition(GetConditionArg0(key_child.second)) );
762 SignalConnector<PropertyNotification> connector(tracker, notification);
763 SetActionOnSignal(root, key_child.second, actor, builder, connector);
765 else if("GreaterThan" == *cond)
767 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
768 GreaterThanCondition(GetConditionArg0(key_child.second)) );
769 SignalConnector<PropertyNotification> connector(tracker, notification);
770 SetActionOnSignal(root, key_child.second, actor, builder, connector);
772 else if("Inside" == *cond)
774 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
775 InsideCondition(GetConditionArg0(key_child.second),
776 GetConditionArg1(key_child.second)) );
777 SignalConnector<PropertyNotification> connector(tracker, notification);
778 SetActionOnSignal(root, key_child.second, actor, builder, connector);
780 else if("Outside" == *cond)
782 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
783 OutsideCondition(GetConditionArg0(key_child.second),
784 GetConditionArg1(key_child.second)) );
785 SignalConnector<PropertyNotification> connector(tracker, notification);
786 SetActionOnSignal(root, key_child.second, actor, builder, connector);
790 DALI_ASSERT_ALWAYS(!"Unknown condition");
793 } // if notifications
797 } // AddPropertyNotification
800 } // namespace Internal
801 } // namespace Toolkit