-//
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Flora License, Version 1.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://floralicense.org/license/
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an AS IS BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
// EXTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/type-info.h>
+#include <dali/public-api/object/property-notification.h>
+
#include <dali/integration-api/debug.h>
+#include <limits>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/builder/builder-impl.h>
{
namespace Internal
{
-extern Animation CreateAnimation( const TreeNode& child );
-extern bool SetPropertyFromNode( const TreeNode& node, Property::Value& value );
+extern Animation CreateAnimation( const TreeNode& child, Dali::Toolkit::Internal::Builder* const builder );
+extern void DeterminePropertyFromNode( const TreeNode& node, Property::Value& value );
}
}
}
// Signal Actions
//
-// Action quit; connected to signals
-// TODO: MOVE TO BUILDER TEMPLATE
-struct ActionQuit
-{
- ActionQuit(void) {};
-
- void operator()(void) {
- // Dali::Application::Get().Quit();
- };
-};
-
-// Action on child actor. The child is found by alias so can be 'previous' etc.
+// Action on child actor. The child is found by name
struct ChildActorAction
{
std::string actorName;
std::string actionName;
- std::string childAlias;
- std::vector<Property::Value> parameters;
+ std::string childName;
+ Property::Map parameters;
void operator()(void)
{
if(actor)
{
- Actor child_actor = actor.FindChildByAlias(childAlias);
+ Actor child_actor = actor.FindChildByName(childName);
if(child_actor)
{
}
else
{
- DALI_SCRIPT_WARNING("Could not find child by alias '%s'\n", childAlias.c_str());
+ DALI_SCRIPT_WARNING("Could not find child by name '%s'\n", childName.c_str());
}
}
};
if( idx != Property::INVALID_INDEX )
{
- actor.SetProperty( idx, value );
+ if( actor.GetPropertyType(idx) != value.GetType() )
+ {
+ DALI_SCRIPT_WARNING("Set property action has different type for property '%s'\n", propertyName.c_str());
+ }
+ else
+ {
+ actor.SetProperty( idx, value );
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Set property action cannot find property '%s'\n", propertyName.c_str());
}
}
};
{
std::string actorName;
std::string actionName;
- std::vector<Property::Value> parameters;
+ Property::Map parameters;
void operator()(void)
{
};
};
+struct QuitAction
+{
+ Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
+
+ void operator()(void)
+ {
+ builder->EmitQuitSignal();
+ }
+};
+
// Delay an animation play; ie wait as its not on stage yet
struct DelayedAnimationPlay
{
- Toolkit::JsonParser memento;
+ OptionalChild animNode;
+ Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
void operator()(void)
{
- Animation anim = Toolkit::Internal::CreateAnimation(*memento.GetRoot());
+ Animation anim = Toolkit::Internal::CreateAnimation(*animNode, builder.Get() );
if(anim)
{
anim.Play();
};
};
+// Delay a pathConstrainer apply
+struct DelayedConstrainerApply
+{
+ std::string constrainerName;
+
+ std::vector<std::string> targetActorNames;
+ std::vector<std::string> sourceActorNames;
+ std::vector<std::string> targetPropertyNames;
+ std::vector<std::string> sourcePropertyNames;
+ std::vector<Vector2> ranges;
+ std::vector<Vector2> wrapRanges;
+
+ Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
+
+ /*
+ * Helper function to get the parameters to apply each constraint
+ * @param[in] i i-essim element
+ * @param[out] tagetActor Target actor for the constraint
+ * @param[out] tagetPropertyIndex Target property index for the constraint
+ * @param[out] sourceActor Source actor for the constraint
+ * @param[out] sourcePropertyIndex Source property index for the constraint
+ */
+ bool GetApplyParameters( size_t i,
+ Actor& targetActor, Property::Index& targetPropertyIndex,
+ Actor& sourceActor, Property::Index& sourcePropertyIndex)
+ {
+
+ targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
+ targetPropertyIndex = Property::INVALID_INDEX;
+ if(targetActor)
+ {
+ targetPropertyIndex = targetActor.GetPropertyIndex(targetPropertyNames[i]);
+ if( targetPropertyIndex == Property::INVALID_INDEX )
+ {
+ DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", targetPropertyNames[i].c_str(), targetActorNames[i].c_str() );
+ return false;
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
+ return false;
+ }
+
+
+ sourceActor = Stage::GetCurrent().GetRootLayer().FindChildByName(sourceActorNames[i]);
+ sourcePropertyIndex = Property::INVALID_INDEX;
+ if(sourceActor)
+ {
+ sourcePropertyIndex = sourceActor.GetPropertyIndex(sourcePropertyNames[i]);
+ if( sourcePropertyIndex == Property::INVALID_INDEX )
+ {
+ DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", sourcePropertyNames[i].c_str(), sourceActorNames[i].c_str() );
+ return false;
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
+ return false;
+ }
+ return true;
+ }
+
+ void operator()(void)
+ {
+ Actor sourceActor, targetActor;
+ Property::Index targetPropertyIndex(Property::INVALID_INDEX);
+ Property::Index sourcePropertyIndex(Property::INVALID_INDEX);
+ size_t actorCount( targetActorNames.size() );
+ if( builder.Get()->IsPathConstrainer( constrainerName ))
+ {
+ PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
+ if( constrainer )
+ {
+ for(size_t i(0); i<actorCount; ++i )
+ {
+
+ if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
+ {
+ constrainer.Apply( Property(targetActor,targetPropertyIndex),
+ Property(sourceActor,sourcePropertyIndex),
+ ranges[i],
+ wrapRanges[i]);
+ }
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
+ }
+ }
+ else if( builder.Get()->IsLinearConstrainer( constrainerName ) )
+ {
+ Dali::LinearConstrainer constrainer( builder.Get()->GetLinearConstrainer(constrainerName));
+ if( constrainer )
+ {
+ for(size_t i(0); i<actorCount; ++i )
+ {
+
+ if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
+ {
+ constrainer.Apply( Property(targetActor,targetPropertyIndex),
+ Property(sourceActor,sourcePropertyIndex),
+ ranges[i],
+ wrapRanges[i]);
+ }
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
+ }
+ }
+};
+
+// Delay a pathConstrainer remove
+struct DelayedConstrainerRemove
+{
+ std::string constrainerName;
+ std::vector<std::string> targetActorNames;
+ Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
+
+ void operator()(void)
+ {
+ size_t actorCount( targetActorNames.size() );
+ if( builder.Get()->IsPathConstrainer( constrainerName ))
+ {
+ PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
+ if( constrainer )
+ {
+ for(size_t i(0); i<actorCount; ++i )
+ {
+ Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
+ if(targetActor)
+ {
+ constrainer.Remove( targetActor );
+ }
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
+ }
+ }
+ else if(builder.Get()->IsLinearConstrainer( constrainerName ))
+ {
+ LinearConstrainer constrainer = builder.Get()->GetLinearConstrainer(constrainerName);
+ if( constrainer )
+ {
+ for(size_t i(0); i<actorCount; ++i )
+ {
+ Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
+ if(targetActor)
+ {
+ constrainer.Remove( targetActor );
+ }
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
+ }
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
+ }
+ }
+};
+
/*
* Gets Property::Value from child
*/
if(0 == nChildren)
{
// cast away unused return for static analyzers
- static_cast<void>( Dali::Toolkit::Internal::SetPropertyFromNode( child, ret ) );
+ static_cast<void>( Dali::Toolkit::Internal::DeterminePropertyFromNode( child, ret ) );
}
else if(1 == nChildren)
{
* Gets Parmeter list from child
* params is be cleared before insertion
*/
-void GetParameters(const TreeNode &child, std::vector<Property::Value> ¶ms)
+void GetParameters(const TreeNode& child, Property::Map& params)
{
if( OptionalChild c = IsChild(child, "parameters") )
{
const TreeNode& node = *c;
- if(0 == node.Size())
- {
- GetPropertyValue(node);
- }
- else
- {
- params.clear();
- params.reserve(node.Size());
+ params.Clear();
- for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
- {
- params.push_back( GetPropertyValue( (*iter).second ) );
- }
+ for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
+ {
+ params[ (*iter).first ] = GetPropertyValue( (*iter).second );
}
}
}
-void DoNothing(void) {};
+// Shim for the property notifcation signal
+template <typename T>
+struct PropertyNotifcationSignalShim
+{
+ T mFunctor;
+
+ PropertyNotifcationSignalShim(T& functor) : mFunctor(functor) {}
+
+ void operator()(PropertyNotification& /* source */)
+ {
+ mFunctor();
+ }
+};
+
+// Specializations for the different signal connection calls between actor & PropertyNotification
+template <typename T>
+struct SignalConnector {};
+
+// Actor specialization
+template <>
+struct SignalConnector<Actor> {
+ Actor& mActor;
+ ConnectionTracker* mTracker;
+ const std::string& mName;
+
+ SignalConnector<Actor>(ConnectionTracker* tracker, Actor& actor, const std::string& name)
+ : mActor(actor), mTracker(tracker), mName(name) {}
+
+ template <typename T>
+ void Connect(T& functor)
+ {
+ mActor.ConnectSignal( mTracker, mName, functor);
+ }
+};
+
+// PropertyNotification specialization
+template <>
+struct SignalConnector<PropertyNotification>
+{
+ PropertyNotification& mNotification;
+ ConnectionTracker* mTracker;
+
+ SignalConnector<PropertyNotification>(ConnectionTracker* tracker, PropertyNotification ¬ification)
+ : mNotification(notification), mTracker(tracker) {}
+
+ template <typename T>
+ void Connect(T& functor)
+ {
+ mNotification.NotifySignal().Connect( mTracker, PropertyNotifcationSignalShim<T>(functor) );
+ }
+};
/**
- * Get an action as boost function callback
+ * Set an action functor on a signal
*/
-boost::function<void (void)> GetAction(const TreeNode &root, const TreeNode &child, Actor actor)
+template <typename T>
+void SetActionOnSignal(const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder, SignalConnector<T>& connector)
{
- OptionalString childActorName(IsString( IsChild(&child, "child-actor")) );
+ OptionalString childActorName(IsString( IsChild(&child, "childActor")) );
OptionalString actorName(IsString( IsChild(&child, "actor")) );
OptionalString propertyName(IsString( IsChild(&child, "property")) );
- OptionalString valueChild(IsString( IsChild(&child, "value")) );
+ OptionalChild valueChild( IsChild(&child, "value") );
OptionalString actionName = IsString( IsChild(&child, "action") );
DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
- boost::function<void(void)> callback = DoNothing;
-
if(childActorName)
{
ChildActorAction action;
action.actorName = *actorName;
- action.childAlias = *childActorName;
+ action.childName = *childActorName;
action.actionName = *actionName;
GetParameters(child, action.parameters);
- callback = action;
+ connector.Connect( action );
}
else if(actorName)
{
- if(propertyName && valueChild)
+ if(propertyName && valueChild && ("set" == *actionName) )
{
PropertySetAction action;
action.actorName = *actorName;
action.propertyName = *propertyName;
- callback = action;
+ // actor may not exist yet so we can't check the property type
+ Dali::Toolkit::Internal::DeterminePropertyFromNode( *valueChild, action.value );
+ connector.Connect( action );
}
else
{
action.actorName = *actorName;
action.actionName = *actionName;
GetParameters(child, action.parameters);
- callback = action;
+ connector.Connect( action );
}
}
else if("quit" == *actionName)
{
- callback = ActionQuit();
+ QuitAction action;
+ action.builder = builder;
+ connector.Connect( action );
}
else if("play" == *actionName)
{
if( OptionalChild animNode = IsChild(*animations, *animationName) )
{
DelayedAnimationPlay action;
- action.memento = Toolkit::JsonParser::New(*animNode);
- callback = action;
+ action.animNode = animNode;
+ action.builder = builder;
+ // @todo; put constants into the map
+ connector.Connect( action );
}
else
{
DALI_SCRIPT_WARNING("Cannot find animations section\n");
}
}
+ else if("applyConstraint" == *actionName )
+ {
+ OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
+ if( !constrainerName )
+ {
+ DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
+ }
+ else
+ {
+ DelayedConstrainerApply action;
+ action.constrainerName = *constrainerName;
+ action.builder = builder;
+ OptionalChild propertiesNode = IsChild(child, "properties");
+ if(propertiesNode)
+ {
+ const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
+ for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
+ {
+ const TreeNode::KeyNodePair& pKeyChild = *iter;
+ OptionalString sourceActorName(IsString(IsChild(pKeyChild.second, "source")));
+ if(!sourceActorName)
+ {
+ DALI_SCRIPT_WARNING("Need to specify source actor to apply the constraint\n");
+ continue;
+ }
+ OptionalString sourcePropertyName( IsString( IsChild(pKeyChild.second, "sourceProperty" ) ) );
+ if(!sourcePropertyName)
+ {
+ DALI_SCRIPT_WARNING("Need to specify source property to apply the constraint\n");
+ continue;
+ }
+
+ OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
+ if(!targetActorName)
+ {
+ DALI_SCRIPT_WARNING("Need to specify target actor to apply the constraint\n");
+ continue;
+ }
+
+ OptionalString targetPropertyName( IsString( IsChild(pKeyChild.second, "targetProperty" ) ) );
+ if(!targetPropertyName)
+ {
+ DALI_SCRIPT_WARNING("Need to specify target property name to apply the constraint\n");
+ continue;
+ }
+
+ OptionalVector2 range(IsVector2(IsChild(pKeyChild.second, "range")));
+ if(!range)
+ {
+ DALI_SCRIPT_WARNING("Constrainer range not specified\n");
+ continue;
+ }
+
+ Vector2 wrap(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
+ OptionalVector2 wrapRange(IsVector2(IsChild(pKeyChild.second, "wrap")));
+ if(wrapRange)
+ {
+ wrap = *wrapRange;
+ }
+
+ action.sourceActorNames.push_back(*sourceActorName);
+ action.sourcePropertyNames.push_back(*sourcePropertyName);
+ action.targetActorNames.push_back(*targetActorName);
+ action.targetPropertyNames.push_back(*targetPropertyName);
+ action.ranges.push_back(*range);
+ action.wrapRanges.push_back(wrap);
+ }
+ connector.Connect(action);
+ }
+ }
+ }
+ else if("removeConstraints" == *actionName )
+ {
+ OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
+ if( !constrainerName )
+ {
+ DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
+ }
+ else
+ {
+
+ DelayedConstrainerRemove action;
+ action.constrainerName = *constrainerName;
+ action.builder = builder;
+ OptionalChild propertiesNode = IsChild(child, "properties");
+ if(propertiesNode)
+ {
+ const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
+ for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
+ {
+ const TreeNode::KeyNodePair& pKeyChild = *iter;
+ OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
+ if(targetActorName)
+ {
+ action.targetActorNames.push_back(*targetActorName);
+ }
+ else
+ {
+ DALI_SCRIPT_WARNING("Need to specify target actor to remove the constraint\n");
+ continue;
+ }
+ }
+ }
+ connector.Connect(action);
+ }
+ }
else
{
// no named actor; presume self
action.actorName = actor.GetName();
action.actionName = *actionName;
GetParameters(child, action.parameters);
- callback = action;
+ connector.Connect( action );
}
-
- return callback;
}
{
f = IsFloat( IsChild(child, "min") );
}
+
DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
- if(f)
- {
- return *f;
- }
- else
- {
- return 0.f;
- }
+
+ return *f;
}
/**
{
f = IsFloat( IsChild(child, "max") );
}
+
DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
- if(f)
- {
- return *f;
- }
- else
- {
- return 0.f;
- }
+
+ return *f;
}
namespace Internal
{
-Actor SetupSignalAction(const TreeNode &child, Actor actor);
-Actor SetupPropertyNotification(const TreeNode &child, Actor actor);
+Actor SetupSignalAction(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
+Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
/**
* Setup signals and actions on an actor
*/
-Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor)
+Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder )
{
DALI_ASSERT_ALWAYS(actor);
OptionalString name( IsString( IsChild( key_child.second, "name")) );
DALI_ASSERT_ALWAYS(name && "Signal must have a name");
- boost::function<void (void)> callback = GetAction(root, key_child.second, actor);
-
- actor.ConnectSignal(tracker, *name, callback);
+ SignalConnector<Actor> connector(tracker, actor, *name);
+ SetActionOnSignal(root, key_child.second, actor, builder, connector);
}
}
/**
* Setup Property notifications for an actor
*/
-Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor)
+Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder )
{
DALI_ASSERT_ALWAYS(actor);
{
const TreeNode::KeyNodePair& key_child = *iter;
- // Actor actions reference by pointer because of circular reference actor->signal
- // So this callback should only go onto the actor maintained list.
- boost::function<void (void)> callback = GetAction(root, key_child.second, actor);
-
OptionalString prop(IsString( IsChild(key_child.second, "property")) );
DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
{
PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
LessThanCondition(1.f) );
- notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
+ SignalConnector<PropertyNotification> connector(tracker, notification);
+ SetActionOnSignal(root, key_child.second, actor, builder, connector);
}
else if("LessThan" == *cond)
{
PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
LessThanCondition(GetConditionArg0(key_child.second)) );
- notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
+ SignalConnector<PropertyNotification> connector(tracker, notification);
+ SetActionOnSignal(root, key_child.second, actor, builder, connector);
}
else if("GreaterThan" == *cond)
{
PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
GreaterThanCondition(GetConditionArg0(key_child.second)) );
- notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
+ SignalConnector<PropertyNotification> connector(tracker, notification);
+ SetActionOnSignal(root, key_child.second, actor, builder, connector);
}
else if("Inside" == *cond)
{
PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
InsideCondition(GetConditionArg0(key_child.second),
GetConditionArg1(key_child.second)) );
- notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
+ SignalConnector<PropertyNotification> connector(tracker, notification);
+ SetActionOnSignal(root, key_child.second, actor, builder, connector);
}
else if("Outside" == *cond)
{
PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
OutsideCondition(GetConditionArg0(key_child.second),
GetConditionArg1(key_child.second)) );
- notification.NotifySignal().Connect( tracker, FunctorDelegate::New(callback) );
+ SignalConnector<PropertyNotification> connector(tracker, notification);
+ SetActionOnSignal(root, key_child.second, actor, builder, connector);
}
else
{