summaryrefslogtreecommitdiff
path: root/src/lib/evas/canvas/efl_animation_object_group_parallel.c
blob: 3c9d928d7b66f30b2a0bc8fd4bafb8e74ab85610 (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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#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)
{
   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);
}

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)
{
   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);
}

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)
{
   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);

        double start_delay = efl_animation_object_start_delay_get(anim_obj);
        if (start_delay > 0.0)
          child_total_duration += start_delay;

        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 start_delay = efl_animation_object_start_delay_get(anim_obj);
        double anim_obj_progress;

        Eina_Bool start_repeat = EINA_FALSE;

        if (total_duration == 0.0)
          anim_obj_progress = 1.0;
        else
          {
             double elapsed_time_without_delay;

             //If object is repeated, then recalculate progress.
             int repeated_count = _repeated_count_get(pd, anim_obj);
             if (repeated_count > 0)
               elapsed_time_without_delay =
                  (elapsed_time - ((total_duration + start_delay) * repeated_count)) - start_delay;
             else
               elapsed_time_without_delay = elapsed_time - start_delay;

             //Object should not start to wait for start delay time.
             if (elapsed_time_without_delay < 0.0) continue;

             anim_obj_progress = elapsed_time_without_delay / 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)
                    {
                       repeated_count = _repeated_count_get(pd, anim_obj);
                       if (repeated_count < repeat_count)
                         {
                            repeated_count++;
                            _repeated_count_set(pd, anim_obj, repeated_count);

                            start_repeat = EINA_TRUE;
                         }
                    }
               }
          }

        /* If object is repeated with reverse mode, then the progress value
         * should be modified as (1.0 - progress). */
        Efl_Animation_Object_Repeat_Mode repeat_mode
           = efl_animation_object_repeat_mode_get(anim_obj);
        if (repeat_mode == EFL_ANIMATION_OBJECT_REPEAT_MODE_REVERSE)
          {
             int repeated_count = _repeated_count_get(pd, anim_obj);
             if (repeated_count > 0)
               {
                  if ((((repeated_count % 2) == 1) && (!start_repeat)) ||
                      (((repeated_count % 2) == 0) && (start_repeat)))
                    anim_obj_progress = 1.0 - anim_obj_progress;
               }
          }

        //Apply interpolator
        Efl_Interpolator *group_interp =
           efl_animation_object_interpolator_get(eo_obj);

        /* If group interpolator exists, then the group interpolator has been
         * already applied. So it is not needed to apply interpolator again. */
        if (!group_interp)
          {
             Efl_Interpolator *interpolator =
                efl_animation_object_interpolator_get(anim_obj);
             if (interpolator)
               {
                  anim_obj_progress =
                     efl_interpolator_interpolate(interpolator,
                                                  anim_obj_progress);
               }
          }

        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"