summaryrefslogtreecommitdiff
path: root/src/lib/evas/canvas/efl_animation_object_group_parallel.c
blob: 7e23b73877c7059449f925a20b849c8a51818792 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#include "efl_animation_object_group_parallel_private.h"

/* Add member object data and append the data to the member object data list.
 * The member object data contains the repeated count of the member object.
 */
static void
_member_anim_obj_data_add(Efl_Animation_Object_Group_Parallel_Data *pd,
                          Efl_Animation_Object *anim_obj,
                          int repeated_count)
{
   Member_Object_Data *member_anim_obj_data =
      calloc(1, sizeof(Member_Object_Data));

   if (!member_anim_obj_data) return;

   member_anim_obj_data->anim_obj = anim_obj;
   member_anim_obj_data->repeated_count = repeated_count;

   pd->member_anim_obj_data_list =
      eina_list_append(pd->member_anim_obj_data_list, member_anim_obj_data);
}

/* Find the member object data which contains the repeated count of the member
 * object. */
static Member_Object_Data *
_member_anim_obj_data_find(Efl_Animation_Object_Group_Parallel_Data *pd,
                           Efl_Animation_Object *anim_obj)
{
   Eina_List *l;
   Member_Object_Data *member_anim_obj_data = NULL;
   EINA_LIST_FOREACH(pd->member_anim_obj_data_list, l, member_anim_obj_data)
     {
        if (member_anim_obj_data->anim_obj == anim_obj)
          break;
     }

   return member_anim_obj_data;
}

/* Delete member object data and remove the data from the member object data
 * list.
 * The member object data contains the repeated count of the member object.
 */
static void
_member_anim_obj_data_del(Efl_Animation_Object_Group_Parallel_Data *pd,
                          Efl_Animation_Object *anim_obj)
{
   Member_Object_Data *member_anim_obj_data = _member_anim_obj_data_find(pd, anim_obj);
   if (member_anim_obj_data)
     {
        pd->member_anim_obj_data_list =
           eina_list_remove(pd->member_anim_obj_data_list, member_anim_obj_data);
        free(member_anim_obj_data);
     }
}

EOLIAN static void
_efl_animation_object_group_parallel_efl_animation_object_group_object_add(Eo *eo_obj,
                                                                           Efl_Animation_Object_Group_Parallel_Data *pd,
                                                                           Efl_Animation_Object *anim_obj)
{
   EFL_ANIMATION_OBJECT_GROUP_PARALLEL_CHECK_OR_RETURN(eo_obj);

   if (!anim_obj) return;

   efl_animation_object_group_object_add(efl_super(eo_obj, MY_CLASS), anim_obj);

   /* Add member object data and append the data to the member object data
    * list. */
   _member_anim_obj_data_add(pd, anim_obj, 0);

   /* Total duration is calculated in
    * efl_animation_object_total_duration_get() based on the current group
    * animation object list.
    * Therefore, the calculated total duration should be set to update total
    * duration. */
   double total_duration = efl_animation_object_total_duration_get(eo_obj);
   efl_animation_object_total_duration_set(eo_obj, total_duration);
}

EOLIAN static void
_efl_animation_object_group_parallel_efl_animation_object_group_object_del(Eo *eo_obj,
                                                                           Efl_Animation_Object_Group_Parallel_Data *pd EINA_UNUSED,
                                                                           Efl_Animation_Object *anim_obj)
{
   EFL_ANIMATION_OBJECT_GROUP_PARALLEL_CHECK_OR_RETURN(eo_obj);

   if (!anim_obj) return;

   efl_animation_object_group_object_del(efl_super(eo_obj, MY_CLASS), anim_obj);

   /* Delete member object data and remove the data from the member object
    * data list. */
   _member_anim_obj_data_del(pd, anim_obj);

   /* Total duration is calculated in
    * efl_animation_object_total_duration_get() based on the current group
    * animation object list.
    * Therefore, the calculated total duration should be set to update total
    * duration. */
   double total_duration = efl_animation_object_total_duration_get(eo_obj);
   efl_animation_object_total_duration_set(eo_obj, total_duration);
}

EOLIAN static double
_efl_animation_object_group_parallel_efl_animation_object_total_duration_get(Eo *eo_obj,
                                                                             Efl_Animation_Object_Group_Parallel_Data *pd EINA_UNUSED)
{
   EFL_ANIMATION_OBJECT_GROUP_PARALLEL_CHECK_OR_RETURN(eo_obj, 0.0);

   Eina_List *anim_objs = efl_animation_object_group_objects_get(eo_obj);
   if (!anim_objs) return 0.0;

   double total_duration = 0.0;
   Eina_List *l;
   Efl_Animation *anim_obj;
   EINA_LIST_FOREACH(anim_objs, l, anim_obj)
     {
        double child_total_duration =
           efl_animation_object_total_duration_get(anim_obj);

        int child_repeat_count =
           efl_animation_object_repeat_count_get(anim_obj);
        if (child_repeat_count > 0)
          child_total_duration *= (child_repeat_count + 1);

        if (child_total_duration > total_duration)
          total_duration = child_total_duration;
     }
   return total_duration;
}

//Set how many times the given object has been repeated.
static void
_repeated_count_set(Efl_Animation_Object_Group_Parallel_Data *pd,
                    Efl_Animation_Object *anim_obj,
                    int repeated_count)
{

   Member_Object_Data *member_anim_obj_data =
      _member_anim_obj_data_find(pd, anim_obj);
   if (!member_anim_obj_data) return;

   member_anim_obj_data->repeated_count = repeated_count;
}

//Get how many times the given object has been repeated.
static int
_repeated_count_get(Efl_Animation_Object_Group_Parallel_Data *pd,
                    Efl_Animation_Object *anim_obj)
{
   Member_Object_Data *member_anim_obj_data =
      _member_anim_obj_data_find(pd, anim_obj);
   if (!member_anim_obj_data) return 0;

   return member_anim_obj_data->repeated_count;
}

EOLIAN static void
_efl_animation_object_group_parallel_efl_animation_object_progress_set(Eo *eo_obj,
                                                                       Efl_Animation_Object_Group_Parallel_Data *pd,
                                                                       double progress)
{
   if ((progress < 0.0) || (progress > 1.0)) return;

   Eina_List *anim_objs = efl_animation_object_group_objects_get(eo_obj);
   if (!anim_objs) return;

   double group_total_duration =
      efl_animation_object_total_duration_get(eo_obj);

   double elapsed_time = progress * group_total_duration;

   Eina_List *l;
   Efl_Animation_Object *anim_obj;
   EINA_LIST_FOREACH(anim_objs, l, anim_obj)
     {
        double total_duration =
           efl_animation_object_total_duration_get(anim_obj);
        double anim_obj_progress;

        if (total_duration == 0.0)
          anim_obj_progress = 1.0;
        else
          {
             //If object is repeated, then recalculate progress.
             int repeated_count = _repeated_count_get(pd, anim_obj);
             if (repeated_count > 0)
               anim_obj_progress = (elapsed_time - (total_duration * repeated_count)) / total_duration;
             else
               anim_obj_progress = elapsed_time / total_duration;

             if (anim_obj_progress > 1.0)
               anim_obj_progress = 1.0;

             //Animation has been finished.
             if (anim_obj_progress == 1.0)
               {
                  /* If object is finished and it should be repeated, then
                   * increate the repeated count to recalculate progress. */
                  int repeat_count =
                     efl_animation_object_repeat_count_get(anim_obj);
                  if (repeat_count > 0)
                    {
                       int repeated_count = _repeated_count_get(pd, anim_obj);
                       if (repeated_count < repeat_count)
                         {
                            repeated_count++;
                            _repeated_count_set(pd, anim_obj, repeated_count);
                         }
                    }
               }
          }

        efl_animation_object_progress_set(anim_obj, anim_obj_progress);
     }

   efl_animation_object_progress_set(efl_super(eo_obj, MY_CLASS), progress);
}

/* Internal EO APIs */

#define EFL_ANIMATION_OBJECT_GROUP_PARALLEL_EXTRA_OPS \
   EFL_OBJECT_OP_FUNC(efl_animation_object_group_object_add, _efl_animation_object_group_parallel_efl_animation_object_group_object_add), \
   EFL_OBJECT_OP_FUNC(efl_animation_object_group_object_del, _efl_animation_object_group_parallel_efl_animation_object_group_object_del), \
   EFL_OBJECT_OP_FUNC(efl_animation_object_total_duration_get, _efl_animation_object_group_parallel_efl_animation_object_total_duration_get)

#include "efl_animation_object_group_parallel.eo.c"