Make ItemView::ActivateLayout do what it says on the tin
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / builder-animations.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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
7 //
8 //     http://floralicense.org/license/
9 //
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.
15 //
16
17 // EXTERNAL INCLUDES
18 #include <dali/integration-api/debug.h>
19
20 // INTERNAL INCLUDES
21 #include <dali-toolkit/internal/builder/builder-impl.h>
22 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
23
24 namespace // unnamed namespace
25 {
26
27 using namespace Dali;
28
29 TimePeriod GetTimePeriod( const TreeNode& child )
30 {
31   OptionalFloat delay      = IsFloat( IsChild(child, "delay" ) );
32   OptionalFloat duration   = IsFloat( IsChild(child, "duration" ) );
33   DALI_ASSERT_ALWAYS( duration && "Time period must have at least a duration" );
34
35   if( delay )
36   {
37     return TimePeriod( *delay, *duration );
38   }
39   else
40   {
41     return TimePeriod( *duration );
42   }
43 }
44
45 Property::Value GetPropertyValue( const Property::Type& propType, const TreeNode& child )
46 {
47   switch ( propType )
48   {
49     case Property::BOOLEAN:
50     {
51       return Property::Value( GetBoolean( child ) );
52     }
53
54     case Property::FLOAT:
55     {
56       return Property::Value( GetFloat( child ) );
57     }
58
59     case Property::VECTOR2:
60     {
61       return Property::Value( GetVector2( child ) );
62     }
63
64     case Property::VECTOR3:
65     {
66       return Property::Value( GetVector3( child ) );
67     }
68
69     case Property::VECTOR4:
70     {
71       return Property::Value( GetVector4( child ) );
72     }
73
74     case Property::ROTATION:
75     {
76       if( 4 == child.Size() )
77       {
78         Vector4 v(GetVector4(child));
79         // angle, axis as per spec
80         return Property::Value( Quaternion(Radian(Degree(v[3])),
81                                            Vector3(v[0],v[1],v[2])) );
82       }
83       else
84       {
85         // degrees as per spec
86         Vector3 rotation = GetVector3( child );
87         return Property::Value( Quaternion(Radian(Degree(rotation.x)),
88                                            Radian(Degree(rotation.y)),
89                                            Radian(Degree(rotation.z))) );
90       }
91     }
92
93     case Property::NONE: // fall
94     default:
95     {
96       DALI_ASSERT_ALWAYS( !"Property type incorrect" );
97       return Property::Value();
98     }
99   }
100 }
101
102 AlphaFunction GetAlphaFunction( const std::string& alphaFunction )
103 {
104   typedef std::map< const std::string, Dali::AlphaFunction > AlphaFunctionLut;
105   static AlphaFunctionLut alphaFunctionLut;
106
107   if( 0 == alphaFunctionLut.size() )
108   {
109     // coding convention is uppercase enums
110     alphaFunctionLut["DEFAULT"]         = Dali::AlphaFunctions::Default;
111     alphaFunctionLut["LINEAR"]          = Dali::AlphaFunctions::Linear;
112     alphaFunctionLut["REVERSE"]         = Dali::AlphaFunctions::Reverse;
113     alphaFunctionLut["EASE_IN"]         = Dali::AlphaFunctions::EaseIn;
114     alphaFunctionLut["EASE_OUT"]        = Dali::AlphaFunctions::EaseOut;
115     alphaFunctionLut["EASE_IN_OUT"]     = Dali::AlphaFunctions::EaseInOut;
116     alphaFunctionLut["EASE_IN_SINE"]    = Dali::AlphaFunctions::EaseInSine;
117     alphaFunctionLut["EASE_OUT_SINE"]   = Dali::AlphaFunctions::EaseOutSine;
118     alphaFunctionLut["EASE_IN_OUT_SINE"]= Dali::AlphaFunctions::EaseInOutSine;
119     alphaFunctionLut["BOUNCE"]          = Dali::AlphaFunctions::Bounce;
120     alphaFunctionLut["BOUNCE_BACK"]     = Dali::AlphaFunctions::BounceBack;
121     alphaFunctionLut["EASE_OUT_BACK"]   = Dali::AlphaFunctions::EaseOutBack;
122     alphaFunctionLut["SIN"]             = Dali::AlphaFunctions::Sin;
123     alphaFunctionLut["SIN2X"]           = Dali::AlphaFunctions::Sin;
124   }
125
126   const AlphaFunctionLut::const_iterator iter( alphaFunctionLut.find( alphaFunction ) );
127
128   if( iter != alphaFunctionLut.end() )
129   {
130     return iter->second;
131   }
132   else
133   {
134     DALI_ASSERT_ALWAYS( iter != alphaFunctionLut.end() && "Unknown Anchor Constant" );
135     return Dali::AlphaFunctions::Default;
136   }
137 }
138
139 } // unnamed namespace
140
141
142 namespace Dali
143 {
144
145 namespace Toolkit
146 {
147
148 namespace Internal
149 {
150
151 Animation CreateAnimation( const TreeNode& child )
152 {
153   float durationSum = 0.f;
154
155   Animation animation( Animation::New( 0.f ) );
156
157   if( OptionalBoolean looping = IsBoolean(  IsChild(child, "loop" ) ) )
158   {
159     animation.SetLooping( *looping );
160   }
161
162   if( OptionalString endAction = IsString(  IsChild(child, "end-action" ) ) )
163   {
164     if("BAKE" == *endAction)
165     {
166       animation.SetEndAction( Animation::Bake );
167     }
168     else if("DISCARD" == *endAction)
169     {
170       animation.SetEndAction( Animation::Discard );
171     }
172   }
173
174   if( OptionalString endAction = IsString(  IsChild(child, "destroy-action" ) ) )
175   {
176     if("BAKE" == *endAction)
177     {
178       animation.SetDestroyAction( Animation::Bake );
179     }
180     else if("DISCARD" == *endAction)
181     {
182       animation.SetDestroyAction( Animation::Discard );
183     }
184   }
185
186   OptionalChild propertiesNode = IsChild(child, "properties" );
187   if(propertiesNode)
188   {
189     const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
190     for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
191     {
192       const TreeNode::KeyNodePair& pKeyChild = *iter;
193
194       OptionalString actorName( IsString( pKeyChild.second, "actor" ) );
195       OptionalString property(  IsString( pKeyChild.second, "property" ) );
196       DALI_ASSERT_ALWAYS( actorName && "Animation must specify actor name" );
197       DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
198
199       Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName( *actorName );
200       DALI_ASSERT_ALWAYS( targetActor && "Actor must exist for property" );
201
202       Property::Index idx( targetActor.GetPropertyIndex( *property ) );
203
204       // A limitation here is that its possible that between binding to the signal and
205       // the signal call that the ShaderEffect of the targetActor has been changed.
206       // However this is a unlikely use case especially when using scripts.
207       if( idx == Property::INVALID_INDEX )
208       {
209         if( ShaderEffect effect = targetActor.GetShaderEffect() )
210         {
211           idx = effect.GetPropertyIndex( *property );
212           if(idx != Property::INVALID_INDEX)
213           {
214             targetActor = effect;
215           }
216           else
217           {
218             DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
219             continue;
220           }
221         }
222         else
223         {
224           DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
225           continue;
226         }
227       }
228
229       if( idx == Property::INVALID_INDEX)
230       {
231         DALI_ASSERT_ALWAYS( idx != Property::INVALID_INDEX && "Animation must specify a valid property" );
232         continue;
233       }
234
235       Property prop( Property( targetActor, idx ) );
236       Property::Value propValue;
237
238       // these are the defaults
239       AlphaFunction alphaFunction( AlphaFunctions::Default );
240       TimePeriod timePeriod( 0.f );
241
242       if( OptionalChild timeChild = IsChild( pKeyChild.second, "time-period" ) )
243       {
244         timePeriod = GetTimePeriod( *timeChild );
245       }
246
247       durationSum = std::max( durationSum, timePeriod.delaySeconds + timePeriod.durationSeconds );
248
249       if( OptionalString alphaChild = IsString( pKeyChild.second, "alpha-function" ) )
250       {
251         alphaFunction = GetAlphaFunction( *alphaChild );
252       }
253
254       if( OptionalChild keyFrameChild = IsChild(pKeyChild.second, "key-frames") )
255       {
256         KeyFrames keyframes = KeyFrames::New();
257
258         const TreeNode::ConstIterator endIter = (*keyFrameChild).CEnd();
259         for( TreeNode::ConstIterator iter = (*keyFrameChild).CBegin(); endIter != iter; ++iter )
260         {
261           const TreeNode::KeyNodePair& kfKeyChild = *iter;
262
263           OptionalFloat kfProgress = IsFloat( kfKeyChild.second, "progress" );
264           DALI_ASSERT_ALWAYS( kfProgress && "Key frame entry must have 'progress'" );
265
266           OptionalChild kfValue = IsChild( kfKeyChild.second, "value" );
267           DALI_ASSERT_ALWAYS( kfValue && "Key frame entry must have 'value'" );
268
269           try
270           {
271             propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *kfValue );
272           }
273           catch(...)
274           {
275             DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n",
276                               (*property).c_str(),
277                               PropertyTypes::GetName(prop.object.GetPropertyType(prop.propertyIndex)) );
278
279             throw;
280           }
281
282           AlphaFunction kfAlphaFunction( AlphaFunctions::Default );
283           if( OptionalString alphaFuncStr = IsString( pKeyChild.second, "alpha-function") )
284           {
285             kfAlphaFunction = GetAlphaFunction( *alphaFuncStr );
286           }
287
288           keyframes.Add( *kfProgress, propValue, kfAlphaFunction );
289         }
290
291         animation.AnimateBetween( prop, keyframes, alphaFunction, timePeriod );
292       }
293       else
294       {
295         try
296         {
297           propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *IsChild(pKeyChild.second, "value") );
298         }
299         catch(...)
300         {
301           DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n", (*property).c_str(),
302                             PropertyTypes::GetName( prop.object.GetPropertyType(prop.propertyIndex) ) );
303
304           throw;
305         }
306
307         if( OptionalBoolean relative = IsBoolean(pKeyChild.second, "relative") )
308         {
309           animation.AnimateBy( prop, propValue, alphaFunction, timePeriod );
310         }
311         else
312         {
313           animation.AnimateTo( prop, propValue, alphaFunction, timePeriod );
314         }
315       }
316     }
317   }
318
319   if( OptionalFloat duration = IsFloat( child, "duration" ) )
320   {
321     animation.SetDuration( *duration );
322   }
323   else
324   {
325     animation.SetDuration( durationSum );
326   }
327
328   return animation;
329 }
330
331 } // namespace Internal
332
333 } // namespace Toolkit
334
335 } // namespace Dali
336