add drag&drop support in actor level
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / layouting / layout-transition-data-impl.cpp
1 /*
2  * Copyright (c) 2018 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 #include <dali/integration-api/debug.h>
18
19 #include <dali/public-api/animation/animation.h>
20 #include <dali/public-api/object/base-handle.h>
21 #include <dali/public-api/object/type-registry-helper.h>
22 #include <dali-toolkit/public-api/controls/control.h>
23 #include <dali/devel-api/object/handle-devel.h>
24 #include <dali-toolkit/devel-api/layouting/layout-item-impl.h>
25 #include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
26 #include <dali-toolkit/internal/layouting/layout-transition-data-impl.h>
27 #include <dali-toolkit/internal/layouting/layout-item-data-impl.h>
28
29 #include <dali/devel-api/scripting/enum-helper.h>
30
31 namespace
32 {
33 // Key tokens
34 const char* TOKEN_PROPERTY("property");
35 const char* TOKEN_INITIAL_VALUE("initialValue");
36 const char* TOKEN_TARGET_VALUE("targetValue");
37 const char* TOKEN_ANIMATOR("animator");
38 const char* TOKEN_TYPE("type");
39 const char* TOKEN_NAME("name");
40 const char* TOKEN_TIME_PERIOD("timePeriod");
41 const char* TOKEN_DURATION("duration");
42 const char* TOKEN_DELAY("delay");
43 const char* TOKEN_ALPHA_FUNCTION("alphaFunction");
44
45 DALI_ENUM_TO_STRING_TABLE_BEGIN( ALPHA_FUNCTION_BUILTIN )
46 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, LINEAR)
47 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, REVERSE)
48 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN)
49 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_OUT)
50 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN_OUT)
51 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN_SQUARE)
52 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_OUT_SQUARE)
53 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN_SINE)
54 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_OUT_SINE)
55 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN_OUT_SINE)
56 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_OUT_BACK)
57 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, BOUNCE)
58 DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, SIN)
59 DALI_ENUM_TO_STRING_TABLE_END( ALPHA_FUNCTION_BUILTIN )
60
61 }
62
63 namespace Dali
64 {
65 namespace Toolkit
66 {
67 namespace Internal
68 {
69
70 LayoutTransitionData::LayoutTransitionData()
71 {
72 }
73
74 LayoutTransitionData::~LayoutTransitionData()
75 {
76 }
77
78 LayoutTransitionDataPtr LayoutTransitionData::New()
79 {
80   LayoutTransitionDataPtr layoutAnimationData( new LayoutTransitionData() );
81   return layoutAnimationData;
82 }
83
84 LayoutTransitionData::PropertyAnimator::PropertyAnimator( )
85   : handle( Actor( ) )
86   , map()
87   , interpolation( Animation::Linear )
88 {
89 }
90
91 LayoutTransitionData::PropertyAnimator::PropertyAnimator( Actor actor, Property::Map map )
92   : handle( actor )
93   , map( map )
94   , interpolation( Animation::Linear )
95 {
96 }
97
98 LayoutTransitionData::PropertyAnimator::PropertyAnimator( Actor actor,  Property::Map map, Path path, Vector3 forward )
99   : handle( actor )
100   , map( map )
101   , interpolation( Animation::Linear )
102   , path( path )
103   , forward( forward )
104 {
105 }
106
107 LayoutTransitionData::PropertyAnimator::PropertyAnimator( Actor actor, Property::Map map, KeyFrames keyFrames, Animation::Interpolation interpolation  )
108   : handle( actor )
109   , map( map )
110   , keyFrames( keyFrames )
111   , interpolation( interpolation )
112 {
113 }
114
115 void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map )
116 {
117   mPropertyAnimators.push_back( PropertyAnimator( actor, map ) );
118 }
119
120 void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map, KeyFrames keyFrames, Animation::Interpolation interpolation )
121 {
122   mPropertyAnimators.push_back( PropertyAnimator( actor, map, keyFrames, interpolation ) );
123 }
124
125 void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map, Path path, Vector3 forward )
126 {
127   mPropertyAnimators.push_back( PropertyAnimator( actor, map, path, forward ) );
128 }
129
130 bool LayoutTransitionData::ConvertToLayoutAnimator( const Property::Map& animatorMap, const PropertyAnimator& propertyAnimator, LayoutDataAnimator& layoutDataAnimator )
131 {
132   bool valid = true;
133
134   for ( size_t animatorMapIdx = 0; animatorMapIdx < animatorMap.Count(); ++animatorMapIdx )
135   {
136     const KeyValuePair pair( animatorMap.GetKeyValue( animatorMapIdx ) );
137
138     Property::Index indexKey = Property::INVALID_INDEX;
139     if ( pair.first.type == Property::Key::STRING )
140     {
141       const std::string& key(pair.first.stringKey);
142       if( key == TOKEN_TYPE )
143       {
144         indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::TYPE;
145       }
146       else if( key == TOKEN_NAME )
147       {
148         indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::NAME;
149       }
150       else if( key == TOKEN_TIME_PERIOD )
151       {
152         indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::TIME_PERIOD;
153       }
154       else if( key == TOKEN_ALPHA_FUNCTION )
155       {
156         indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION;
157       }
158     }
159     else
160     {
161       indexKey = pair.first.indexKey;
162     }
163
164     const Property::Value& value( pair.second );
165
166     if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION )
167     {
168       if ( value.GetType() == Property::ARRAY )
169       {
170         valid = true;
171         Vector4 controlPoints;
172         Property::Array *array = value.GetArray();
173         if ( array && array->Count() >= 4 )
174         {
175           for ( size_t vecIdx = 0; vecIdx < 4; ++vecIdx )
176           {
177             Property::Value& v = array->GetElementAt( vecIdx );
178             if ( v.GetType() == Property::FLOAT )
179             {
180               controlPoints[vecIdx] = v.Get<float>();
181             }
182             else
183             {
184               valid = false;
185               break;
186             }
187           }
188         }
189         else
190         {
191           valid = false;
192         }
193
194         if ( valid )
195         {
196           Vector2 controlPoint1( controlPoints.x, controlPoints.y );
197           Vector2 controlPoint2( controlPoints.z, controlPoints.w );
198           layoutDataAnimator.alphaFunction = AlphaFunction( controlPoint1, controlPoint2 );
199         }
200         else
201         {
202           valid = false;
203         }
204       }
205       else if ( value.GetType() == Property::VECTOR4 )
206       {
207         Vector4 controlPoints = value.Get<Vector4>();
208         Vector2 controlPoint1( controlPoints.x, controlPoints.y );
209         Vector2 controlPoint2( controlPoints.z, controlPoints.w );
210         layoutDataAnimator.alphaFunction = AlphaFunction( controlPoint1, controlPoint2 );
211       }
212       else if ( value.GetType() == Property::STRING )
213       {
214         std::string alphaFunctionValue = value.Get<std::string>();
215
216         if ( alphaFunctionValue == "LINEAR" )
217         {
218           layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::LINEAR );
219         }
220         else if ( !alphaFunctionValue.compare( 0, 5, "EASE_" ) )
221         {
222           if ( alphaFunctionValue == "EASE_IN" )
223           {
224             layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN );
225           }
226           else if ( alphaFunctionValue == "EASE_OUT" )
227           {
228             layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_OUT );
229           }
230           else if ( !alphaFunctionValue.compare( 5, 3, "IN_" ) )
231           {
232             if ( !alphaFunctionValue.compare( 8, -1, "SQUARE" ) )
233             {
234               layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN_SQUARE );
235             }
236             else if ( !alphaFunctionValue.compare( 8, -1, "OUT" ) )
237             {
238               layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN_OUT );
239             }
240             else if ( !alphaFunctionValue.compare( 8, -1, "OUT_SINE" ) )
241             {
242               layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN_OUT_SINE );
243             }
244             else if ( !alphaFunctionValue.compare( 8, -1, "SINE" ) )
245             {
246               layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN_SINE );
247             }
248           }
249           else if ( !alphaFunctionValue.compare( 5, 4, "OUT_" ) )
250           {
251             if ( !alphaFunctionValue.compare( 9, -1, "SQUARE" ) )
252             {
253               layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_OUT_SQUARE );
254             }
255             else if ( !alphaFunctionValue.compare( 9, -1, "SINE" ) )
256             {
257               layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_OUT_SINE );
258             }
259             else if ( !alphaFunctionValue.compare( 9, -1, "BACK" ) )
260             {
261               layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_OUT_BACK );
262             }
263           }
264         }
265         else if ( alphaFunctionValue == "REVERSE" )
266         {
267           layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::REVERSE );
268         }
269         else if ( alphaFunctionValue == "BOUNCE" )
270         {
271           layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::BOUNCE );
272         }
273         else if ( alphaFunctionValue == "SIN" )
274         {
275           layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::SIN );
276         }
277         else
278         {
279           valid = false;
280         }
281       }
282       else
283       {
284         valid = false;
285       }
286     }
287     else if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::NAME )
288     {
289       if( value.GetType() == Property::STRING )
290       {
291         layoutDataAnimator.name = value.Get<std::string>();
292       }
293     }
294     else if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::TYPE )
295     {
296       if( value.GetType() == Property::STRING )
297       {
298         std::string animatorType = value.Get<std::string>();
299         if( animatorType == "ANIMATE_TO" )
300         {
301           layoutDataAnimator.animatorType = LayoutDataAnimator::AnimatorType::ANIMATE_TO;
302         }
303         else if( animatorType == "ANIMATE_BY" )
304         {
305           layoutDataAnimator.animatorType = LayoutDataAnimator::AnimatorType::ANIMATE_BY;
306         }
307         else if( animatorType == "ANIMATE_BETWEEN" )
308         {
309           layoutDataAnimator.animatorType = LayoutDataAnimator::AnimatorType::ANIMATE_BETWEEN;
310           layoutDataAnimator.keyFrames = propertyAnimator.keyFrames;
311         }
312         else if( animatorType == "ANIMATE_PATH" )
313         {
314           layoutDataAnimator.animatorType = LayoutDataAnimator::AnimatorType::ANIMATE_PATH;
315           layoutDataAnimator.path = propertyAnimator.path;
316           layoutDataAnimator.forward = propertyAnimator.forward;
317         }
318       }
319     }
320     else if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::TIME_PERIOD )
321     {
322       Property::Map timeMap = value.Get<Property::Map>();
323       for ( size_t timeMapIdx = 0; timeMapIdx < timeMap.Count(); ++timeMapIdx )
324       {
325         const KeyValuePair pair( timeMap.GetKeyValue( timeMapIdx ) );
326         indexKey = Property::INVALID_INDEX;
327
328         if ( pair.first.type == Property::Key::STRING)
329         {
330           const std::string& key( pair.first.stringKey );
331           if( key == TOKEN_DURATION )
332           {
333             indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::DURATION;
334           }
335           else if( key == TOKEN_DELAY )
336           {
337             indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::DELAY;
338           }
339         }
340         else
341         {
342           indexKey = pair.first.indexKey;
343         }
344
345         if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::DELAY )
346         {
347           layoutDataAnimator.timePeriod.delaySeconds = pair.second.Get<float>();
348         }
349         else if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::DURATION )
350         {
351           layoutDataAnimator.timePeriod.durationSeconds = pair.second.Get<float>();
352         }
353       }
354     }
355   }
356
357   return valid;
358 }
359
360 bool LayoutTransitionData::ConvertToLayoutDataElement( const PropertyAnimator& propertyAnimator, LayoutDataElement& layoutDataElement, LayoutData& layoutData )
361 {
362   const Property::Map& map = propertyAnimator.map;
363   bool propertyFound = false;
364
365   for( unsigned int mapIdx = 0; mapIdx < map.Count(); ++mapIdx )
366   {
367     const KeyValuePair pair( map.GetKeyValue( mapIdx ) );
368     const Property::Value& value( pair.second );
369     Property::Index indexKey = Property::INVALID_INDEX;
370
371     if ( pair.first.type == Property::Key::STRING )
372     {
373       const std::string& key( pair.first.stringKey );
374       if ( key == TOKEN_PROPERTY )
375       {
376         indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::PROPERTY;
377       }
378       else if( key == TOKEN_INITIAL_VALUE )
379       {
380         indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::INITIAL_VALUE;
381       }
382       else if( key == TOKEN_TARGET_VALUE )
383       {
384         indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::TARGET_VALUE;
385       }
386       else if( key == TOKEN_ANIMATOR )
387       {
388         indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::ANIMATOR;
389       }
390     }
391     else
392     {
393       indexKey = pair.first.indexKey;
394     }
395
396     if( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::PROPERTY )
397     {
398       if( value.GetType() == Property::STRING )
399       {
400         Actor actor = Actor::DownCast( layoutDataElement.handle );
401         layoutDataElement.propertyIndex = DevelHandle::GetPropertyIndex( actor, Property::Key( value.Get<std::string>() ) );
402       }
403       else
404       {
405         layoutDataElement.propertyIndex = value.Get<int>();
406       }
407       propertyFound = true;
408     }
409     else if( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::INITIAL_VALUE )
410     {
411       layoutDataElement.initialValue = value;
412     }
413     else if( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::TARGET_VALUE )
414     {
415       layoutDataElement.targetValue = value;
416     }
417     else if( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::ANIMATOR )
418     {
419       if( value.GetType() == Property::STRING )
420       {
421         std::string animatorName = value.Get<std::string>();
422         if ( animatorName.empty() )
423         {
424           layoutDataElement.animatorIndex = 0;
425         }
426         else
427         {
428           auto animator = std::find_if( layoutData.layoutAnimatorArray.begin(), layoutData.layoutAnimatorArray.end(), [&animatorName](const LayoutDataAnimator& iter) {
429             return (iter.name == animatorName); } );
430           if( animator != layoutData.layoutAnimatorArray.end() )
431           {
432             layoutDataElement.animatorIndex = std::distance( layoutData.layoutAnimatorArray.begin(), animator );
433           }
434         }
435       }
436       else if ( value.GetType() == Property::MAP )
437       {
438         Property::Map animatorMap = value.Get< Property::Map >();
439         LayoutDataAnimator layoutDataAnimator;
440         if( ConvertToLayoutAnimator( animatorMap, propertyAnimator, layoutDataAnimator ) )
441         {
442           layoutData.layoutAnimatorArray.push_back( layoutDataAnimator );
443           layoutDataElement.animatorIndex = layoutData.layoutAnimatorArray.size()-1;
444         }
445       }
446     }
447   }
448
449   return propertyFound;
450 }
451
452 void LayoutTransitionData::ConvertToLayoutDataElements( Actor owner, LayoutData& layoutData )
453 {
454   LayoutDataArray& layoutDataArray = layoutData.layoutDataArray;
455   // Add the children animators
456   for( const PropertyAnimator& iter : layoutData.childrenPropertyAnimators )
457   {
458     LayoutDataElement layoutDataElement;
459     layoutDataElement.handle = owner;
460     layoutDataElement.positionDataIndex = layoutData.layoutPositionDataArray.size() - 1;
461
462     if( ConvertToLayoutDataElement( iter, layoutDataElement, layoutData ) )
463     {
464       layoutDataArray.push_back( layoutDataElement );
465     }
466   }
467
468   // Add the transition animators
469   for( const PropertyAnimator& iter : mPropertyAnimators )
470   {
471     if( iter.handle == nullptr )
472     {
473       layoutData.childrenPropertyAnimators.push_back( iter );
474       continue;
475     }
476
477     LayoutDataElement layoutDataElement;
478     layoutDataElement.handle = iter.handle;
479     if( ConvertToLayoutDataElement( iter, layoutDataElement, layoutData ) )
480     {
481       layoutDataArray.push_back( layoutDataElement );
482     }
483   }
484 }
485
486 Dali::Toolkit::LayoutTransitionData::LayoutTransitionSignalType& LayoutTransitionData::FinishedSignal()
487 {
488   return mFinishedSignal;
489 }
490
491 void LayoutTransitionData::EmitSignalFinish( int layoutTransitionType )
492 {
493   if ( !mFinishedSignal.Empty() )
494   {
495     Dali::Toolkit::LayoutTransitionData handle( this );
496     mFinishedSignal.Emit( static_cast<Dali::Toolkit::LayoutTransitionData::LayoutTransitionType>(layoutTransitionType), handle );
497   }
498 }
499
500 } // namespace Internal
501 } // namespace Toolkit
502 } // namespace Dali