5ee926e1a1120ed6f16bd6c60223cf3e09f600df
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / transition / transition-base-impl.cpp
1 /*
2  * Copyright (c) 2021 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 // CLASS HEADER
19 #include <dali-toolkit/internal/transition/transition-base-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/public-api/controls/control-impl.h>
23
24 // EXTERNAL INCLUDES
25 #include <dali/devel-api/actors/actor-devel.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/public-api/animation/key-frames.h>
28 #include <dali/public-api/common/dali-common.h>
29 #include <dali/public-api/object/type-registry.h>
30
31 namespace Dali
32 {
33 namespace Toolkit
34 {
35 namespace Internal
36 {
37 namespace
38 {
39 static constexpr float OPACITY_TRANSPARENT = 0.0f;
40
41 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION(Dali::AlphaFunction::DEFAULT);
42
43 const Property::Map PROPERTY_MAP_INDEPENDENT_CONTROL{
44   {Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER},
45   {Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER},
46   {Dali::Actor::Property::POSITION_USES_ANCHOR_POINT, true},
47   {Dali::Actor::Property::INHERIT_POSITION, false},
48   {Dali::Actor::Property::INHERIT_ORIENTATION, false},
49   {Dali::Actor::Property::INHERIT_SCALE, false},
50   {Dali::Actor::Property::COLOR_MODE, Dali::ColorMode::USE_OWN_COLOR},
51 };
52
53 Property::Map GetOriginalProperties(Dali::Toolkit::Control control)
54 {
55   Property::Map propertyMap;
56   propertyMap.Insert(Dali::Actor::Property::ANCHOR_POINT, control[Dali::Actor::Property::ANCHOR_POINT]);
57   propertyMap.Insert(Dali::Actor::Property::PARENT_ORIGIN, control[Dali::Actor::Property::PARENT_ORIGIN]);
58   propertyMap.Insert(Dali::Actor::Property::POSITION_USES_ANCHOR_POINT, control[Dali::Actor::Property::POSITION_USES_ANCHOR_POINT]);
59   propertyMap.Insert(Dali::Actor::Property::INHERIT_POSITION, control[Dali::Actor::Property::INHERIT_POSITION]);
60   propertyMap.Insert(Dali::Actor::Property::INHERIT_ORIENTATION, control[Dali::Actor::Property::INHERIT_ORIENTATION]);
61   propertyMap.Insert(Dali::Actor::Property::INHERIT_SCALE, control[Dali::Actor::Property::INHERIT_SCALE]);
62   propertyMap.Insert(Dali::Actor::Property::COLOR_MODE, control[Dali::Actor::Property::COLOR_MODE]);
63   propertyMap.Insert(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, control[Dali::Actor::Property::HEIGHT_RESIZE_POLICY]);
64   propertyMap.Insert(Dali::Actor::Property::WIDTH_RESIZE_POLICY, control[Dali::Actor::Property::WIDTH_RESIZE_POLICY]);
65   propertyMap.Insert(Dali::Actor::Property::POSITION, control[Dali::Actor::Property::POSITION]);
66   propertyMap.Insert(Dali::Actor::Property::ORIENTATION, control[Dali::Actor::Property::ORIENTATION]);
67   propertyMap.Insert(Dali::Actor::Property::SCALE, control[Dali::Actor::Property::SCALE]);
68   propertyMap.Insert(Dali::Actor::Property::COLOR, control[Dali::Actor::Property::COLOR]);
69
70   return propertyMap;
71 }
72
73 /**
74  * @brief Computes and center position by using transform properties.
75  * @param[in] anchorPoint anchorPoint of an actor.
76  * @param[in] positionUsesAnchorPoint positionUsesAnchorPoint of an actor.
77  * @param[in] size size of an actor.
78  * @param[in] scale scale of an actor.
79  * @param[in] orientation orientation of an actor.
80  */
81 Vector3 CalculateCenterPosition(
82   const Vector3&    anchorPoint,
83   const bool        positionUsesAnchorPoint,
84   const Vector3&    size,
85   const Vector3&    scale,
86   const Quaternion& orientation)
87 {
88   Vector3       centerPosition;
89   const Vector3 half(0.5f, 0.5f, 0.5f);
90   const Vector3 topLeft(0.0f, 0.0f, 0.5f);
91   // Calculate the center-point by applying the scale and rotation on the anchor point.
92   centerPosition = (half - anchorPoint) * size * scale;
93   centerPosition *= orientation;
94
95   // If the position is ignoring the anchor-point, then remove the anchor-point shift from the position.
96   if(!positionUsesAnchorPoint)
97   {
98     centerPosition -= (topLeft - anchorPoint) * size;
99   }
100   return centerPosition;
101 }
102
103 } // anonymous namespace
104
105 TransitionBasePtr TransitionBase::New()
106 {
107   TransitionBasePtr transition = new TransitionBase();
108
109   // Second-phase construction
110   transition->Initialize();
111
112   return transition;
113 }
114
115 TransitionBase::TransitionBase()
116 : mAlphaFunction(DEFAULT_ALPHA_FUNCTION),
117   mTimePeriod(TimePeriod(0.0f)),
118   mTransitionWithChild(false),
119   mMoveTargetChildren(false),
120   mIsAppearingTransition(true),
121   mIsPairTransition(false)
122 {
123 }
124
125 void TransitionBase::Initialize()
126 {
127   RegisterObject();
128 }
129
130 void TransitionBase::SetTimePeriod(const Dali::TimePeriod& timePeriod)
131 {
132   if(timePeriod.durationSeconds < 0.0f)
133   {
134     DALI_LOG_WARNING("Duration should be greater than 0.0f.\n");
135   }
136   else
137   {
138     mTimePeriod.durationSeconds = timePeriod.durationSeconds;
139   }
140
141   if(timePeriod.delaySeconds < 0.0f)
142   {
143     DALI_LOG_WARNING("Delay should be greater than 0.0f.\n");
144     return;
145   }
146   else
147   {
148     mTimePeriod.delaySeconds = timePeriod.delaySeconds;
149   }
150 }
151
152 Dali::TimePeriod TransitionBase::GetTimePeriod() const
153 {
154   return mTimePeriod;
155 }
156
157 void TransitionBase::TransitionWithChild(bool transitionWithChild)
158 {
159   mTransitionWithChild = transitionWithChild;
160 }
161
162 void TransitionBase::PreProcess(Dali::Animation animation)
163 {
164   mAnimation           = animation;
165   // Retrieve original property map of mTarget to backup and to reset after transition is finished.
166   mOriginalPropertyMap = GetOriginalProperties(mTarget);
167   mMoveTargetChildren  = false;
168   if(!mTransitionWithChild && mTarget.GetChildCount() > 0)
169   {
170     mMoveTargetChildren = true;
171     CopyTarget();
172   }
173   GetImplementation(mTarget).SetTransparent(false);
174 }
175
176 void TransitionBase::Play()
177 {
178   if(!mTarget[Dali::Actor::Property::CONNECTED_TO_SCENE])
179   {
180     DALI_LOG_ERROR("The target is not added on the window\n");
181     return;
182   }
183
184   // Set world transform and color to the target control to make it independent of the parent control and its transition.
185   // The properties will be returned at the TransitionFinished() method.
186   Matrix     targetWorldTransform = GetWorldTransform(mTarget);
187   Vector3    targetPosition, targetScale;
188   Quaternion targetOrientation;
189   targetWorldTransform.GetTransformComponents(targetPosition, targetOrientation, targetScale);
190   Vector4 targetColor = GetWorldColor(mTarget);
191
192   mTarget.SetProperties(PROPERTY_MAP_INDEPENDENT_CONTROL);
193   mTarget[Dali::Actor::Property::POSITION]    = targetPosition;
194   mTarget[Dali::Actor::Property::SCALE]       = targetScale;
195   mTarget[Dali::Actor::Property::ORIENTATION] = targetOrientation;
196   mTarget[Dali::Actor::Property::COLOR]       = targetColor;
197
198   OnPlay();
199
200   SetAnimation();
201 }
202
203 void TransitionBase::SetAnimation()
204 {
205   if(!mAnimation)
206   {
207     DALI_LOG_ERROR("animation is not initialized\n");
208     return;
209   }
210
211   for(uint32_t i = 0; i < mStartPropertyMap.Count(); ++i)
212   {
213     Property::Value* finishValue = mFinishPropertyMap.Find(mStartPropertyMap.GetKeyAt(i).indexKey);
214     if(finishValue)
215     {
216       // If this transition is appearing transition, this property keeps start value during delay.
217       // If multiple transitions are applied to this Control and others run before this transition,
218       // this property should keep start value until this transition starts.
219       if(!IsPairTransition() && IsAppearingTransition() && mTimePeriod.delaySeconds > Dali::Math::MACHINE_EPSILON_10)
220       {
221         mTarget.SetProperty(mStartPropertyMap.GetKeyAt(i).indexKey, mStartPropertyMap.GetValue(i));
222       }
223       AnimateBetween(mTarget, mStartPropertyMap.GetKeyAt(i).indexKey, mStartPropertyMap.GetValue(i), *finishValue);
224     }
225   }
226 }
227
228 void TransitionBase::AnimateBetween(Dali::Toolkit::Control target, Property::Index index, Property::Value sourceValue, Property::Value destinationValue)
229 {
230   if(mAnimation)
231   {
232     // To make each property keep start value during delay time.
233     // When this transition is not Pair transition, it is not required.
234     // (For appearing transition, the mTarget control will not be shown during delay time,
235     //  For disapplearing transition, the property of mTarget control keeps current value during delay time)
236     if(IsPairTransition() && mTimePeriod.delaySeconds > Dali::Math::MACHINE_EPSILON_10)
237     {
238       Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
239       initialKeyframes.Add(0.0f, sourceValue);
240       initialKeyframes.Add(1.0f, sourceValue);
241       mAnimation.AnimateBetween(Property(target, index), initialKeyframes, TimePeriod(mTimePeriod.delaySeconds));
242     }
243     Dali::KeyFrames keyframes = Dali::KeyFrames::New();
244     keyframes.Add(0.0f, sourceValue);
245     keyframes.Add(1.0f, destinationValue);
246     mAnimation.AnimateBetween(Property(target, index), keyframes, mAlphaFunction, mTimePeriod);
247   }
248 }
249
250 void TransitionBase::CopyTarget()
251 {
252   mCopiedActor = Dali::Actor::New();
253   mTarget.GetParent().Add(mCopiedActor);
254
255   mCopiedActor[Dali::DevelActor::Property::SIBLING_ORDER] = static_cast<int32_t>(mTarget[Dali::DevelActor::Property::SIBLING_ORDER]) + 1;
256   while(mTarget.GetChildCount() > 0)
257   {
258     Dali::Actor child = mTarget.GetChildAt(0);
259     Dali::DevelActor::SwitchParent(child, mCopiedActor);
260   }
261
262   // Copy Size property to mCopiedActor because Size is not included mOriginalPropertyMap.
263   mCopiedActor[Dali::Actor::Property::SIZE] = mTarget.GetProperty<Vector3>(Dali::Actor::Property::SIZE);
264   mCopiedActor.SetProperties(mOriginalPropertyMap);
265 }
266
267 void TransitionBase::TransitionFinished()
268 {
269   OnFinished();
270
271   mTarget.SetProperties(mOriginalPropertyMap);
272   if(mMoveTargetChildren)
273   {
274     while(mCopiedActor.GetChildCount() > 0)
275     {
276       Dali::Actor child = mCopiedActor.GetChildAt(0);
277       Dali::DevelActor::SwitchParent(child, mTarget);
278     }
279     mCopiedActor.Unparent();
280     mCopiedActor.Reset();
281   }
282   mAnimation.Reset();
283 }
284
285 Matrix TransitionBase::GetWorldTransform(Dali::Actor actor)
286 {
287   enum InheritanceMode
288   {
289     DONT_INHERIT_TRANSFORM = 0,
290     INHERIT_POSITION       = 1,
291     INHERIT_SCALE          = 2,
292     INHERIT_ORIENTATION    = 4,
293     INHERIT_ALL            = INHERIT_POSITION | INHERIT_SCALE | INHERIT_ORIENTATION,
294   };
295
296   std::vector<Dali::Actor>     descentList;
297   std::vector<InheritanceMode> inheritanceModeList;
298   Dali::Actor                  currentActor = actor;
299   int                          inheritance  = 0;
300   do
301   {
302     inheritance = (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_ORIENTATION)) << 2) +
303                   (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_SCALE)) << 1) +
304                   static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_POSITION));
305     inheritanceModeList.push_back(static_cast<InheritanceMode>(inheritance));
306     descentList.push_back(currentActor);
307     currentActor = currentActor.GetParent();
308   } while(inheritance != DONT_INHERIT_TRANSFORM && currentActor);
309
310   Matrix  worldMatrix;
311   Vector3 localPosition;
312   for(unsigned int i(descentList.size() - 1); i < descentList.size(); --i)
313   {
314     Vector3    anchorPoint             = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::ANCHOR_POINT);
315     Vector3    parentOrigin            = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::PARENT_ORIGIN);
316     bool       positionUsesAnchorPoint = descentList[i].GetProperty<bool>(Dali::Actor::Property::POSITION_USES_ANCHOR_POINT);
317     Vector3    size                    = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
318     Vector3    actorPosition           = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::POSITION);
319     Quaternion localOrientation        = descentList[i].GetProperty<Quaternion>(Dali::Actor::Property::ORIENTATION);
320     Vector3    localScale              = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SCALE);
321
322     Vector3 centerPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
323     if(inheritanceModeList[i] != DONT_INHERIT_TRANSFORM && descentList[i].GetParent())
324     {
325       Matrix  localMatrix;
326       Vector3 parentSize = descentList[i + 1].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
327       if(inheritanceModeList[i] == INHERIT_ALL)
328       {
329         localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
330         localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
331
332         //Update the world matrix
333         Matrix tempMatrix;
334         Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
335         worldMatrix = tempMatrix;
336       }
337       else
338       {
339         Vector3    parentPosition, parentScale;
340         Quaternion parentOrientation;
341         worldMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
342
343         if((inheritanceModeList[i] & INHERIT_SCALE) == 0)
344         {
345           //Don't inherit scale
346           localScale /= parentScale;
347         }
348
349         if((inheritanceModeList[i] & INHERIT_ORIENTATION) == 0)
350         {
351           //Don't inherit orientation
352           parentOrientation.Invert();
353           localOrientation = parentOrientation * localOrientation;
354         }
355
356         if((inheritanceModeList[i] & INHERIT_POSITION) == 0)
357         {
358           localMatrix.SetTransformComponents(localScale, localOrientation, Vector3::ZERO);
359           Matrix tempMatrix;
360           Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
361           worldMatrix = tempMatrix;
362           worldMatrix.SetTranslation(actorPosition + centerPosition);
363         }
364         else
365         {
366           localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
367           localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
368           Matrix tempMatrix;
369           Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
370           worldMatrix = tempMatrix;
371         }
372       }
373     }
374     else
375     {
376       localPosition = actorPosition + centerPosition;
377       worldMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
378     }
379   }
380
381   return worldMatrix;
382 }
383
384 Vector4 TransitionBase::GetWorldColor(Dali::Actor actor)
385 {
386   std::vector<Dali::Actor>     descentList;
387   std::vector<Dali::ColorMode> inheritanceModeList;
388   Dali::Actor                  currentActor = actor;
389   Dali::ColorMode              inheritance  = Dali::ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA;
390   do
391   {
392     inheritance = currentActor.GetProperty<Dali::ColorMode>(Dali::Actor::Property::COLOR_MODE);
393     inheritanceModeList.push_back(inheritance);
394     descentList.push_back(currentActor);
395     currentActor = currentActor.GetParent();
396   } while(inheritance != Dali::ColorMode::USE_OWN_COLOR && currentActor);
397
398   Vector4 worldColor;
399   for(unsigned int i(descentList.size() - 1); i < descentList.size(); --i)
400   {
401     if(inheritanceModeList[i] == USE_OWN_COLOR || i == descentList.size() - 1)
402     {
403       worldColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
404     }
405     else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_ALPHA)
406     {
407       Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
408       worldColor       = Vector4(ownColor.r, ownColor.g, ownColor.b, ownColor.a * worldColor.a);
409     }
410     else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_COLOR)
411     {
412       Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
413       worldColor *= ownColor;
414     }
415   }
416
417   return worldColor;
418 }
419
420 } // namespace Internal
421
422 } // namespace Toolkit
423
424 } // namespace Dali