Use OrderedSet so remove useless iteration for some singletone
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / animation-playlist.cpp
1 /*
2  * Copyright (c) 2023 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/internal/event/animation/animation-playlist.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/internal/event/animation/animation-impl.h>
24 #include <dali/public-api/common/vector-wrapper.h>
25
26 namespace Dali
27 {
28 namespace Internal
29 {
30 AnimationPlaylist* AnimationPlaylist::New()
31 {
32   return new AnimationPlaylist();
33 }
34
35 AnimationPlaylist::AnimationPlaylist() = default;
36
37 AnimationPlaylist::~AnimationPlaylist() = default;
38
39 void AnimationPlaylist::AnimationCreated(Animation& animation)
40 {
41   mAnimations.PushBack(&animation);
42 }
43
44 void AnimationPlaylist::AnimationDestroyed(Animation& animation)
45 {
46   auto iter = mAnimations.Find(&animation);
47   DALI_ASSERT_ALWAYS(iter != mAnimations.End() && "Animation not found");
48
49   mAnimations.Erase(iter);
50 }
51
52 void AnimationPlaylist::OnPlay(Animation& animation)
53 {
54   Dali::Animation handle = Dali::Animation(&animation);
55   auto            iter   = mPlaylist.lower_bound(handle);
56   if(iter != mPlaylist.end() && (*iter).first == handle)
57   {
58     // Just increase reference count.
59     ++(iter->second);
60   }
61   else
62   {
63     mPlaylist.insert(iter, {handle, 1u});
64   }
65 }
66
67 void AnimationPlaylist::OnClear(Animation& animation)
68 {
69   Dali::Animation handle = Dali::Animation(&animation);
70   auto            iter   = mPlaylist.find(handle);
71
72   // Animation might be removed when NotifyCompleted called.
73   if(DALI_LIKELY(iter != mPlaylist.end()))
74   {
75     // Just decrease reference count. But if reference count is zero, remove it.
76     if(--(iter->second) == 0u)
77     {
78       mPlaylist.erase(iter);
79     }
80   }
81 }
82
83 void AnimationPlaylist::NotifyCompleted()
84 {
85   std::vector<Dali::Animation> finishedAnimations;
86
87   // Since animations can be unreferenced during the signal emissions, iterators into animationPointers may be invalidated.
88   // First copy and reference the finished animations, then emit signals
89   for(auto* animation : mAnimations)
90   {
91     if(animation->HasFinished())
92     {
93       Dali::Animation handle = Dali::Animation(animation);
94       finishedAnimations.push_back(handle);
95
96       // The animation may be present in mPlaylist - remove if necessary
97       // Note that the animation "Finish" signal is emitted after Stop() has been called
98       OnClear(*animation);
99     }
100   }
101
102   // Now it's safe to emit the signals
103   for(auto iter = finishedAnimations.begin(); iter != finishedAnimations.end(); ++iter)
104   {
105     Dali::Animation& handle = *iter;
106
107     GetImplementation(handle).EmitSignalFinish();
108   }
109 }
110
111 void AnimationPlaylist::NotifyProgressReached(const SceneGraph::Animation* sceneGraphAnimation)
112 {
113   std::vector<Dali::Animation> notifyProgressAnimations; // Will own animations until all emits have been done
114
115   for(auto* animation : mAnimations)
116   {
117     if((animation->GetSceneObject()) == sceneGraphAnimation)
118     {
119       // Store handles to animations that need signals emitted in the case of an animation being cleared in-between emits
120       notifyProgressAnimations.push_back(Dali::Animation(animation));
121     }
122   }
123
124   for(std::vector<Dali::Animation>::iterator iter = notifyProgressAnimations.begin(); iter != notifyProgressAnimations.end(); ++iter)
125   {
126     Dali::Animation& handle = *iter;
127
128     GetImplementation(handle).EmitSignalProgressReached();
129   }
130 }
131
132 uint32_t AnimationPlaylist::GetAnimationCount()
133 {
134   return mAnimations.Count();
135 }
136
137 Dali::Animation AnimationPlaylist::GetAnimationAt(uint32_t index)
138 {
139   if(index >= mAnimations.Count())
140   {
141     DALI_LOG_ERROR("Animation index is out of bounds.\n");
142     return Dali::Animation();
143   }
144
145   // This will spend a lot of time. But GetAnimationAt API will be called very rarely.
146   Animation* ret = nullptr;
147   for(auto iter : mAnimations)
148   {
149     if(index == 0u)
150     {
151       ret = iter;
152       break;
153     }
154     --index;
155   }
156   DALI_ASSERT_DEBUG(ret != nullptr);
157   return Dali::Animation(ret);
158 }
159
160 } // namespace Internal
161
162 } // namespace Dali