Fixed popup label properties
[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 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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
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
18 // EXTERNAL INCLUDES
19 #include <dali/integration-api/debug.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/builder/builder-impl.h>
23 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
24 #include <dali-toolkit/internal/builder/replacement.h>
25
26 namespace // unnamed namespace
27 {
28
29 using namespace Dali;
30
31 TimePeriod GetTimePeriod( const TreeNode& child, const Toolkit::Internal::Replacement& constant )
32 {
33   OptionalFloat delay      = constant.IsFloat( IsChild(child, "delay" ) );
34   OptionalFloat duration   = constant.IsFloat( IsChild(child, "duration" ) );
35   DALI_ASSERT_ALWAYS( duration && "Time period must have at least a duration" );
36
37   if( delay )
38   {
39     return TimePeriod( *delay, *duration );
40   }
41   else
42   {
43     return TimePeriod( *duration );
44   }
45 }
46
47 Property::Value GetPropertyValue( const Property::Type& propType, const TreeNode& child )
48 {
49   switch ( propType )
50   {
51     case Property::BOOLEAN:
52     {
53       return Property::Value( GetBoolean( child ) );
54     }
55
56     case Property::FLOAT:
57     {
58       return Property::Value( GetFloat( child ) );
59     }
60
61     case Property::VECTOR2:
62     {
63       return Property::Value( GetVector2( child ) );
64     }
65
66     case Property::VECTOR3:
67     {
68       return Property::Value( GetVector3( child ) );
69     }
70
71     case Property::VECTOR4:
72     {
73       return Property::Value( GetVector4( child ) );
74     }
75
76     case Property::ROTATION:
77     {
78       if( 4 == child.Size() )
79       {
80         Vector4 v(GetVector4(child));
81         // angle, axis as per spec
82         return Property::Value( Quaternion(Radian(Degree(v[3])),
83                                            Vector3(v[0],v[1],v[2])) );
84       }
85       else
86       {
87         // degrees as per spec
88         Vector3 rotation = GetVector3( child );
89         return Property::Value( Quaternion(Radian(Degree(rotation.x)),
90                                            Radian(Degree(rotation.y)),
91                                            Radian(Degree(rotation.z))) );
92       }
93     }
94
95     case Property::NONE: // fall
96     default:
97     {
98       DALI_ASSERT_ALWAYS( !"Property type incorrect" );
99     }
100   }
101 }
102
103 AlphaFunction GetAlphaFunction( const std::string& alphaFunction )
104 {
105   typedef std::map< const std::string, Dali::AlphaFunction > AlphaFunctionLut;
106   static AlphaFunctionLut alphaFunctionLut;
107
108   if( 0 == alphaFunctionLut.size() )
109   {
110     // coding convention is uppercase enums
111     alphaFunctionLut["DEFAULT"]                    = AlphaFunctions::Default;
112     alphaFunctionLut["LINEAR"]                     = AlphaFunctions::Linear;
113     alphaFunctionLut["SQUARE"]                     = AlphaFunctions::Square;
114     alphaFunctionLut["REVERSE"]                    = AlphaFunctions::Reverse;
115     alphaFunctionLut["EASE_IN"]                    = AlphaFunctions::EaseIn;
116     alphaFunctionLut["EASE_OUT"]                   = AlphaFunctions::EaseOut;
117     alphaFunctionLut["EASE_IN_OUT"]                = AlphaFunctions::EaseInOut;
118     alphaFunctionLut["EASE_IN_SINE"]               = AlphaFunctions::EaseInSine;
119     alphaFunctionLut["EASE_OUT_SINE"]              = AlphaFunctions::EaseOutSine;
120     alphaFunctionLut["EASE_IN_OUT_SINE"]           = AlphaFunctions::EaseInOutSine;
121     alphaFunctionLut["EASE_IN_SINE_33"]            = AlphaFunctions::EaseInSine33;
122     alphaFunctionLut["EASE_OUT_SINE_33"]           = AlphaFunctions::EaseOutSine33;
123     alphaFunctionLut["EASE_IN_OUT_SINE_33"]        = AlphaFunctions::EaseInOutSine33;
124     alphaFunctionLut["EASE_IN_OUT_SINE_50"]        = AlphaFunctions::EaseInOutSine50;
125     alphaFunctionLut["EASE_IN_OUT_SINE_60"]        = AlphaFunctions::EaseInOutSine60;
126     alphaFunctionLut["EASE_IN_OUT_SINE_70"]        = AlphaFunctions::EaseInOutSine70;
127     alphaFunctionLut["EASE_IN_OUT_SINE_80"]        = AlphaFunctions::EaseInOutSine80;
128     alphaFunctionLut["EASE_IN_OUT_SINE_90"]        = AlphaFunctions::EaseInOutSine90;
129     alphaFunctionLut["DOUBLE_EASE_IN_OUT_SINE_60"] = AlphaFunctions::DoubleEaseInOutSine60;
130     alphaFunctionLut["EASE_OUT_QUINT_50"]          = AlphaFunctions::EaseOutQuint50;
131     alphaFunctionLut["EASE_OUT_QUINT_80"]          = AlphaFunctions::EaseOutQuint80;
132     alphaFunctionLut["BOUNCE"]                     = AlphaFunctions::Bounce;
133     alphaFunctionLut["BOUNCE_BACK"]                = AlphaFunctions::BounceBack;
134     alphaFunctionLut["EASE_IN_BACK"]               = AlphaFunctions::EaseInBack;
135     alphaFunctionLut["EASE_OUT_BACK"]              = AlphaFunctions::EaseOutBack;
136     alphaFunctionLut["EASE_IN_OUT_BACK"]           = AlphaFunctions::EaseInOutBack;
137     alphaFunctionLut["SIN"]                        = AlphaFunctions::Sin;
138     alphaFunctionLut["SIN2X"]                      = AlphaFunctions::Sin2x;
139   }
140
141   const AlphaFunctionLut::const_iterator iter( alphaFunctionLut.find( alphaFunction ) );
142
143   if( iter != alphaFunctionLut.end() )
144   {
145     return iter->second;
146   }
147   else
148   {
149     DALI_ASSERT_ALWAYS( iter != alphaFunctionLut.end() && "Unknown Anchor Constant" );
150     return Dali::AlphaFunctions::Default;
151   }
152 }
153
154 } // unnamed namespace
155
156
157 namespace Dali
158 {
159
160 namespace Toolkit
161 {
162
163 namespace Internal
164 {
165
166 Animation CreateAnimation( const TreeNode& child, const Replacement& constant, Dali::Actor searchRoot, Builder* const builder )
167 {
168   float durationSum = 0.f;
169
170   Dali::Actor searchActor = searchRoot ? searchRoot : Dali::Stage::GetCurrent().GetRootLayer();
171
172   Animation animation( Animation::New( 0.f ) );
173
174   // duration needs to be set before AnimateTo calls for correct operation when AnimateTo has no "time-period".
175   OptionalFloat duration = constant.IsFloat( IsChild(child, "duration" ) );
176
177   if( duration )
178   {
179     animation.SetDuration( *duration );
180   }
181
182   if( OptionalBoolean looping = constant.IsBoolean(  IsChild(child, "loop" ) ) )
183   {
184     animation.SetLooping( *looping );
185   }
186
187   if( OptionalString endAction = constant.IsString(  IsChild(child, "end-action" ) ) )
188   {
189     if("BAKE" == *endAction)
190     {
191       animation.SetEndAction( Animation::Bake );
192     }
193     else if("DISCARD" == *endAction)
194     {
195       animation.SetEndAction( Animation::Discard );
196     }
197     else if("BAKE_FINAL" == *endAction)
198     {
199       animation.SetEndAction( Animation::BakeFinal );
200     }
201   }
202
203   if( OptionalString endAction = constant.IsString(  IsChild(child, "disconnect-action" ) ) )
204   {
205     if("BAKE" == *endAction)
206     {
207       animation.SetDisconnectAction( Animation::Bake );
208     }
209     else if("DISCARD" == *endAction)
210     {
211       animation.SetDisconnectAction( Animation::Discard );
212     }
213     else if("BAKE_FINAL" == *endAction)
214     {
215       animation.SetDisconnectAction( Animation::BakeFinal );
216     }
217   }
218
219   OptionalChild propertiesNode = IsChild(child, "properties" );
220   if(propertiesNode)
221   {
222     const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
223     for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
224     {
225       const TreeNode::KeyNodePair& pKeyChild = *iter;
226
227       OptionalString actorName( constant.IsString( IsChild(pKeyChild.second, "actor" ) ) );
228       OptionalString property(  constant.IsString( IsChild(pKeyChild.second, "property" ) ) );
229       DALI_ASSERT_ALWAYS( actorName && "Animation must specify actor name" );
230
231       Handle targetHandle = searchActor.FindChildByName( *actorName );
232       DALI_ASSERT_ALWAYS( targetHandle && "Actor must exist for property" );
233
234       Property::Value propValue;
235       Property::Index propIndex = Property::INVALID_INDEX;
236       if( property )
237       {
238         propIndex = targetHandle.GetPropertyIndex( *property );
239
240         // if the property is not found from the (actor) handle, try to downcast it to renderable actor
241         // to allow animating shader uniforms
242         if( propIndex == Property::INVALID_INDEX )
243         {
244           RenderableActor renderable = RenderableActor::DownCast( targetHandle );
245           if( renderable )
246           {
247             // A limitation here is that its possible that between creation of animation
248             // and running it the ShaderEffect of the actor has been changed.
249             // However this is a unlikely use case especially when using scripts.
250             if( ShaderEffect effect = renderable.GetShaderEffect() )
251             {
252               propIndex = effect.GetPropertyIndex( *property );
253               if(propIndex != Property::INVALID_INDEX)
254               {
255                 targetHandle = effect;
256               }
257               else
258               {
259                 DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
260                 continue;
261               }
262             }
263           }
264           else
265           {
266             DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
267             continue;
268           }
269         }
270
271         if( propIndex == Property::INVALID_INDEX)
272         {
273           DALI_ASSERT_ALWAYS( propIndex != Property::INVALID_INDEX && "Animation must specify a valid property" );
274           continue;
275         }
276       }
277
278       // these are the defaults
279       AlphaFunction alphaFunction( AlphaFunctions::Default );
280       TimePeriod timePeriod( 0.f );
281
282       OptionalChild timeChild = IsChild( pKeyChild.second, "time-period" );
283
284       if( timeChild )
285       {
286         timePeriod = GetTimePeriod( *timeChild, constant );
287       }
288
289       durationSum = std::max( durationSum, timePeriod.delaySeconds + timePeriod.durationSeconds );
290
291       if( OptionalString alphaChild = constant.IsString( IsChild(pKeyChild.second, "alpha-function" ) ) )
292       {
293         alphaFunction = GetAlphaFunction( *alphaChild );
294       }
295
296       if( OptionalChild keyFrameChild = IsChild(pKeyChild.second, "key-frames") )
297       {
298         DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
299         Property prop = Property( targetHandle, propIndex );
300
301         KeyFrames keyframes = KeyFrames::New();
302
303         const TreeNode::ConstIterator endIter = (*keyFrameChild).CEnd();
304         for( TreeNode::ConstIterator iter = (*keyFrameChild).CBegin(); endIter != iter; ++iter )
305         {
306           const TreeNode::KeyNodePair& kfKeyChild = *iter;
307
308           OptionalFloat kfProgress = constant.IsFloat( IsChild(kfKeyChild.second, "progress" ) );
309           DALI_ASSERT_ALWAYS( kfProgress && "Key frame entry must have 'progress'" );
310
311           OptionalChild kfValue = IsChild( kfKeyChild.second, "value" );
312           DALI_ASSERT_ALWAYS( kfValue && "Key frame entry must have 'value'" );
313
314           try
315           {
316             propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *kfValue );
317           }
318           catch(...)
319           {
320             DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n",
321                               (*property).c_str(),
322                               PropertyTypes::GetName(prop.object.GetPropertyType(prop.propertyIndex)) );
323
324             throw;
325           }
326
327           AlphaFunction kfAlphaFunction( AlphaFunctions::Default );
328           if( OptionalString alphaFuncStr = constant.IsString( IsChild(pKeyChild.second, "alpha-function") ) )
329           {
330             kfAlphaFunction = GetAlphaFunction( *alphaFuncStr );
331           }
332
333           keyframes.Add( *kfProgress, propValue, kfAlphaFunction );
334         }
335
336         if( timeChild )
337         {
338           animation.AnimateBetween( prop, keyframes, alphaFunction, timePeriod );
339         }
340         else
341         {
342           animation.AnimateBetween( prop, keyframes, alphaFunction );
343         }
344       }
345       else if( OptionalString pathChild = IsString(pKeyChild.second, "path") )
346       {
347         //Get path
348         Path path = builder->GetPath(*pathChild);
349         if( path )
350         {
351           //Get forward vector if specified
352           Vector3 forward( 0.0f, 0.0f, 0.0f );
353           OptionalVector3 forwardProperty = constant.IsVector3( IsChild(pKeyChild.second, "forward" ) );
354           if( forwardProperty )
355           {
356             forward = *forwardProperty;
357           }
358
359           Actor actor = Actor::DownCast( targetHandle );
360           if( actor )
361           {
362             if( timeChild )
363             {
364               animation.Animate( actor, path, forward, alphaFunction, timePeriod );
365             }
366             else
367             {
368               animation.Animate( actor, path, forward, alphaFunction );
369             }
370
371           }
372         }
373         else
374         {
375           //Path not found
376           DALI_SCRIPT_WARNING( "Cannot find animation path '%s'\n", (*pathChild).c_str() );
377         }
378       }
379       else
380       {
381         DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
382
383         Property prop = Property( targetHandle, propIndex );
384         try
385         {
386           propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *IsChild(pKeyChild.second, "value") );
387         }
388         catch(...)
389         {
390           DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n", (*property).c_str(),
391                             PropertyTypes::GetName( prop.object.GetPropertyType(prop.propertyIndex) ) );
392
393           throw;
394         }
395
396         if( OptionalBoolean relative = constant.IsBoolean( IsChild(pKeyChild.second, "relative") ) )
397         {
398           if( timeChild )
399           {
400             animation.AnimateBy( prop, propValue, alphaFunction, timePeriod );
401           }
402           else
403           {
404             animation.AnimateBy( prop, propValue, alphaFunction );
405           }
406         }
407         else
408         {
409           if( timeChild )
410           {
411             animation.AnimateTo( prop, propValue, alphaFunction, timePeriod );
412           }
413           else
414           {
415             animation.AnimateTo( prop, propValue, alphaFunction );
416           }
417         }
418       }
419     }
420   }
421
422   if( !duration )
423   {
424     animation.SetDuration( durationSum );
425   }
426
427   return animation;
428 }
429
430 Animation CreateAnimation( const TreeNode& child, Builder* const builder )
431 {
432   Replacement replacement;
433   return CreateAnimation( child, replacement, Stage::GetCurrent().GetRootLayer(), builder );
434 }
435
436 } // namespace Internal
437
438 } // namespace Toolkit
439
440 } // namespace Dali
441