2 * Copyright (c) 2020 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>
23 #include <dali/devel-api/common/stage.h>
25 #include <dali/integration-api/debug.h>
29 #include <dali-toolkit/internal/builder/builder-impl.h>
30 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
38 extern Animation CreateAnimation( const TreeNode& child, Dali::Toolkit::Internal::Builder* const builder );
39 extern void DeterminePropertyFromNode( const TreeNode& node, Property::Value& value );
52 // Action on child actor. The child is found by name
53 struct ChildActorAction
55 std::string actorName;
56 std::string actionName;
57 std::string childName;
58 Property::Map parameters;
62 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
66 Actor child_actor = actor.FindChildByName(childName);
70 child_actor.DoAction(actionName, parameters);
74 DALI_SCRIPT_WARNING("Could not find child by name '%s'\n", childName.c_str());
80 // Action to set a property
81 struct PropertySetAction
83 std::string actorName;
84 std::string propertyName;
85 Property::Value value;
89 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
93 Property::Index idx = actor.GetPropertyIndex(propertyName);
95 if( idx != Property::INVALID_INDEX )
97 if( actor.GetPropertyType(idx) != value.GetType() )
99 DALI_SCRIPT_WARNING("Set property action has different type for property '%s'\n", propertyName.c_str());
103 actor.SetProperty( idx, value );
108 DALI_SCRIPT_WARNING("Set property action cannot find property '%s'\n", propertyName.c_str());
114 // Generic action on a handle (Animation & Actor)
117 std::string actorName;
118 std::string actionName;
119 Property::Map parameters;
121 void operator()(void)
123 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
126 actor.DoAction(actionName, parameters);
134 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
136 void operator()(void)
138 builder->EmitQuitSignal();
142 // Delay an animation play; ie wait as its not on stage yet
143 struct DelayedAnimationPlay
145 OptionalChild animNode;
146 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
148 void operator()(void)
150 Animation anim = Toolkit::Internal::CreateAnimation(*animNode, builder.Get() );
158 // Delay a pathConstrainer apply
159 struct DelayedConstrainerApply
161 std::string constrainerName;
163 std::vector<std::string> targetActorNames;
164 std::vector<std::string> sourceActorNames;
165 std::vector<std::string> targetPropertyNames;
166 std::vector<std::string> sourcePropertyNames;
167 std::vector<Vector2> ranges;
168 std::vector<Vector2> wrapRanges;
170 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
173 * Helper function to get the parameters to apply each constraint
174 * @param[in] i i-essim element
175 * @param[out] tagetActor Target actor for the constraint
176 * @param[out] tagetPropertyIndex Target property index for the constraint
177 * @param[out] sourceActor Source actor for the constraint
178 * @param[out] sourcePropertyIndex Source property index for the constraint
180 bool GetApplyParameters( size_t i,
181 Actor& targetActor, Property::Index& targetPropertyIndex,
182 Actor& sourceActor, Property::Index& sourcePropertyIndex)
185 targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
186 targetPropertyIndex = Property::INVALID_INDEX;
189 targetPropertyIndex = targetActor.GetPropertyIndex(targetPropertyNames[i]);
190 if( targetPropertyIndex == Property::INVALID_INDEX )
192 DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", targetPropertyNames[i].c_str(), targetActorNames[i].c_str() );
198 DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
203 sourceActor = Stage::GetCurrent().GetRootLayer().FindChildByName(sourceActorNames[i]);
204 sourcePropertyIndex = Property::INVALID_INDEX;
207 sourcePropertyIndex = sourceActor.GetPropertyIndex(sourcePropertyNames[i]);
208 if( sourcePropertyIndex == Property::INVALID_INDEX )
210 DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", sourcePropertyNames[i].c_str(), sourceActorNames[i].c_str() );
216 DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
222 void operator()(void)
224 Actor sourceActor, targetActor;
225 Property::Index targetPropertyIndex(Property::INVALID_INDEX);
226 Property::Index sourcePropertyIndex(Property::INVALID_INDEX);
227 size_t actorCount( targetActorNames.size() );
228 if( builder.Get()->IsPathConstrainer( constrainerName ))
230 PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
233 for(size_t i(0); i<actorCount; ++i )
236 if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
238 constrainer.Apply( Property(targetActor,targetPropertyIndex),
239 Property(sourceActor,sourcePropertyIndex),
247 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
250 else if( builder.Get()->IsLinearConstrainer( constrainerName ) )
252 Dali::LinearConstrainer constrainer( builder.Get()->GetLinearConstrainer(constrainerName));
255 for(size_t i(0); i<actorCount; ++i )
258 if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
260 constrainer.Apply( Property(targetActor,targetPropertyIndex),
261 Property(sourceActor,sourcePropertyIndex),
269 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
274 DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
279 // Delay a pathConstrainer remove
280 struct DelayedConstrainerRemove
282 std::string constrainerName;
283 std::vector<std::string> targetActorNames;
284 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
286 void operator()(void)
288 size_t actorCount( targetActorNames.size() );
289 if( builder.Get()->IsPathConstrainer( constrainerName ))
291 PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
294 for(size_t i(0); i<actorCount; ++i )
296 Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
299 constrainer.Remove( targetActor );
305 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
308 else if(builder.Get()->IsLinearConstrainer( constrainerName ))
310 LinearConstrainer constrainer = builder.Get()->GetLinearConstrainer(constrainerName);
313 for(size_t i(0); i<actorCount; ++i )
315 Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
318 constrainer.Remove( targetActor );
324 DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
329 DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
335 * Gets Property::Value from child
337 Property::Value GetPropertyValue(const TreeNode &child)
339 size_t nChildren = child.Size();
345 // cast away unused return for static analyzers
346 static_cast<void>( Dali::Toolkit::Internal::DeterminePropertyFromNode( child, ret ) );
348 else if(1 == nChildren)
350 // {"property": {"quaternion":[1,2,3,4]} }
351 // {"property": {"angle":22, "axis": [1,2,3]} }
353 OptionalChild quaternion = IsChild(&child, "quaternion");
354 OptionalChild axis = IsChild(&child, "axis");
355 OptionalChild angle = IsChild(&child, "angle");
359 ret = Property::Value(Quaternion(GetVector4(*quaternion)));
361 else if(axis && angle)
363 ret = Property::Value(AngleAxis(Degree(GetFloat(*angle)), GetVector3(*axis)));
366 else if(2 == nChildren)
368 // {"property": [1,2]}
369 ret = Property::Value(GetVector2(child));
371 else if(3 == nChildren)
373 // {"property": [1,2,3]}
374 ret = Property::Value(GetVector3(child));
376 else if(4 == nChildren)
378 // {"property": [1,2,3,4]}
379 ret = Property::Value(GetVector4(child));
387 * Gets Parmeter list from child
388 * params is be cleared before insertion
390 void GetParameters(const TreeNode& child, Property::Map& params)
392 if( OptionalChild c = IsChild(child, "parameters") )
394 const TreeNode& node = *c;
398 for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
400 params[ (*iter).first ] = GetPropertyValue( (*iter).second );
405 // Shim for the property notifcation signal
406 template <typename T>
407 struct PropertyNotifcationSignalShim
411 PropertyNotifcationSignalShim(T& functor) : mFunctor(functor) {}
413 void operator()(PropertyNotification& /* source */)
419 // Specializations for the different signal connection calls between actor & PropertyNotification
420 template <typename T>
421 struct SignalConnector {};
423 // Actor specialization
425 struct SignalConnector<Actor> {
427 ConnectionTracker* mTracker;
428 const std::string& mName;
430 SignalConnector<Actor>(ConnectionTracker* tracker, Actor& actor, const std::string& name)
431 : mActor(actor), mTracker(tracker), mName(name) {}
433 template <typename T>
434 void Connect(T& functor)
436 mActor.ConnectSignal( mTracker, mName, functor);
440 // PropertyNotification specialization
442 struct SignalConnector<PropertyNotification>
444 PropertyNotification& mNotification;
445 ConnectionTracker* mTracker;
447 SignalConnector<PropertyNotification>(ConnectionTracker* tracker, PropertyNotification ¬ification)
448 : mNotification(notification), mTracker(tracker) {}
450 template <typename T>
451 void Connect(T& functor)
453 mNotification.NotifySignal().Connect( mTracker, PropertyNotifcationSignalShim<T>(functor) );
458 * Set an action functor on a signal
460 template <typename T>
461 void SetActionOnSignal(const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder, SignalConnector<T>& connector)
463 OptionalString childActorName(IsString( IsChild(&child, "childActor")) );
464 OptionalString actorName(IsString( IsChild(&child, "actor")) );
465 OptionalString propertyName(IsString( IsChild(&child, "property")) );
466 OptionalChild valueChild( IsChild(&child, "value") );
468 OptionalString actionName = IsString( IsChild(&child, "action") );
469 DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
473 ChildActorAction action;
474 action.actorName = *actorName;
475 action.childName = *childActorName;
476 action.actionName = *actionName;
477 GetParameters(child, action.parameters);
478 connector.Connect( action );
482 if(propertyName && valueChild && ("set" == *actionName) )
484 PropertySetAction action;
485 action.actorName = *actorName;
486 action.propertyName = *propertyName;
487 // actor may not exist yet so we can't check the property type
488 Dali::Toolkit::Internal::DeterminePropertyFromNode( *valueChild, action.value );
489 connector.Connect( action );
493 GenericAction action;
494 action.actorName = *actorName;
495 action.actionName = *actionName;
496 GetParameters(child, action.parameters);
497 connector.Connect( action );
500 else if("quit" == *actionName)
503 action.builder = builder;
504 connector.Connect( action );
506 else if("play" == *actionName)
508 OptionalChild animations = IsChild( root, "animations" );
509 OptionalString animationName = IsString( IsChild(child, "animation") );
510 if( animations && animationName )
512 if( OptionalChild animNode = IsChild(*animations, *animationName) )
514 DelayedAnimationPlay action;
515 action.animNode = animNode;
516 action.builder = builder;
517 // @todo; put constants into the map
518 connector.Connect( action );
522 DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
527 DALI_SCRIPT_WARNING("Cannot find animations section\n");
530 else if("applyConstraint" == *actionName )
532 OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
533 if( !constrainerName )
535 DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
539 DelayedConstrainerApply action;
540 action.constrainerName = *constrainerName;
541 action.builder = builder;
542 OptionalChild propertiesNode = IsChild(child, "properties");
545 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
546 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
548 const TreeNode::KeyNodePair& pKeyChild = *iter;
549 OptionalString sourceActorName(IsString(IsChild(pKeyChild.second, "source")));
552 DALI_SCRIPT_WARNING("Need to specify source actor to apply the constraint\n");
555 OptionalString sourcePropertyName( IsString( IsChild(pKeyChild.second, "sourceProperty" ) ) );
556 if(!sourcePropertyName)
558 DALI_SCRIPT_WARNING("Need to specify source property to apply the constraint\n");
562 OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
565 DALI_SCRIPT_WARNING("Need to specify target actor to apply the constraint\n");
569 OptionalString targetPropertyName( IsString( IsChild(pKeyChild.second, "targetProperty" ) ) );
570 if(!targetPropertyName)
572 DALI_SCRIPT_WARNING("Need to specify target property name to apply the constraint\n");
576 OptionalVector2 range(IsVector2(IsChild(pKeyChild.second, "range")));
579 DALI_SCRIPT_WARNING("Constrainer range not specified\n");
583 Vector2 wrap(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
584 OptionalVector2 wrapRange(IsVector2(IsChild(pKeyChild.second, "wrap")));
590 action.sourceActorNames.push_back(*sourceActorName);
591 action.sourcePropertyNames.push_back(*sourcePropertyName);
592 action.targetActorNames.push_back(*targetActorName);
593 action.targetPropertyNames.push_back(*targetPropertyName);
594 action.ranges.push_back(*range);
595 action.wrapRanges.push_back(wrap);
597 connector.Connect(action);
601 else if("removeConstraints" == *actionName )
603 OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
604 if( !constrainerName )
606 DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
611 DelayedConstrainerRemove action;
612 action.constrainerName = *constrainerName;
613 action.builder = builder;
614 OptionalChild propertiesNode = IsChild(child, "properties");
617 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
618 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
620 const TreeNode::KeyNodePair& pKeyChild = *iter;
621 OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
624 action.targetActorNames.push_back(*targetActorName);
628 DALI_SCRIPT_WARNING("Need to specify target actor to remove the constraint\n");
633 connector.Connect(action);
638 // no named actor; presume self
639 GenericAction action;
640 action.actorName = actor.GetProperty< std::string >( Dali::Actor::Property::NAME );
641 action.actionName = *actionName;
642 GetParameters(child, action.parameters);
643 connector.Connect( action );
649 * Get a notification condition argument0 as 'arg0' 'value' or 'min'
651 float GetConditionArg0(const TreeNode &child)
653 OptionalFloat f = IsFloat( IsChild(child, "arg0") );
654 // allowing some human preferable alternatives
657 f = IsFloat( IsChild(child, "value") );
661 f = IsFloat( IsChild(child, "min") );
664 DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
670 * Get a notification condition argument1 as 'arg1' or 'max'
672 float GetConditionArg1(const TreeNode &child)
674 OptionalFloat f = IsFloat( IsChild(child, "arg1") );
675 // allowing some human preferable alternatives
678 f = IsFloat( IsChild(child, "max") );
681 DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
697 Actor SetupSignalAction(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
698 Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
701 * Setup signals and actions on an actor
703 Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder )
705 DALI_ASSERT_ALWAYS(actor);
707 if(OptionalChild signalsChild = IsChild(child, "signals"))
709 const TreeNode& signalsNode = *signalsChild;
710 const TreeConstIter endIter = signalsNode.CEnd();
711 for( TreeConstIter iter = signalsNode.CBegin(); endIter != iter; ++iter )
713 const TreeNode::KeyNodePair& key_child = *iter;
715 DALI_SCRIPT_INFO(" Creating Signal for: %s\n", actor.GetProperty< std::string >( Dali::Actor::Property::NAME ).c_str());
717 OptionalString name( IsString( IsChild( key_child.second, "name")) );
718 DALI_ASSERT_ALWAYS(name && "Signal must have a name");
720 SignalConnector<Actor> connector(tracker, actor, *name);
721 SetActionOnSignal(root, key_child.second, actor, builder, connector);
729 * Setup Property notifications for an actor
731 Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder )
733 DALI_ASSERT_ALWAYS(actor);
735 if(OptionalChild notificationsChild = IsChild(child,"notifications"))
737 const TreeNode& notificationsNode = *notificationsChild;
738 const TreeNode::ConstIterator endIter = notificationsNode.CEnd();
739 for( TreeNode::ConstIterator iter = notificationsNode.CBegin(); endIter != iter; ++iter )
741 const TreeNode::KeyNodePair& key_child = *iter;
743 OptionalString prop(IsString( IsChild(key_child.second, "property")) );
744 DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
746 Property::Index prop_index = actor.GetPropertyIndex(*prop);
747 DALI_ASSERT_ALWAYS(prop_index != Property::INVALID_INDEX && "Notification signal specifies an unknown property");
749 OptionalString cond(IsString( IsChild(key_child.second, "condition")));
750 DALI_ASSERT_ALWAYS(cond && "Notification signal must specify a condition");
754 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
755 LessThanCondition(1.f) );
756 SignalConnector<PropertyNotification> connector(tracker, notification);
757 SetActionOnSignal(root, key_child.second, actor, builder, connector);
759 else if("LessThan" == *cond)
761 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
762 LessThanCondition(GetConditionArg0(key_child.second)) );
763 SignalConnector<PropertyNotification> connector(tracker, notification);
764 SetActionOnSignal(root, key_child.second, actor, builder, connector);
766 else if("GreaterThan" == *cond)
768 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
769 GreaterThanCondition(GetConditionArg0(key_child.second)) );
770 SignalConnector<PropertyNotification> connector(tracker, notification);
771 SetActionOnSignal(root, key_child.second, actor, builder, connector);
773 else if("Inside" == *cond)
775 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
776 InsideCondition(GetConditionArg0(key_child.second),
777 GetConditionArg1(key_child.second)) );
778 SignalConnector<PropertyNotification> connector(tracker, notification);
779 SetActionOnSignal(root, key_child.second, actor, builder, connector);
781 else if("Outside" == *cond)
783 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
784 OutsideCondition(GetConditionArg0(key_child.second),
785 GetConditionArg1(key_child.second)) );
786 SignalConnector<PropertyNotification> connector(tracker, notification);
787 SetActionOnSignal(root, key_child.second, actor, builder, connector);
791 DALI_ASSERT_ALWAYS(!"Unknown condition");
794 } // if notifications
798 } // AddPropertyNotification
801 } // namespace Internal
802 } // namespace Toolkit