DALi Version 2.1.5
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / transition / transition-set-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-set-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/adaptor-framework/adaptor.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/object/type-registry.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/transition/transition-lifecycle-controller.h>
28
29 namespace Dali
30 {
31 namespace Toolkit
32 {
33 namespace Internal
34 {
35 namespace
36 {
37 // Signals
38 static constexpr std::string_view SIGNAL_FINISHED = "finished";
39
40 static constexpr float OPACITY_TRANSPARENT = 0.0f;
41
42 float CustomAlphaFunction(float progress)
43 {
44   return (progress >= 1.0f) ? 1.0f : 0.0f;
45 }
46
47 BaseHandle Create()
48 {
49   return Dali::Toolkit::TransitionSet::New();
50 }
51
52 TypeRegistration mType(typeid(Dali::Toolkit::TransitionSet), typeid(Dali::BaseHandle), Create);
53
54 SignalConnectorType signalConnector1(mType, std::string(SIGNAL_FINISHED), &TransitionSet::DoConnectSignal);
55
56 } // anonymous namespace
57
58 TransitionSetPtr TransitionSet::New()
59 {
60   TransitionSetPtr transitionSet = new TransitionSet();
61
62   return transitionSet;
63 }
64
65 TransitionSet::TransitionSet()
66 {
67 }
68
69 TransitionSet::~TransitionSet()
70 {
71   mTransitions.clear();
72 }
73
74 void TransitionSet::AddTransition(TransitionBasePtr transition)
75 {
76   mTransitions.push_back(transition);
77 }
78
79 TransitionBase* TransitionSet::GetTransitionAt(uint32_t index) const
80 {
81   TransitionBase* result(nullptr);
82   if(index < GetTransitionCount())
83   {
84     result = mTransitions[index].Get();
85   }
86   else
87   {
88     DALI_LOG_ERROR("Error: Invalid index to TransitionSet::GetTransitionAt\n");
89   }
90
91   return result;
92 }
93
94 uint32_t TransitionSet::GetTransitionCount() const
95 {
96   return mTransitions.size();
97 }
98
99 void TransitionSet::Play()
100 {
101   Adaptor::Get().RegisterProcessor(*this, true);
102   Adaptor::Get().RegisterProcessor(*this, false);
103   TransitionLifecycleController::GetInstance().AddTransitions(Dali::Toolkit::TransitionSet(this));
104 }
105
106 void TransitionSet::TransitionPreProcess()
107 {
108   float lastDuration = 0.0f;
109   for(auto&& transition : mTransitions)
110   {
111     TimePeriod timePeriod = transition->GetTimePeriod();
112     if(lastDuration <= timePeriod.durationSeconds + timePeriod.delaySeconds)
113     {
114       lastDuration = timePeriod.durationSeconds + timePeriod.delaySeconds;
115     }
116   }
117   mAnimation = Dali::Animation::New(lastDuration);
118
119   for(auto&& transition : mTransitions)
120   {
121     transition->PreProcess(mAnimation);
122   }
123 }
124
125 void TransitionSet::TransitionStart()
126 {
127   std::vector<std::pair<Dali::Actor, float>> minimumDelays;
128   for(auto&& transition : mTransitions)
129   {
130     transition->Play();
131
132     // If target Control has appearing transition, the target will not be rendered during delay.
133     // And if the Control has multiple transitions, the target will not be rendered during minimum delay of the transitions.
134     // Here we can find minimum delay of each target.
135     if(!transition->IsPairTransition() && transition->IsAppearingTransition())
136     {
137       bool found = false;
138       for(uint32_t index = 0; index < minimumDelays.size(); ++index)
139       {
140         if(minimumDelays[index].first == transition->GetTarget())
141         {
142           minimumDelays[index].second = std::min(minimumDelays[index].second, transition->GetTimePeriod().delaySeconds);
143           found = true;
144           break;
145         }
146       }
147       if(!found)
148       {
149         minimumDelays.push_back(std::pair<Dali::Actor, float>(transition->GetTarget(), transition->GetTimePeriod().delaySeconds));
150       }
151     }
152   }
153
154   // If the target has delay that is larger than 0, hide the target during minimum delay.
155   // The custom alpha function make the target hide just during delay.
156   for(auto&& delay : minimumDelays)
157   {
158     if(delay.second > Dali::Math::MACHINE_EPSILON_10)
159     {
160       Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
161       initialKeyframes.Add(0.0f, OPACITY_TRANSPARENT);
162       initialKeyframes.Add(1.0f, delay.first.GetProperty<float>(Dali::Actor::Property::OPACITY));
163
164       AlphaFunction alpha(&CustomAlphaFunction);
165       mAnimation.AnimateBetween(Property(delay.first, Dali::Actor::Property::OPACITY), initialKeyframes, alpha, TimePeriod(delay.second));
166     }
167   }
168
169   mAnimation.FinishedSignal().Connect(this, &TransitionSet::TransitionFinished);
170   mAnimation.Play();
171 }
172
173 void TransitionSet::TransitionFinished(Dali::Animation& source)
174 {
175   // Call TransitionFinished() in reverse order.
176   // This let the first copied original properties will be return again at the final.
177   std::vector<TransitionBasePtr>::reverse_iterator riter;
178   for(riter = mTransitions.rbegin(); riter != mTransitions.rend(); riter++)
179   {
180     (*riter)->TransitionFinished();
181   }
182
183   EmitFinishedSignal();
184 }
185
186 Dali::Toolkit::TransitionSet::TransitionSetSignalType& TransitionSet::FinishedSignal()
187 {
188   return mFinishedSignal;
189 }
190
191 void TransitionSet::EmitFinishedSignal()
192 {
193   if(!mFinishedSignal.Empty())
194   {
195     Dali::Toolkit::TransitionSet handle(this);
196     mFinishedSignal.Emit(handle);
197   }
198 }
199
200 bool TransitionSet::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
201 {
202   bool           connected(false);
203   TransitionSet* transitionSet = static_cast<TransitionSet*>(object); // TypeRegistry guarantees that this is the correct type.
204
205   if(SIGNAL_FINISHED == signalName)
206   {
207     transitionSet->FinishedSignal().Connect(tracker, functor);
208     connected = true;
209   }
210
211   return connected;
212 }
213
214 void TransitionSet::Process(bool postProcessor)
215 {
216   if(!postProcessor)
217   {
218     TransitionPreProcess();
219   }
220   else
221   {
222     TransitionStart();
223   }
224   Adaptor::Get().UnregisterProcessor(*this, postProcessor);
225 }
226
227 } // namespace Internal
228
229 } // namespace Toolkit
230
231 } // namespace Dali