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