efl_animation: Add animation object
authorJaehyun Cho <jae_hyun.cho@samsung.com>
Thu, 24 Aug 2017 13:34:13 +0000 (22:34 +0900)
committerJaehyun Cho <jae_hyun.cho@samsung.com>
Thu, 12 Oct 2017 12:03:49 +0000 (21:03 +0900)
Efl.Animation.Object is a class which starts or cancels animation.
Efl.Animation.Object instance is created by Efl.Animation instance.
So Efl.Animation.Object instance contains animation properties from
Efl.animation instance.

Animation properties are set by using Efl.Animation instance and the
animation is started or cancelled by using Efl.Animation.Object.

src/Makefile_Evas.am
src/lib/evas/Evas_Common.h
src/lib/evas/Evas_Eo.h
src/lib/evas/Evas_Internal.h
src/lib/evas/canvas/efl_animation.c
src/lib/evas/canvas/efl_animation.eo
src/lib/evas/canvas/efl_animation_object.c [new file with mode: 0644]
src/lib/evas/canvas/efl_animation_object.eo [new file with mode: 0644]
src/lib/evas/canvas/efl_animation_object_private.h [new file with mode: 0644]
src/lib/evas/canvas/efl_animation_types.eot

index ce53ba0..d136f38 100644 (file)
@@ -45,6 +45,7 @@ evas_eolian_pub_files = \
        lib/evas/canvas/efl_input_focus.eo \
        lib/evas/canvas/efl_gfx_map.eo \
        lib/evas/canvas/efl_animation.eo \
+       lib/evas/canvas/efl_animation_object.eo \
        $(NULL)
 
 evas_eolian_legacy_files = \
@@ -123,7 +124,8 @@ lib/evas/canvas/evas_image_private.h \
 lib/evas/canvas/evas_polygon_private.h \
 lib/evas/canvas/efl_canvas_surface.h \
 lib/evas/common3d/primitives/primitive_common.h \
-lib/evas/canvas/efl_animation_private.h
+lib/evas/canvas/efl_animation_private.h \
+lib/evas/canvas/efl_animation_object_private.h
 
 # Linebreak
 
@@ -210,6 +212,7 @@ lib/evas/canvas/efl_input_pointer.c \
 lib/evas/canvas/efl_input_hold.c \
 lib/evas/canvas/efl_input_focus.c \
 lib/evas/canvas/efl_animation.c \
+lib/evas/canvas/efl_animation_object.c \
 $(NULL)
 
 EXTRA_DIST2 += \
index d97b856..eb346ae 100644 (file)
@@ -3337,6 +3337,18 @@ typedef Eo Efl_Animation;
 
 #endif
 
+#ifndef _EFL_ANIMATION_OBJECT_EO_CLASS_TYPE
+#define _EFL_ANIMATION_OBJECT_EO_CLASS_TYPE
+
+typedef Eo Efl_Animation_Object;
+
+#endif
+
+struct _Efl_Animation_Object_Running_Event_Info
+{
+   double progress;
+};
+
 /**
  * @}
  */
index b81a6ad..b7b376b 100644 (file)
@@ -56,6 +56,7 @@
 #include "canvas/efl_canvas_object.eo.h"
 
 #include "canvas/efl_animation.eo.h"
+#include "canvas/efl_animation_object.eo.h"
 
 #endif /* EFL_EO_API_SUPPORT */
 
index 5366d7a..c91defc 100644 (file)
@@ -83,6 +83,19 @@ EWAPI extern const Efl_Event_Description _EVAS_CANVAS_EVENT_VIEWPORT_RESIZE;
 #define EFL_CANVAS_GROUP_ADD_OPS(kls) EFL_OBJECT_OP_FUNC(efl_canvas_group_add, _##kls##_efl_canvas_group_group_add)
 #define EFL_CANVAS_GROUP_ADD_DEL_OPS(kls) EFL_CANVAS_GROUP_ADD_OPS(kls), EFL_CANVAS_GROUP_DEL_OPS(kls)
 
+/* Efl.Animation.Object */
+EOAPI void efl_animation_object_target_set(Eo *obj, Efl_Canvas_Object *target);
+EOAPI Efl_Canvas_Object *efl_animation_object_target_get(const Eo *obj);
+
+EOAPI void efl_animation_object_final_state_keep_set(Eo *obj, Eina_Bool state_keep);
+EOAPI Eina_Bool efl_animation_object_final_state_keep_get(const Eo *obj);
+
+EOAPI void efl_animation_object_duration_set(Eo *obj, double duration);
+EOAPI double efl_animation_object_duration_get(const Eo *obj);
+
+EWAPI extern const Efl_Event_Description _EFL_ANIMATION_OBJECT_EVENT_PRE_STARTED;
+#define EFL_ANIMATION_OBJECT_EVENT_PRE_STARTED (&(_EFL_ANIMATION_OBJECT_EVENT_PRE_STARTED))
+/* Efl.Animation.Object END */
 
 #ifdef __cplusplus
 }
index 92bef8f..df5d4e6 100644 (file)
@@ -77,6 +77,26 @@ _efl_animation_final_state_keep_get(Eo *eo_obj, Efl_Animation_Data *pd)
    return pd->keep_final_state;
 }
 
+EOLIAN static Efl_Animation_Object *
+_efl_animation_object_create(Eo *eo_obj, Efl_Animation_Data *pd EINA_UNUSED)
+{
+   EFL_ANIMATION_CHECK_OR_RETURN(eo_obj, NULL);
+
+   Efl_Animation_Object *anim_obj
+      = efl_add(EFL_ANIMATION_OBJECT_CLASS, NULL);
+
+   Efl_Canvas_Object *target = efl_animation_target_get(eo_obj);
+   efl_animation_object_target_set(anim_obj, target);
+
+   Eina_Bool state_keep = efl_animation_final_state_keep_get(eo_obj);
+   efl_animation_object_final_state_keep_set(anim_obj, state_keep);
+
+   double duration = efl_animation_duration_get(eo_obj);
+   efl_animation_object_duration_set(anim_obj, duration);
+
+   return anim_obj;
+}
+
 EOLIAN static Efl_Object *
 _efl_animation_efl_object_constructor(Eo *eo_obj,
                                       Efl_Animation_Data *pd)
index 67da77c..09c01b6 100644 (file)
@@ -35,6 +35,10 @@ class Efl.Animation (Efl.Object)
       is_deleted @protected {
          return: bool; [[$true if animation is deleted, $false otherwise.]]
       }
+      object_create {
+         [[Create object of the animation.]]
+         return: Efl.Animation.Object; [[Created object of the animation]]
+      }
    }
    implements {
       Efl.Object.constructor;
diff --git a/src/lib/evas/canvas/efl_animation_object.c b/src/lib/evas/canvas/efl_animation_object.c
new file mode 100644 (file)
index 0000000..6f134d8
--- /dev/null
@@ -0,0 +1,372 @@
+#include "efl_animation_object_private.h"
+
+EOLIAN static void
+_efl_animation_object_auto_del_set(Eo *eo_obj,
+                                   Efl_Animation_Object_Data *pd,
+                                   Eina_Bool auto_del)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   pd->auto_del = auto_del;
+}
+
+EOLIAN static Eina_Bool
+_efl_animation_object_auto_del_get(Eo *eo_obj,
+                                   Efl_Animation_Object_Data *pd)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj, EINA_TRUE);
+
+   return pd->auto_del;
+}
+
+static void
+_target_del_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+   Eo *eo_obj = data;
+
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+   EFL_ANIMATION_OBJECT_DATA_GET(eo_obj, pd);
+
+   pd->target = NULL;
+   efl_animation_object_cancel(eo_obj);
+}
+
+EOLIAN static void
+_efl_animation_object_target_set(Eo *eo_obj,
+                                 Efl_Animation_Object_Data *pd,
+                                 Efl_Canvas_Object *target)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   if (pd->target == target) return;
+
+   if (pd->target)
+     efl_event_callback_del(pd->target, EFL_EVENT_DEL, _target_del_cb, eo_obj);
+
+   efl_event_callback_add(target, EFL_EVENT_DEL, _target_del_cb, eo_obj);
+
+   pd->target = target;
+}
+
+EOLIAN static Efl_Canvas_Object *
+_efl_animation_object_target_get(Eo *eo_obj, Efl_Animation_Object_Data *pd)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN((Eo *)eo_obj, NULL);
+
+   return pd->target;
+}
+
+EOLIAN static void
+_efl_animation_object_duration_set(Eo *eo_obj,
+                                   Efl_Animation_Object_Data *pd,
+                                   double duration)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   pd->duration = duration;
+}
+
+EOLIAN static double
+_efl_animation_object_duration_get(Eo *eo_obj,
+                                   Efl_Animation_Object_Data *pd)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN((Eo *)eo_obj, 0.0);
+
+   return pd->duration;
+}
+
+EOLIAN static Eina_Bool
+_efl_animation_object_is_deleted(Eo *eo_obj,
+                                 Efl_Animation_Object_Data *pd)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(eo_obj, EINA_TRUE);
+
+   return pd->is_deleted;
+}
+
+EOLIAN static void
+_efl_animation_object_target_state_save(Eo *eo_obj,
+                                        Efl_Animation_Object_Data *pd)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   if (!pd->target || !pd->target_state) return;
+
+   Evas_Coord x, y, w, h;
+   evas_object_geometry_get(pd->target, &x, &y, &w, &h);
+
+   pd->target_state->x = x;
+   pd->target_state->y = y;
+   pd->target_state->w = w;
+   pd->target_state->h = h;
+
+   int r, g, b, a;
+   evas_object_color_get(pd->target, &r, &g, &b, &a);
+
+   pd->target_state->r = r;
+   pd->target_state->g = g;
+   pd->target_state->b = b;
+   pd->target_state->a = a;
+
+   Evas_Map *map = evas_map_dup(evas_object_map_get(pd->target));
+   pd->target_state->map = map;
+
+   Eina_Bool enable_map = evas_object_map_enable_get(pd->target);
+   pd->target_state->enable_map = enable_map;
+}
+
+EOLIAN static void
+_efl_animation_object_target_state_reset(Eo *eo_obj,
+                                         Efl_Animation_Object_Data *pd)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   if (!pd->target) return;
+
+   if (efl_gfx_map_has(pd->target))
+     efl_gfx_map_reset(pd->target);
+
+   if (!pd->target_state) return;
+
+   Evas_Coord x, y, w, h;
+   x = pd->target_state->x;
+   y = pd->target_state->y;
+   w = pd->target_state->w;
+   h = pd->target_state->h;
+
+   evas_object_resize(pd->target, w, h);
+   evas_object_move(pd->target, x, y);
+
+   int r, g, b, a;
+   r = pd->target_state->r;
+   g = pd->target_state->g;
+   b = pd->target_state->b;
+   a = pd->target_state->a;
+
+   evas_object_color_set(pd->target, r, g, b, a);
+
+   Evas_Map *map = pd->target_state->map;
+   evas_object_map_set(pd->target, map);
+
+   Eina_Bool enable_map = pd->target_state->enable_map;
+   evas_object_map_enable_set(pd->target, enable_map);
+}
+
+EOLIAN static void
+_efl_animation_object_final_state_keep_set(Eo *eo_obj,
+                                           Efl_Animation_Object_Data *pd,
+                                           Eina_Bool keep_final_state)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   if (pd->keep_final_state == keep_final_state) return;
+
+   pd->keep_final_state = !!keep_final_state;
+}
+
+EOLIAN static Eina_Bool
+_efl_animation_object_final_state_keep_get(Eo *eo_obj,
+                                           Efl_Animation_Object_Data *pd)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN((Eo *)eo_obj, EINA_FALSE);
+
+   return pd->keep_final_state;
+}
+
+static Eina_Bool
+_animator_cb(void *data)
+{
+   Eo *eo_obj = data;
+   EFL_ANIMATION_OBJECT_DATA_GET(eo_obj, pd);
+
+   if (pd->is_cancelled) goto end;
+
+   double elapsed_time, duration;
+
+   pd->time.current = ecore_loop_time_get();
+   elapsed_time = pd->time.current - pd->time.begin;
+   duration = pd->duration;
+   if (elapsed_time > duration)
+     elapsed_time = duration;
+
+   if (duration < 0.0) goto end;
+
+   if (duration == 0.0)
+     {
+        ecore_animator_del(pd->animator);
+        pd->animator = NULL;
+
+        pd->progress = 1.0;
+     }
+   else
+     pd->progress = elapsed_time / duration;
+
+   //Reset previous animation effect before applying animation effect
+   efl_animation_object_target_state_reset(eo_obj);
+
+   efl_animation_object_progress_set(eo_obj, pd->progress);
+
+   //Not end. Keep going.
+   if (elapsed_time < duration) return ECORE_CALLBACK_RENEW;
+
+end:
+   pd->animator = NULL;
+
+   //Reset the state of the target to the initial state
+   if (!pd->keep_final_state)
+     efl_animation_object_target_state_reset(eo_obj);
+
+   efl_event_callback_call(eo_obj, EFL_ANIMATION_OBJECT_EVENT_ENDED, NULL);
+
+   if (pd->auto_del) efl_del(eo_obj);
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_start(Eo *eo_obj, Efl_Animation_Object_Data *pd)
+{
+   if (pd->duration < 0.0) return;
+
+   //Save the current state of the target
+   efl_animation_object_target_state_save(eo_obj);
+
+   pd->is_cancelled = EINA_FALSE;
+
+   ecore_animator_del(pd->animator);
+   pd->animator = NULL;
+
+   pd->time.begin = ecore_loop_time_get();
+
+   //pre started event is supported within class only (protected event)
+   efl_event_callback_call(eo_obj, EFL_ANIMATION_OBJECT_EVENT_PRE_STARTED,
+                           NULL);
+   efl_event_callback_call(eo_obj, EFL_ANIMATION_OBJECT_EVENT_STARTED, NULL);
+
+   pd->animator = ecore_animator_add(_animator_cb, eo_obj);
+
+   _animator_cb(eo_obj);
+}
+
+EOLIAN static void
+_efl_animation_object_start(Eo *eo_obj,
+                            Efl_Animation_Object_Data *pd)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   _start(eo_obj, pd);
+}
+
+EOLIAN static void
+_efl_animation_object_cancel(Eo *eo_obj,
+                             Efl_Animation_Object_Data *pd)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   pd->is_cancelled = EINA_TRUE;
+
+   if (pd->animator)
+     {
+        ecore_animator_del(pd->animator);
+        pd->animator = NULL;
+
+        //Reset the state of the target to the initial state
+        if (!pd->keep_final_state)
+          efl_animation_object_target_state_reset(eo_obj);
+
+        efl_event_callback_call(eo_obj, EFL_ANIMATION_OBJECT_EVENT_ENDED, NULL);
+     }
+
+   if (pd->auto_del) efl_del(eo_obj);
+}
+
+EOLIAN static void
+_efl_animation_object_progress_set(Eo *eo_obj,
+                                   Efl_Animation_Object_Data *pd EINA_UNUSED,
+                                   double progress)
+{
+   EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(eo_obj);
+
+   if ((progress < 0.0) || (progress > 1.0)) return;
+
+   Efl_Animation_Object_Running_Event_Info event_info;
+   event_info.progress = progress;
+
+   efl_event_callback_call(eo_obj, EFL_ANIMATION_OBJECT_EVENT_RUNNING,
+                           &event_info);
+}
+
+EOLIAN static Efl_Object *
+_efl_animation_object_efl_object_constructor(Eo *eo_obj,
+                                             Efl_Animation_Object_Data *pd)
+{
+   eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
+
+   pd->time.begin = 0.0;
+   pd->time.current = 0.0;
+
+   pd->target = NULL;
+   pd->target_state = (Target_State *) calloc(1, sizeof(Target_State));
+
+   pd->progress = 0.0;
+
+   pd->duration = 0.0;
+
+   pd->auto_del = EINA_TRUE;
+   pd->is_deleted = EINA_FALSE;
+   pd->is_cancelled = EINA_FALSE;
+   pd->keep_final_state = EINA_FALSE;
+
+   return eo_obj;
+}
+
+EOLIAN static void
+_efl_animation_object_efl_object_destructor(Eo *eo_obj,
+                                            Efl_Animation_Object_Data *pd)
+{
+   pd->is_deleted = EINA_TRUE;
+
+   if (pd->animator)
+     {
+        ecore_animator_del(pd->animator);
+        pd->animator = NULL;
+
+        //Reset the state of the target to the initial state
+        if (!pd->keep_final_state)
+          efl_animation_object_target_state_reset(eo_obj);
+
+        efl_event_callback_call(eo_obj, EFL_ANIMATION_OBJECT_EVENT_ENDED, NULL);
+     }
+
+   if (pd->target)
+     efl_event_callback_del(pd->target, EFL_EVENT_DEL, _target_del_cb, eo_obj);
+
+   free(pd->target_state);
+   pd->target_state = NULL;
+
+   efl_destructor(efl_super(eo_obj, MY_CLASS));
+}
+
+/* Internal EO APIs */
+
+EOAPI EFL_VOID_FUNC_BODYV(efl_animation_object_target_set, EFL_FUNC_CALL(target), Efl_Canvas_Object *target);
+EOAPI EFL_FUNC_BODY_CONST(efl_animation_object_target_get, Efl_Canvas_Object *, NULL);
+
+EOAPI EFL_VOID_FUNC_BODYV(efl_animation_object_final_state_keep_set, EFL_FUNC_CALL(state_keep), Eina_Bool state_keep);
+EOAPI EFL_FUNC_BODY_CONST(efl_animation_object_final_state_keep_get, Eina_Bool, 0);
+
+EOAPI EFL_VOID_FUNC_BODYV(efl_animation_object_duration_set, EFL_FUNC_CALL(duration), double duration);
+EOAPI EFL_FUNC_BODY_CONST(efl_animation_object_duration_get, double, 0);
+
+#define EFL_ANIMATION_OBJECT_EXTRA_OPS \
+   EFL_OBJECT_OP_FUNC(efl_animation_object_target_set, _efl_animation_object_target_set), \
+   EFL_OBJECT_OP_FUNC(efl_animation_object_target_get, _efl_animation_object_target_get), \
+   EFL_OBJECT_OP_FUNC(efl_animation_object_final_state_keep_set, _efl_animation_object_final_state_keep_set), \
+   EFL_OBJECT_OP_FUNC(efl_animation_object_final_state_keep_get, _efl_animation_object_final_state_keep_get), \
+   EFL_OBJECT_OP_FUNC(efl_animation_object_duration_set, _efl_animation_object_duration_set), \
+   EFL_OBJECT_OP_FUNC(efl_animation_object_duration_get, _efl_animation_object_duration_get)
+
+EWAPI const Efl_Event_Description _EFL_ANIMATION_OBJECT_EVENT_PRE_STARTED =
+   EFL_EVENT_DESCRIPTION("pre_started");
+
+#include "efl_animation_object.eo.c"
diff --git a/src/lib/evas/canvas/efl_animation_object.eo b/src/lib/evas/canvas/efl_animation_object.eo
new file mode 100644 (file)
index 0000000..4780644
--- /dev/null
@@ -0,0 +1,48 @@
+import efl_animation_types;
+
+class Efl.Animation.Object (Efl.Object)
+{
+   [[Efl animation object class]]
+   data: Efl_Animation_Object_Data;
+   methods {
+      @property auto_del {
+         set {
+         }
+         get {
+         }
+         values {
+            auto_del: bool; [[$true to delete animation object automatically when animation is finished or animation is cancelled, $false otherwise.]]
+         }
+      }
+      start {
+         [[Start animation.]]
+      }
+      cancel {
+         [[Cancel animation.]]
+      }
+      is_deleted @protected {
+         return: bool; [[$true if animation object is deleted, $false otherwise.]]
+      }
+      target_state_save @protected {
+         [[Save the state of the target.]]
+      }
+      target_state_reset @protected {
+         [[Reset the state of the target to the previously saved state.]]
+      }
+      progress_set @protected {
+         [[Display the moment of animation according to the given progress.]]
+         params {
+            @in progress: double; [[The value between 0.0 and 1.0 which indicates the progress of the animation]]
+         }
+      }
+   }
+   implements {
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+   }
+   events {
+      started; [[Animation is started.]]
+      running; [[Animation is running.]]
+      ended; [[Animation is ended.]]
+   }
+}
diff --git a/src/lib/evas/canvas/efl_animation_object_private.h b/src/lib/evas/canvas/efl_animation_object_private.h
new file mode 100644 (file)
index 0000000..616d8c6
--- /dev/null
@@ -0,0 +1,53 @@
+#define EFL_ANIMATION_OBJECT_PROTECTED
+
+#include "evas_common_private.h"
+#include <Ecore.h>
+
+#define MY_CLASS EFL_ANIMATION_OBJECT_CLASS
+#define MY_CLASS_NAME efl_class_name_get(MY_CLASS)
+
+typedef struct _Target_State
+{
+   Evas_Coord x, y, w, h;
+   int        r, g, b, a;
+
+   Evas_Map  *map;
+   Eina_Bool  enable_map : 1;
+} Target_State;
+
+typedef struct _Efl_Animation_Object_Data
+{
+   Ecore_Animator    *animator;
+
+   struct {
+        double begin;
+        double current;
+     } time;
+
+   Efl_Canvas_Object *target;
+   Target_State      *target_state;
+
+   double             progress;
+
+   double             duration;
+
+   Eina_Bool          auto_del : 1;
+   Eina_Bool          is_deleted : 1;
+   Eina_Bool          is_cancelled : 1;
+   Eina_Bool          keep_final_state : 1;
+} Efl_Animation_Object_Data;
+
+#define EFL_ANIMATION_OBJECT_CHECK_OR_RETURN(anim_obj, ...) \
+   do { \
+      if (!anim_obj) { \
+         CRI("Efl_Animation_Object " # anim_obj " is NULL!"); \
+         return __VA_ARGS__; \
+      } \
+      if (efl_animation_object_is_deleted(anim_obj)) { \
+         ERR("Efl_Animation_Object " # anim_obj " has already been deleted!"); \
+         return __VA_ARGS__; \
+      } \
+   } while (0)
+
+#define EFL_ANIMATION_OBJECT_DATA_GET(o, pd) \
+   Efl_Animation_Object_Data *pd = efl_data_scope_get(o, EFL_ANIMATION_OBJECT_CLASS)
index f9047e3..3913db4 100644 (file)
@@ -1,2 +1,4 @@
 // ----------------------------------------------------------------------------
 // All the below types are for Efl Animation
+
+struct Efl.Animation.Object.Running_Event_Info; [[Information of running event]]