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/object/type-info.h>
22 #include <dali/public-api/object/property-notification.h>
23 #include <dali/integration-api/debug.h>
26 #include <dali-toolkit/internal/builder/builder-impl.h>
27 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
35 extern Animation CreateAnimation( const TreeNode& child, Dali::Toolkit::Internal::Builder* const builder );
36 extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
49 // Action on child actor. The child is found by name
50 struct ChildActorAction
52 std::string actorName;
53 std::string actionName;
54 std::string childName;
55 PropertyValueContainer parameters;
59 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
63 Actor child_actor = actor.FindChildByName(childName);
67 child_actor.DoAction(actionName, parameters);
71 DALI_SCRIPT_WARNING("Could not find child by name '%s'\n", childName.c_str());
77 // Action to set a property
78 struct PropertySetAction
80 std::string actorName;
81 std::string propertyName;
82 Property::Value value;
86 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
90 Property::Index idx = actor.GetPropertyIndex(propertyName);
92 if( idx != Property::INVALID_INDEX )
94 if( actor.GetPropertyType(idx) != value.GetType() )
96 DALI_SCRIPT_WARNING("Set property action has different type for property '%s'\n", propertyName.c_str());
100 actor.SetProperty( idx, value );
105 DALI_SCRIPT_WARNING("Set property action cannot find property '%s'\n", propertyName.c_str());
111 // Generic action on a handle (Animation & Actor)
114 std::string actorName;
115 std::string actionName;
116 PropertyValueContainer parameters;
118 void operator()(void)
120 Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
123 actor.DoAction(actionName, parameters);
129 // Delay an animation play; ie wait as its not on stage yet
130 struct DelayedAnimationPlay
132 OptionalChild animNode;
133 Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
135 void operator()(void)
137 Animation anim = Toolkit::Internal::CreateAnimation(*animNode, builder.Get() );
146 * Gets Property::Value from child
148 Property::Value GetPropertyValue(const TreeNode &child)
150 size_t nChildren = child.Size();
156 // cast away unused return for static analyzers
157 static_cast<void>( Dali::Toolkit::Internal::SetPropertyFromNode( child, ret ) );
159 else if(1 == nChildren)
161 // {"property": {"quaternion":[1,2,3,4]} }
162 // {"property": {"angle":22, "axis": [1,2,3]} }
164 OptionalChild quaternion = IsChild(&child, "quaternion");
165 OptionalChild axis = IsChild(&child, "axis");
166 OptionalChild angle = IsChild(&child, "angle");
170 ret = Property::Value(Quaternion(GetVector4(*quaternion)));
172 else if(axis && angle)
174 ret = Property::Value(AngleAxis(Degree(GetFloat(*angle)), GetVector3(*axis)));
177 else if(2 == nChildren)
179 // {"property": [1,2]}
180 ret = Property::Value(GetVector2(child));
182 else if(3 == nChildren)
184 // {"property": [1,2,3]}
185 ret = Property::Value(GetVector3(child));
187 else if(4 == nChildren)
189 // {"property": [1,2,3,4]}
190 ret = Property::Value(GetVector4(child));
198 * Gets Parmeter list from child
199 * params is be cleared before insertion
201 void GetParameters(const TreeNode& child, PropertyValueContainer& params)
203 if( OptionalChild c = IsChild(child, "parameters") )
205 const TreeNode& node = *c;
209 GetPropertyValue(node);
214 params.reserve(node.Size());
216 for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
218 params.push_back( GetPropertyValue( (*iter).second ) );
224 void DoNothing(void) {};
227 * Get an action as boost function callback
229 boost::function<void (void)> GetAction(const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder)
231 OptionalString childActorName(IsString( IsChild(&child, "child-actor")) );
232 OptionalString actorName(IsString( IsChild(&child, "actor")) );
233 OptionalString propertyName(IsString( IsChild(&child, "property")) );
234 OptionalChild valueChild( IsChild(&child, "value") );
236 OptionalString actionName = IsString( IsChild(&child, "action") );
237 DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
239 boost::function<void(void)> callback = DoNothing;
243 ChildActorAction action;
244 action.actorName = *actorName;
245 action.childName = *childActorName;
246 action.actionName = *actionName;
247 GetParameters(child, action.parameters);
252 if(propertyName && valueChild && ("set" == *actionName) )
254 PropertySetAction action;
255 action.actorName = *actorName;
256 action.propertyName = *propertyName;
257 // actor may not exist yet so we can't check the property type
258 if( !Dali::Toolkit::Internal::SetPropertyFromNode( *valueChild, action.value ) )
260 DALI_SCRIPT_WARNING("Cannot set property for set property action\n");
266 GenericAction action;
267 action.actorName = *actorName;
268 action.actionName = *actionName;
269 GetParameters(child, action.parameters);
273 else if("quit" == *actionName)
275 callback = quitAction;
277 else if("play" == *actionName)
279 OptionalChild animations = IsChild( root, "animations" );
280 OptionalString animationName = IsString( IsChild(child, "animation") );
281 if( animations && animationName )
283 if( OptionalChild animNode = IsChild(*animations, *animationName) )
285 DelayedAnimationPlay action;
286 action.animNode = animNode;
287 action.builder = builder;
288 // @todo; put constants into the map
293 DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
298 DALI_SCRIPT_WARNING("Cannot find animations section\n");
303 // no named actor; presume self
304 GenericAction action;
305 action.actorName = actor.GetName();
306 action.actionName = *actionName;
307 GetParameters(child, action.parameters);
316 * Get a notification condition argument0 as 'arg0' 'value' or 'min'
318 float GetConditionArg0(const TreeNode &child)
320 OptionalFloat f = IsFloat( IsChild(child, "arg0") );
321 // allowing some human preferable alternatives
324 f = IsFloat( IsChild(child, "value") );
328 f = IsFloat( IsChild(child, "min") );
331 DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
337 * Get a notification condition argument1 as 'arg1' or 'max'
339 float GetConditionArg1(const TreeNode &child)
341 OptionalFloat f = IsFloat( IsChild(child, "arg1") );
342 // allowing some human preferable alternatives
345 f = IsFloat( IsChild(child, "max") );
348 DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
364 Actor SetupSignalAction(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
365 Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
368 * Setup signals and actions on an actor
370 Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
372 DALI_ASSERT_ALWAYS(actor);
374 if(OptionalChild signalsChild = IsChild(child, "signals"))
376 const TreeNode& signalsNode = *signalsChild;
377 const TreeConstIter endIter = signalsNode.CEnd();
378 for( TreeConstIter iter = signalsNode.CBegin(); endIter != iter; ++iter )
380 const TreeNode::KeyNodePair& key_child = *iter;
382 DALI_SCRIPT_INFO(" Creating Signal for: %s\n", actor.GetName().c_str());
384 OptionalString name( IsString( IsChild( key_child.second, "name")) );
385 DALI_ASSERT_ALWAYS(name && "Signal must have a name");
387 boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction, builder );
389 actor.ConnectSignal(tracker, *name, callback);
397 * Setup Property notifications for an actor
399 Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, boost::function<void (void)> quitAction, Dali::Toolkit::Internal::Builder* const builder )
401 DALI_ASSERT_ALWAYS(actor);
403 if(OptionalChild notificationsChild = IsChild(child,"notifications"))
405 const TreeNode& notificationsNode = *notificationsChild;
406 const TreeNode::ConstIterator endIter = notificationsNode.CEnd();
407 for( TreeNode::ConstIterator iter = notificationsNode.CBegin(); endIter != iter; ++iter )
409 const TreeNode::KeyNodePair& key_child = *iter;
411 // Actor actions reference by pointer because of circular reference actor->signal
412 // So this callback should only go onto the actor maintained list.
413 boost::function<void (void)> callback = GetAction(root, key_child.second, actor, quitAction, builder );
415 OptionalString prop(IsString( IsChild(key_child.second, "property")) );
416 DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
418 Property::Index prop_index = actor.GetPropertyIndex(*prop);
419 DALI_ASSERT_ALWAYS(prop_index != Property::INVALID_INDEX && "Notification signal specifies an unknown property");
421 OptionalString cond(IsString( IsChild(key_child.second, "condition")));
422 DALI_ASSERT_ALWAYS(cond && "Notification signal must specify a condition");
426 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
427 LessThanCondition(1.f) );
428 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
430 else if("LessThan" == *cond)
432 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
433 LessThanCondition(GetConditionArg0(key_child.second)) );
434 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
436 else if("GreaterThan" == *cond)
438 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
439 GreaterThanCondition(GetConditionArg0(key_child.second)) );
440 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
442 else if("Inside" == *cond)
444 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
445 InsideCondition(GetConditionArg0(key_child.second),
446 GetConditionArg1(key_child.second)) );
447 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
449 else if("Outside" == *cond)
451 PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
452 OutsideCondition(GetConditionArg0(key_child.second),
453 GetConditionArg1(key_child.second)) );
454 notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
458 DALI_ASSERT_ALWAYS(!"Unknown condition");
461 } // if notifications
465 } // AddPropertyNotification
468 } // namespace Internal
469 } // namespace Toolkit