Add a new widget - elm_animation_view. 62/191662/14
authorHermet Park <hermetpark@gmail.com>
Mon, 22 Oct 2018 04:23:20 +0000 (13:23 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Mon, 29 Apr 2019 07:19:51 +0000 (16:19 +0900)
This widget is designed for lottie animation player.

Change-Id: I129e5aa0569012ebb734bf42e3b8ddc91ccb00b0

src/lib/Elementary.h.in
src/lib/Makefile.am
src/lib/elm_animation_view.c [new file with mode: 0644]
src/lib/elm_animation_view.eo [new file with mode: 0644]
src/lib/elm_animation_view.h [new file with mode: 0644]
src/lib/elm_animation_view_eo.h [new file with mode: 0644]
src/lib/elm_animation_view_legacy.h [new file with mode: 0644]
src/lib/elm_transit.c
src/lib/elm_transit.h
src/lib/elm_widget_animation_view.h [new file with mode: 0644]

index 3e0e09d81939754f07b1a50343f01ad73f41fe72..6a40ac45bc01461683ef9268238ab792ca362297 100644 (file)
@@ -187,6 +187,7 @@ EAPI extern Elm_Version *elm_version;
 #include <elc_naviframe.h>
 #include <elc_popup.h>
 #include <elm_actionslider.h>
+#include <elm_animation_view.h>
 #include <elm_app_common.h>
 #include <elm_app_server.h>
 #include <elm_app_server_view.h>
index 15276bf621b490681d2639f393196df300fd0506..ec0e9863aa6e5e432619bcec80ea453278280267 100644 (file)
@@ -37,6 +37,7 @@ Elementary_GL_Helpers.h
 includesdir = $(includedir)/elementary-@VMAJ@
 
 includesunstable_HEADERS = \
+elm_widget_animation_view.h \
 elm_gen_common.h \
 elm_atspi_bridge.h \
 elm_atspi_ewk_wrapper.h \
@@ -114,6 +115,10 @@ elm_widget_web.h
 includesunstabledir = $(includedir)/elementary-@VMAJ@
 
 includesub_HEADERS = \
+elm_animation_view.h \
+elm_animation_view_eo.h \
+elm_animation_view.eo.h \
+elm_animation_view_legacy.h \
 elc_ctxpopup.h \
 elc_ctxpopup_eo.h \
 elc_ctxpopup_legacy.h \
@@ -395,6 +400,7 @@ elc_naviframe.c \
 elc_player.c \
 elc_popup.c \
 elc_scrolled_entry.c \
+elm_animation_view.c \
 elm_access.c \
 elm_actionslider.c \
 elm_app_common.c \
@@ -531,6 +537,7 @@ elm_box.eo \
 elm_bubble.eo \
 elm_button.eo \
 elm_calendar.eo \
+elm_animation_view.eo \
 elm_check.eo \
 elm_clock.eo \
 elm_colorselector.eo \
diff --git a/src/lib/elm_animation_view.c b/src/lib/elm_animation_view.c
new file mode 100644 (file)
index 0000000..f2bed16
--- /dev/null
@@ -0,0 +1,520 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+
+#include "elm_priv.h"
+#include "elm_widget_animation_view.h"
+
+#define MY_CLASS ELM_ANIMATION_VIEW_CLASS
+
+#define MY_CLASS_NAME "Elm_Animation_View"
+#define MY_CLASS_NAME_LEGACY "elm_animation_view"
+
+static const char SIG_FOCUSED[] = "focused";
+static const char SIG_UNFOCUSED[] = "unfocused";
+static const char SIG_PLAY_START[] = "play,start";
+static const char SIG_PLAY_REPEAT[] = "play,repeat";
+static const char SIG_PLAY_DONE[] = "play,done";
+static const char SIG_PLAY_PAUSE[] = "play,pause";
+static const char SIG_PLAY_RESUME[] = "play,resume";
+static const char SIG_PLAY_STOP[] = "play,stop";
+static const char SIG_PLAY_UPDATE[] = "play,update";
+
+/* smart callbacks coming from Elm_Animation_View objects: */
+static const Evas_Smart_Cb_Description _smart_callbacks[] = {
+   {SIG_FOCUSED, ""},
+   {SIG_UNFOCUSED, ""},
+   {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
+   {SIG_PLAY_START, ""},
+   {SIG_PLAY_REPEAT, ""},
+   {SIG_PLAY_DONE, ""},
+   {SIG_PLAY_PAUSE, ""},
+   {SIG_PLAY_RESUME, ""},
+   {SIG_PLAY_STOP, ""},
+   {NULL, NULL}
+};
+
+static void
+_transit_go_facade(Elm_Animation_View_Data *pd)
+{
+   pd->repeat_times = 0;
+   elm_transit_go(pd->transit);
+   evas_object_smart_callback_call(pd->obj, SIG_PLAY_START, NULL);
+}
+
+static Eina_Bool
+_visible_check(Eo *obj)
+{
+   if (!evas_object_visible_get(obj)) return EINA_FALSE;
+
+   //TODO: Check Smart parents visibilities?
+
+   Evas_Coord x, y, w, h;
+   evas_object_geometry_get(obj, &x, &y, &w, &h);
+   if (w == 0 || h == 0) return EINA_FALSE;
+
+   Evas_Coord output_w, output_h;
+   evas_output_size_get(evas_object_evas_get(obj), &output_w, &output_h);
+
+   //Outside viewport
+   if ((x + w < 0) || (x > output_w) ||
+       (y + h < 0) || (y > output_h))
+     return EINA_FALSE;
+
+   //Inside viewport
+   return EINA_TRUE;
+}
+
+static void
+_auto_play(Elm_Animation_View_Data *pd, Eina_Bool vis)
+{
+   if (!pd->auto_play || !pd->transit) return;
+
+   //Resume Animation
+   if (vis)
+     {
+        if (pd->state == ELM_ANIMATION_VIEW_STATE_PAUSE && pd->auto_play_pause)
+          {
+             elm_transit_paused_set(pd->transit, EINA_FALSE);
+             if (pd->play_back)
+               pd->state = ELM_ANIMATION_VIEW_STATE_PLAY_BACK;
+             else
+               pd->state = ELM_ANIMATION_VIEW_STATE_PLAY;
+             pd->auto_play_pause = EINA_FALSE;
+             evas_object_smart_callback_call(pd->obj, SIG_PLAY_RESUME, NULL);
+          }
+     }
+   //Pause Animation
+   else
+     {
+        if ((pd->state == ELM_ANIMATION_VIEW_STATE_PLAY) ||
+            (pd->state == ELM_ANIMATION_VIEW_STATE_PLAY_BACK))
+          {
+             elm_transit_paused_set(pd->transit, EINA_TRUE);
+             pd->state = ELM_ANIMATION_VIEW_STATE_PAUSE;
+             pd->auto_play_pause = EINA_TRUE;
+             evas_object_smart_callback_call(pd->obj, SIG_PLAY_PAUSE, NULL);
+          }
+     }
+}
+
+static void
+_transit_del_cb(Elm_Transit_Effect *effect, Elm_Transit *transit)
+{
+   Elm_Animation_View_Data *pd = (Elm_Animation_View_Data *) effect;
+
+   if ((pd->state == ELM_ANIMATION_VIEW_STATE_PLAY && pd->keyframe == 1) ||
+       (pd->state == ELM_ANIMATION_VIEW_STATE_PLAY_BACK && pd->keyframe == 0))
+     evas_object_smart_callback_call(pd->obj, SIG_PLAY_DONE, NULL);
+
+   if (pd->transit != transit) return;
+
+   Elm_Animation_View_State prev_state = pd->state;
+   pd->state = ELM_ANIMATION_VIEW_STATE_STOP;
+   pd->transit = NULL;
+   pd->auto_play_pause = EINA_FALSE;
+
+   if (prev_state != ELM_ANIMATION_VIEW_STATE_STOP)
+     {
+        evas_object_smart_callback_call(pd->obj, SIG_PLAY_STOP, NULL);
+        pd->keyframe = 0;
+     }
+}
+
+static void
+_transit_cb(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
+{
+   Elm_Animation_View_Data *pd = (Elm_Animation_View_Data *) effect;
+
+   if (!pd->vg)
+     {
+        ERR("Vector Object is removed in wrong way!, Elm_Animation_View = %p", pd->obj);
+        elm_transit_del(transit);
+        return;
+     }
+
+   if (pd->play_back)
+     {
+        pd->state = ELM_ANIMATION_VIEW_STATE_PLAY_BACK;
+        progress = 1 - progress;
+     }
+   else pd->state = ELM_ANIMATION_VIEW_STATE_PLAY;
+
+   pd->keyframe = progress;
+   evas_object_vg_animated_frame_set(pd->vg, (int) (pd->frame_cnt * progress));
+
+   if (pd->auto_repeat)
+     {
+        int repeat_times = elm_transit_current_repeat_times_get(pd->transit);
+        if (pd->repeat_times != repeat_times)
+          {
+             evas_object_smart_callback_call(pd->obj, SIG_PLAY_REPEAT, NULL);
+             pd->repeat_times = repeat_times;
+          }
+     }
+
+   evas_object_smart_callback_call(pd->obj, SIG_PLAY_UPDATE, NULL);
+}
+
+EOLIAN static void
+_elm_animation_view_evas_object_smart_add(Eo *obj, Elm_Animation_View_Data *priv)
+{
+   eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
+
+   elm_widget_sub_object_parent_add(obj);
+
+   // Create vg to render vector animation
+   Eo *vg = evas_object_vg_add(evas_object_evas_get(obj));
+   elm_widget_resize_object_set(obj, vg, EINA_TRUE);
+
+   priv->vg = vg;
+   priv->speed = 1;
+   priv->frame_duration = 0;
+}
+
+EOLIAN static void
+_elm_animation_view_evas_object_smart_del(Eo *obj, Elm_Animation_View_Data *pd EINA_UNUSED)
+{
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+   if (pd->file) eina_stringshare_del(pd->file);
+   if (pd->transit) elm_transit_del(pd->transit);
+   pd->state = ELM_ANIMATION_VIEW_STATE_NOT_READY;
+   eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
+}
+
+EOLIAN static void
+_elm_animation_view_eo_base_destructor(Eo *obj,
+                                       Elm_Animation_View_Data *pd)
+{
+   eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+EOLIAN static Eo *
+_elm_animation_view_eo_base_constructor(Eo *obj,
+                                        Elm_Animation_View_Data *pd)
+{
+   pd->obj = obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+   eo_do(obj,
+         evas_obj_type_set(MY_CLASS_NAME_LEGACY),
+         evas_obj_smart_callbacks_descriptions_set(_smart_callbacks));
+
+   return obj;
+}
+
+static Eina_Bool
+_ready_play(Elm_Animation_View_Data *pd)
+{
+   pd->auto_play_pause = EINA_FALSE;
+   pd->state = ELM_ANIMATION_VIEW_STATE_STOP;
+
+   if (pd->transit) elm_transit_del(pd->transit);
+
+   pd->frame_cnt = (double) evas_object_vg_animated_frame_count_get(pd->vg);
+   pd->frame_duration = evas_object_vg_animated_frame_duration_get(pd->vg, 0, 0);
+   evas_object_vg_animated_frame_set(pd->vg, 0);
+
+   if (pd->frame_duration > 0)
+     {
+        Elm_Transit *transit = elm_transit_add();
+        elm_transit_object_add(transit, pd->vg);
+        if (pd->auto_repeat) elm_transit_repeat_times_set(transit, -1);
+        elm_transit_duration_set(transit, pd->frame_duration * (1/pd->speed));
+        elm_transit_effect_add(transit, _transit_cb, pd, _transit_del_cb);
+        elm_transit_progress_value_set(transit, pd->keyframe);
+        elm_transit_objects_final_state_keep_set(transit, EINA_TRUE);
+        pd->transit = transit;
+
+        return EINA_TRUE;
+     }
+   return EINA_FALSE;
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_efl_file_file_set(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd, const char *file, const char *key)
+{
+   if (!evas_object_vg_file_set(pd->vg, file, key)) return EINA_FALSE;
+
+   if (pd->file) eina_stringshare_del(pd->file);
+   pd->file = eina_stringshare_add(file);
+   pd->keyframe = 0;
+
+   if (!pd->file)
+     {
+        pd->state = ELM_ANIMATION_VIEW_STATE_NOT_READY;
+        pd->frame_cnt = 0;
+        pd->frame_duration = 0;
+        if (pd->transit) elm_transit_del(pd->transit);
+        return EINA_FALSE;
+     }
+
+   if (!_ready_play(pd)) return EINA_TRUE;
+
+   if (pd->auto_play)
+     {
+        _transit_go_facade(pd);
+
+        if (!_visible_check(obj))
+          {
+             elm_transit_paused_set(pd->transit, EINA_TRUE);
+             pd->state = ELM_ANIMATION_VIEW_STATE_PAUSE;
+             pd->auto_play_pause = EINA_TRUE;
+             evas_object_smart_callback_call(pd->obj, SIG_PLAY_PAUSE, NULL);
+          }
+     }
+   return EINA_TRUE;
+}
+
+EOLIAN static void
+_elm_animation_view_evas_object_smart_move(Eo *obj,
+                                           Elm_Animation_View_Data *pd,
+                                           Evas_Coord x, Evas_Coord y)
+{
+   eo_do_super(obj, MY_CLASS, evas_obj_smart_move(x, y));
+   _auto_play(pd, _visible_check(obj));
+}
+
+EOLIAN static void
+_elm_animation_view_evas_object_smart_resize(Eo *obj,
+                                             Elm_Animation_View_Data *pd,
+                                             Evas_Coord w, Evas_Coord h)
+{
+   eo_do_super(obj, MY_CLASS, evas_obj_smart_resize(w, h));
+   _auto_play(pd, _visible_check(obj));
+}
+
+EOLIAN static void
+_elm_animation_view_evas_object_smart_show(Eo *obj,
+                                            Elm_Animation_View_Data *pd)
+{
+   eo_do_super(obj, MY_CLASS, evas_obj_smart_show());
+   _auto_play(pd, _visible_check(obj));
+}
+
+EOLIAN static void
+_elm_animation_view_evas_object_smart_hide(Eo *obj,
+                                           Elm_Animation_View_Data *pd)
+{
+   eo_do_super(obj, MY_CLASS, evas_obj_smart_hide());
+   _auto_play(pd, _visible_check(obj));
+}
+
+EOLIAN static void
+_elm_animation_view_auto_repeat_set(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd, Eina_Bool auto_repeat)
+{
+   if (pd->auto_repeat == auto_repeat) return;
+   pd->auto_repeat = auto_repeat;
+   if (pd->transit)
+     {
+        if (auto_repeat) elm_transit_repeat_times_set(pd->transit, -1);
+        else elm_transit_repeat_times_set(pd->transit, 0);
+     }
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_auto_repeat_get(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   return pd->auto_repeat;
+}
+
+EOLIAN static void
+_elm_animation_view_auto_play_set(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd,
+                                  Eina_Bool auto_play)
+{
+   pd->auto_play = auto_play;
+   if (!auto_play) pd->auto_play_pause = EINA_FALSE;
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_auto_play_get(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   return pd->auto_play;
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_play(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   if (pd->state == ELM_ANIMATION_VIEW_STATE_PLAY) return EINA_FALSE;
+
+   Eina_Bool rewind = EINA_FALSE;
+   if (pd->state == ELM_ANIMATION_VIEW_STATE_PLAY_BACK) rewind = EINA_TRUE;
+
+   pd->play_back = EINA_FALSE;
+   pd->auto_play_pause = EINA_FALSE;
+
+   if (!pd->file) return EINA_FALSE;
+   if (!pd->transit && !_ready_play(pd)) return EINA_FALSE;
+
+   if (pd->state == ELM_ANIMATION_VIEW_STATE_STOP)
+     _transit_go_facade(pd);
+   else if (rewind)
+     elm_transit_progress_value_set(pd->transit, pd->keyframe);
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_stop(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   if (!pd->transit) return EINA_FALSE;
+
+   if ((pd->state == ELM_ANIMATION_VIEW_STATE_NOT_READY) ||
+       (pd->state == ELM_ANIMATION_VIEW_STATE_STOP))
+     return EINA_FALSE;
+
+   evas_object_vg_animated_frame_set(pd->vg, 0);
+   pd->keyframe = 0;
+   pd->state = ELM_ANIMATION_VIEW_STATE_STOP;
+   evas_object_smart_callback_call(pd->obj, SIG_PLAY_STOP, NULL);
+   elm_transit_del(pd->transit);
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_pause(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   if (!pd->transit) return EINA_FALSE;
+
+   if ((pd->state == ELM_ANIMATION_VIEW_STATE_PLAY) ||
+       (pd->state == ELM_ANIMATION_VIEW_STATE_PLAY_BACK))
+     {
+        elm_transit_paused_set(pd->transit, EINA_TRUE);
+        pd->state = ELM_ANIMATION_VIEW_STATE_PAUSE;
+        pd->auto_play_pause = EINA_FALSE;
+        evas_object_smart_callback_call(pd->obj, SIG_PLAY_PAUSE, NULL);
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_resume(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   if (!pd->transit) return EINA_FALSE;
+
+   if (pd->state == ELM_ANIMATION_VIEW_STATE_PAUSE)
+     {
+        elm_transit_paused_set(pd->transit, EINA_FALSE);
+        if (pd->play_back)
+          pd->state = ELM_ANIMATION_VIEW_STATE_PLAY_BACK;
+        else
+          pd->state = ELM_ANIMATION_VIEW_STATE_PLAY;
+        pd->auto_play_pause = EINA_FALSE;
+
+        evas_object_smart_callback_call(pd->obj, SIG_PLAY_RESUME, NULL);
+
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_play_back(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   if (pd->state == ELM_ANIMATION_VIEW_STATE_PLAY_BACK) return EINA_FALSE;
+
+   Eina_Bool rewind = EINA_FALSE;
+   if (pd->state == ELM_ANIMATION_VIEW_STATE_PLAY) rewind = EINA_TRUE;
+
+   pd->play_back = EINA_TRUE;
+   pd->auto_play_pause = EINA_FALSE;
+
+   if (!pd->file) return EINA_FALSE;
+   if (!pd->transit && !_ready_play(pd)) return EINA_FALSE;
+
+   if (pd->state == ELM_ANIMATION_VIEW_STATE_STOP)
+     _transit_go_facade(pd);
+   else if (rewind)
+     elm_transit_progress_value_set(pd->transit, 1 - pd->keyframe);
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_elm_animation_view_speed_set(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd, double speed)
+{
+   if (speed <= 0) return EINA_FALSE;
+   pd->speed = speed;
+
+   if (pd->transit)
+     elm_transit_duration_set(pd->transit, pd->frame_duration * (1/pd->speed));
+
+   return EINA_TRUE;
+}
+
+EOLIAN static void
+_elm_animation_view_keyframe_set(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd, double keyframe)
+{
+   if (keyframe < 0) keyframe = 0;
+   else if (keyframe > 1) keyframe = 1;
+   if (pd->keyframe == keyframe) return;
+
+   pd->keyframe = keyframe;
+
+   if (pd->frame_cnt > 0)
+     evas_object_vg_animated_frame_set(pd->vg, (int) (pd->frame_cnt * keyframe));
+
+   if (pd->transit)
+     elm_transit_progress_value_set(pd->transit, keyframe);
+}
+
+EOLIAN static double
+_elm_animation_view_keyframe_get(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   return pd->keyframe;
+}
+
+EOLIAN static double
+_elm_animation_view_speed_get(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   return pd->speed;
+}
+
+EOLIAN static double
+_elm_animation_view_duration_time_get(Eo *obj EINA_UNUSED, Elm_Animation_View_Data *pd)
+{
+   return pd->frame_duration;
+}
+
+EAPI Elm_Animation_View*
+elm_animation_view_add(Evas_Object *parent)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+   return eo_add(MY_CLASS, parent);
+}
+
+EAPI Eina_Bool
+elm_animation_view_file_set(Elm_Animation_View *obj, const char *file, const char *key)
+{
+   Eina_Bool ret;
+   return eo_do_ret((Eo *) obj, ret, efl_file_set(file, key));
+}
+
+EAPI Elm_Animation_View_State
+elm_animation_view_state_get(const Elm_Animation_View *obj)
+{
+   ELM_ANIMATION_VIEW_DATA_GET(obj, pd);
+   if (!pd) return ELM_ANIMATION_VIEW_STATE_NOT_READY;
+
+   return pd->state;
+}
+
+EAPI Eina_Bool
+elm_animation_view_is_playing_back(const Elm_Animation_View *obj)
+{
+   ELM_ANIMATION_VIEW_DATA_GET(obj, pd);
+   if (!pd) return EINA_FALSE;
+
+   return pd->play_back;
+}
+
+/* Internal EO APIs and hidden overrides */
+
+#define ELM_ANIMATION_VIEW_EXTRA_OPS \
+   EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_animation_view)
+
+#include "elm_animation_view.eo.c"
diff --git a/src/lib/elm_animation_view.eo b/src/lib/elm_animation_view.eo
new file mode 100644 (file)
index 0000000..31b542f
--- /dev/null
@@ -0,0 +1,141 @@
+class Elm.Animation_View (Elm.Widget, Efl.File)
+{
+   [[Elementary Animation View class]]
+   legacy_prefix: elm_animation_view;
+   eo_prefix: elm_obj_animation_view;
+   methods {
+      @property auto_play {
+         [[Animation will be started automatically when it's possible.
+
+           If $auto_play is $true, animation will be started when it's readied.
+           The condition of auto play is when animation view opened file successfully,
+           yet to play it plus when the object is visible.
+           If animation view is disabled, invisible,
+           it turns to pause state then resume animation when it's visible again.
+
+           Warning: This auto play will be only affected to the next animation source.
+           So must be called before elm_animation_view_file_set().]]
+         set {
+         }
+         get {
+         }
+         values {
+            auto_play: bool; [[$true Enable auto play mode, disable otherwise]]
+         }
+      }
+      @property auto_repeat {
+         [[Turn on/off animation looping.
+
+           If $auto_repeat is $true, it repeats animation when animation frame is reached to
+           end. This auto repeat mode is valid to both play and play_back cases.]]
+         set {
+         }
+         get {
+         }
+         values {
+            auto_repeat: bool; [[Enable loop mode if $true, disable otherwise]]
+         }
+      }
+      @property speed {
+         [[Control animation speed.
+
+           Control animation speed by multiplying $speed value. If you want to play
+           animation double-time faster, you can give $speed 2. If you want to play
+           animation double-time slower, you can give $speed 0.5.
+
+           Warning: speed must be greater than zero.]]
+         set {
+            return: bool; [[$true when it's successful. $false otherwise.]]
+         }
+         get {
+         }
+         values {
+            speed: double; [[ Speed factor. Default value is 1]]
+         }
+      }
+      @property duration_time {
+         [[Get the duration of animation in seconds.
+
+           This API returns total duration time of current animation in the seconds.
+           If current animation source isn't animatable, it returns zero.]]
+         get {
+         }
+         values {
+            frame_duration: double; [[duration time in the seconds]]
+         }
+      }
+      @property keyframe {
+         [[Set current keyframe position of animation view.
+
+           When you required to jump on a certain frame instantly,
+           you can change current keyframe by using this API.
+
+           Warning: The range of keyframe is 0 ~ 1.]]
+         set {
+         }
+         get {
+         }
+         values {
+            keyframe: double; [[Keyframe position. Value must be 0 ~ 1.]]
+         }
+      }
+      play {
+         [[Play animation one time instantly when it's available.
+
+           If current keyframe is on a certain position by playing back, this will
+           play forward from there.
+
+           Warning: Play request will be ignored if animation source is not set yet or
+           animation is paused state or it's already on playing.]]
+
+         return: bool; [[$true when it's successful. $false otherwise.]]
+      }
+      play_back {
+         [[Play back animation one time instantly when it's available.
+
+           If current keyframe is on a certain position by playing, this will
+           play backward from there.
+
+           Warning: Play back request will be ignored if animation source is not set yet or
+           animation is paused state or it's already on playing back.]]
+
+         return: bool; [[$true when it's successful. $false otherwise.]]
+      }
+      pause {
+         [[Pause current animation instantly.
+
+           Once animation is paused, animation view must get resume to play continue again.
+
+           Warning: Animation must be on playing or playing back status.]]
+
+         return: bool; [[$true when it's successful. $false otherwise.]]
+      }
+      resume {
+         [[Resume paused animation to continue animation.
+
+           Warning: This resume must be called on animation paused status. ]]
+
+         return: bool; [[$true when it's successful. $false otherwise.]]
+      }
+      stop {
+         [[Stop playing animation.
+
+           Stop animation instatly regardless of it's status and reset to
+           show first frame of animation. Even though current animation is paused,
+           the animation status will be stopped.]]
+
+         return: bool; [[$true when it's successful. $false otherwise.]]
+      }
+   }
+   implements {
+      Eo.Base.constructor;
+      Eo.Base.destructor;
+      Evas.Object_Smart.add;
+      Evas.Object_Smart.del;
+      Evas.Object_Smart.show;
+      Evas.Object_Smart.hide;
+      Evas.Object_Smart.move;
+      Evas.Object_Smart.resize;
+      Efl.File.file.set;
+   }
+}
diff --git a/src/lib/elm_animation_view.h b/src/lib/elm_animation_view.h
new file mode 100644 (file)
index 0000000..d31842f
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * @defgroup Elm_Animation_View Animation_View
+ * @ingroup Elementary
+ *
+ * Animation_View widget is designed to show and play animation of
+ * vector graphics based content. It hides all efl_canvas_vg details
+ * but just open an API to read vector data from file. Also, it implements
+ * details of animation control methods of Vector.
+ *
+ * Vector data could contain static or animatable vector elements including
+ * animation infomation. Currently approved vector data file format is svg, json and eet.
+ * Only json(known for Lottie file as well) and eet could contains animation infomation,
+ * currently Animation_View is supporting.
+ *
+ * This widget emits the following signals, besides the ones sent from
+ * @ref Animation_View:
+ * @li "play,start": animation is just started.
+ * @li "play,repeat": animation is just repeated.
+ * @li "play,done": animation is just finished.
+ * @li "play,pause": animation is just paused.
+ * @li "play,resume": animation is just resumed.
+ * @li "play,stop": animation is just stopped.
+ * @li "play,update": animation is updated to the next frame.
+ *
+ */
+
+/**
+ * @ingroup Elm_Animation_View
+ */
+
+#ifdef EFL_EO_API_SUPPORT
+#include "elm_animation_view_eo.h"
+#endif
+#ifndef EFL_NOLEGACY_API_SUPPORT
+#include "elm_animation_view_legacy.h"
+#endif
+/**
+ * @}
+ */
diff --git a/src/lib/elm_animation_view_eo.h b/src/lib/elm_animation_view_eo.h
new file mode 100644 (file)
index 0000000..e7ef06f
--- /dev/null
@@ -0,0 +1 @@
+#include "elm_animation_view.eo.h"
diff --git a/src/lib/elm_animation_view_legacy.h b/src/lib/elm_animation_view_legacy.h
new file mode 100644 (file)
index 0000000..81b5851
--- /dev/null
@@ -0,0 +1,71 @@
+typedef Eo Elm_Animation_View;
+
+typedef enum
+{
+   ELM_ANIMATION_VIEW_STATE_NOT_READY, /*< Animation is not ready to play. (Probably, it didn't file set yet or failed to read file. @since 1.22 @ingroup Elm_Animation_View */
+   ELM_ANIMATION_VIEW_STATE_PLAY, /*< Animation is on playing. @see elm_animation_play() @since 1.22 @ingroup Elm_Animation_View */
+   ELM_ANIMATION_VIEW_STATE_PLAY_BACK, /*< Animation is on playing back (rewinding). @see elm_animation_back() @since 1.22 @ingroup Elm_Animation_View */
+   ELM_ANIMATION_VIEW_STATE_PAUSE, /*< Animation has been paused. To continue animation, call elm_animation_view_resume(). @see elm_animation_pause() @since 1.22 @ingroup Elm_Animation_View */
+   ELM_ANIMATION_VIEW_STATE_STOP /*< Animation view successfully loaded a file then readied for playing. Otherwise after finished animation or stopped forcely by request. @see elm_animation_stop() @since 1.22 @ingroup Elm_Animation_View */
+} Elm_Animation_View_State;
+
+/**
+ * Add a new animation view widget to the parent's canvas
+ *
+ * @param parent The parent object
+ * @return The new animation view object or @c NULL if it failed to create.
+ *
+ * @ingroup Elm_Animation_View
+ *
+ * @since 1.22
+ */
+EAPI Elm_Animation_View     *elm_animation_view_add(Evas_Object *parent);
+
+/**
+ *
+ * Set the source file from where an vector object must fetch the real
+ * vector data (it may be one of json, svg, eet files).
+ *
+ * If the file supports multiple data stored in it (as Eet files do),
+ * you can specify the key to be used as the index of the vector in
+ * this file.
+ *
+ * @param[in] file The vector file path.
+ * @param[in] key The vector key in @p file (if its an Eet one), or @c
+NULL, otherwise.
+ *
+ * @return @c EINA_TRUE if it's succeed to read file, @c EINA_FALSE otherwise.
+ *
+ * @ingroup Elm_Animation_View
+ *
+ * @since 1.22
+*/
+EAPI Eina_Bool        elm_animation_view_file_set(Elm_Animation_View *obj, const char *file, const char *key);
+
+/**
+ * @brief Get current animation view state.
+ *
+ * @return Current animation view state
+ *
+ * @see Elm_Animation_View_State
+ *
+ * @ingroup Elm_Animation_View
+ *
+ * @since 1.22
+ */
+EAPI Elm_Animation_View_State elm_animation_view_state_get(const Elm_Animation_View *obj);
+
+/**
+ * @brief Returns the status whether current animation is on playing forward or backward.
+ *
+ * @return @c EINA_TRUE, if animation on playing back, @c EINA_FALSE otherwise.
+ *
+ * @ingroup Elm_Animation_View
+ *
+ * @warning If animation view is not on playing, it will return @c EINA_FALSE.
+ *
+ * @since 1.22
+ */
+EAPI Eina_Bool         elm_animation_view_is_playing_back(const Elm_Animation_View *obj);
+
+#include "elm_animation_view.eo.legacy.h"
index b8f851bcea5ffb915f9ce19bdb58bfde7ec6e844..a9c32b9320ba7479689661f2bfe899b39431abd9 100644 (file)
@@ -48,6 +48,10 @@ struct _Elm_Transit
         double duration;
         double begin;
         double current;
+        double revert_start;
+        double revert_elapsed;
+        double revert_paused;
+        double revert_delayed;
      } time;
    struct
      {
@@ -56,6 +60,10 @@ struct _Elm_Transit
         Eina_Bool reverse;
      } repeat;
    double progress;
+   double inter_progress;
+   double revert_begin_progress;
+   double revert_duration;
+   double total_revert_time;
    unsigned int effects_pending_del;
    int walking;
    double v[4];
@@ -65,6 +73,7 @@ struct _Elm_Transit
    Eina_Bool state_keep : 1;
    Eina_Bool finished : 1;
    Eina_Bool smooth : 1;
+   Eina_Bool revert_mode : 1;
 };
 
 struct _Elm_Transit_Effect_Module
@@ -295,7 +304,7 @@ _transit_del(Elm_Transit *transit)
    free(transit);
 }
 
-//If the transit is deleted then EINA_FALSE is retruned.
+//If the transit is deleted then EINA_FALSE is returned.
 static Eina_Bool
 _transit_animate_op(Elm_Transit *transit, double progress)
 {
@@ -327,16 +336,31 @@ static Eina_Bool
 _transit_animate_cb(void *data)
 {
    Elm_Transit *transit = data;
-   double elapsed_time, duration;
+   double elapsed_time, duration, revert_progress;
 
    transit->time.current = ecore_loop_time_get();
-   elapsed_time = transit->time.current - transit->time.begin;
-   duration = transit->time.duration + transit->time.delayed;
+   elapsed_time = (transit->time.current - transit->time.begin - transit->time.delayed)
+      - (2 * transit->total_revert_time);
+   duration = transit->time.duration;
+   transit->progress = elapsed_time / duration;
 
-   if (elapsed_time > duration)
-     elapsed_time = duration;
+   if (transit->revert_mode && transit->revert_begin_progress == 0)
+     {
+        transit->revert_begin_progress = transit->progress;
+        transit->time.revert_start = transit->time.current;
+     }
+
+   if (transit->revert_mode)
+     {
+        transit->time.revert_elapsed =
+           (transit->time.current - transit->time.revert_start - transit->time.revert_delayed);
+        revert_progress = transit->time.revert_elapsed / duration;
+        transit->progress = transit->revert_begin_progress - revert_progress;
+     }
+
+   /* Intervention Progress */
+   transit->progress += transit->inter_progress;
 
-   transit->progress = elapsed_time / duration;
    switch (transit->tween_mode)
      {
       case ELM_TRANSIT_TWEEN_MODE_LINEAR:
@@ -389,14 +413,32 @@ _transit_animate_cb(void *data)
    /* Reverse? */
    if (transit->repeat.reverse) transit->progress = 1 - transit->progress;
 
-   if (transit->time.duration > 0)
+   if (!_transit_animate_op(transit, transit->progress))
+     return ECORE_CALLBACK_CANCEL;
+
+   if (transit->revert_mode && (transit->progress <= 0 || transit->progress >= 1))
      {
-        if (!_transit_animate_op(transit, transit->progress))
-          return ECORE_CALLBACK_CANCEL;
+        transit->revert_mode = EINA_FALSE;
+        transit->time.begin = ecore_loop_time_get();
+        transit->time.revert_delayed = 0;
+        transit->total_revert_time = 0;
+        transit->inter_progress = 0;
+        if ((transit->repeat.count >= 0) &&
+            (transit->repeat.current == transit->repeat.count) &&
+            ((!transit->auto_reverse) || transit->repeat.reverse))
+          {
+             transit->finished = EINA_TRUE;
+             elm_transit_del(transit);
+             return ECORE_CALLBACK_CANCEL;
+          }
+        else
+          return ECORE_CALLBACK_RENEW;
      }
 
    /* Not end. Keep going. */
-   if (elapsed_time < duration) return ECORE_CALLBACK_RENEW;
+   if ((!transit->repeat.reverse && transit->progress < 1) ||
+        (transit->repeat.reverse && transit->progress > 0) ||
+        transit->revert_mode) return ECORE_CALLBACK_RENEW;
 
    /* Repeat and reverse and time done! */
    if ((transit->repeat.count >= 0) &&
@@ -417,6 +459,9 @@ _transit_animate_cb(void *data)
    else transit->repeat.reverse = EINA_TRUE;
 
    transit->time.begin = ecore_loop_time_get();
+   transit->time.delayed = 0;
+   transit->total_revert_time = 0;
+   transit->inter_progress = 0;
 
    return ECORE_CALLBACK_RENEW;
 }
@@ -699,6 +744,13 @@ elm_transit_repeat_times_set(Elm_Transit *transit, int repeat)
    transit->repeat.current = 0;
 }
 
+EAPI int
+elm_transit_current_repeat_times_get(const Elm_Transit *transit)
+{
+   ELM_TRANSIT_CHECK_OR_RETURN(transit, 0);
+   return transit->repeat.current;
+}
+
 EAPI int
 elm_transit_repeat_times_get(const Elm_Transit *transit)
 {
@@ -750,11 +802,6 @@ EAPI void
 elm_transit_duration_set(Elm_Transit *transit, double duration)
 {
    ELM_TRANSIT_CHECK_OR_RETURN(transit);
-   if (transit->animator)
-     {
-        WRN("elm_transit does not allow to set the duration time in operating! : transit=%p", transit);
-        return;
-     }
    transit->time.duration = duration;
 }
 
@@ -765,6 +812,28 @@ elm_transit_duration_get(const Elm_Transit *transit)
    return transit->time.duration;
 }
 
+EAPI Eina_Bool
+elm_transit_revert(Elm_Transit *transit)
+{
+   ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
+
+   if (!transit->animator) return EINA_FALSE;
+
+   if (transit->revert_mode)
+     {
+        transit->total_revert_time += transit->time.revert_elapsed;
+        transit->revert_mode = EINA_FALSE;
+     }
+   else
+     {
+        transit->revert_mode = EINA_TRUE;
+        transit->time.revert_elapsed = 0;
+        transit->revert_begin_progress = 0;
+     }
+
+   return EINA_TRUE;
+}
+
 EAPI void
 elm_transit_go(Elm_Transit *transit)
 {
@@ -788,6 +857,10 @@ elm_transit_go(Elm_Transit *transit)
 
    transit->time.paused = 0;
    transit->time.delayed = 0;
+   transit->time.revert_paused = 0;
+   transit->time.revert_delayed = 0;
+   transit->total_revert_time = 0;
+   transit->revert_mode = EINA_FALSE;
    transit->time.begin = ecore_loop_time_get();
    transit->animator = ecore_animator_add(_transit_animate_cb, transit);
 
@@ -812,18 +885,34 @@ elm_transit_paused_set(Elm_Transit *transit, Eina_Bool paused)
 
    if (paused)
      {
-        if (transit->time.paused > 0)
-          return;
+        if (transit->revert_mode)
+          {
+             if (transit->time.revert_paused > 0)return;
+             transit->time.revert_paused = ecore_loop_time_get();
+          }
+        else
+          {
+             if (transit->time.paused > 0)return;
+             transit->time.paused = ecore_loop_time_get();
+          }
         ecore_animator_freeze(transit->animator);
-        transit->time.paused = ecore_loop_time_get();
      }
    else
      {
-        if (transit->time.paused == 0)
-          return;
-        ecore_animator_thaw(transit->animator);
-        transit->time.delayed += (ecore_loop_time_get() - transit->time.paused);
-        transit->time.paused = 0;
+        if (transit->revert_mode)
+          {
+             if (transit->time.revert_paused == 0) return;
+             ecore_animator_thaw(transit->animator);
+             transit->time.revert_delayed += (ecore_loop_time_get() - transit->time.revert_paused);
+             transit->time.revert_paused = 0;
+          }
+        else
+          {
+             if (transit->time.paused == 0) return;
+             ecore_animator_thaw(transit->animator);
+             transit->time.delayed += (ecore_loop_time_get() - transit->time.paused);
+             transit->time.paused = 0;
+          }
      }
 }
 
@@ -838,6 +927,17 @@ elm_transit_paused_get(const Elm_Transit *transit)
    return EINA_TRUE;
 }
 
+EAPI void
+elm_transit_progress_value_set(Elm_Transit *transit, double progress)
+{
+   ELM_TRANSIT_CHECK_OR_RETURN(transit);
+
+   if (progress < 0) progress = 0;
+   else if (progress > 1) progress = 1;
+
+   transit->inter_progress = (progress - transit->progress);
+}
+
 EAPI double
 elm_transit_progress_value_get(const Elm_Transit *transit)
 {
index 67b6042c63e6eecefc1dee751515357653d0955f..f3f0023aae2b19e0a5cb50ea8ab17c27f1bdfee8 100644 (file)
@@ -476,6 +476,22 @@ EAPI void                   elm_transit_repeat_times_set(Elm_Transit *transit, i
  */
 EAPI int                    elm_transit_repeat_times_get(const Elm_Transit *transit);
 
+/**
+ * Get current transit repeated count.
+ *
+ * @see elm_transit_repeat_times_set()
+ *
+ * @param transit The Transit object.
+ * @return Current repeated count. If @p transit is NULL
+ * 0 is returned
+ *
+ * @warning Return value is only valid when repeat times is set.
+ * @since 1.22
+ *
+ * @ingroup Elm_Transit
+ */
+EAPI int                    elm_transit_current_repeat_times_get(const Elm_Transit *transit);
+
 /**
  * Set the transit animation acceleration type.
  *
@@ -668,6 +684,26 @@ EAPI double                 elm_transit_duration_get(const Elm_Transit *transit)
  */
 EAPI void                   elm_transit_go(Elm_Transit *transit);
 
+/**
+ * This API can be used to reverse play an ongoing transition.
+ * It shows effect only when an animation is going on.
+ * If this API is called twice transition will go in forward direction as normal one.
+ * If a repeat count is set, this API call will revert just the ongoing cycle and once
+ * it is reverted back completely, the transition will go in forward direction.
+ * If an autoreverse is set for the transition and this API is called in the midst of
+ * the transition the ongoing transition will be reverted and once it is done, the
+ * transition will begin again and complete a full auto reverse cycle.
+ *
+ * @note @p transit can not be NULL
+ *
+ * @param transit The transit object.
+ * @return @c EINA_TRUE if transition is reverted, @c EINA_FALSE otherwise.
+ *
+ * @since 1.18
+ * @ingroup Elm_Transit
+ */
+EAPI Eina_Bool               elm_transit_revert(Elm_Transit *transit);
+
 /**
  * Starts the transition in given seconds.
  *
@@ -744,6 +780,25 @@ EAPI Eina_Bool              elm_transit_paused_get(const Elm_Transit *transit);
  */
 EAPI double                 elm_transit_progress_value_get(const Elm_Transit *transit);
 
+
+/**
+ * Set current time progression of the animation.
+ *
+ * Intervene current progress instantly when it requires to jump onto a specific frame position.
+ *
+ * @note @p transit can not be NULL
+ *
+ * @param transit The transit object.
+ * @param progress The time progression value. The value must be in range of (0.0 ~ 1.0).
+ *
+ * @see elm_transit_progress_value_get()
+ *
+ * @since 1.22
+ *
+ * @ingroup Elm_Transit
+ */
+EAPI void                   elm_transit_progress_value_set(Elm_Transit *transit, double progress);
+
 /**
  * Makes the chain relationship between two transits.
  *
diff --git a/src/lib/elm_widget_animation_view.h b/src/lib/elm_widget_animation_view.h
new file mode 100644 (file)
index 0000000..2c40a2e
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef ELM_WIDGET_ANIMATION_VIEW_H
+#define ELM_WIDGET_ANIMATION_VIEW_H
+
+#include "Elementary.h"
+
+typedef struct _Elm_Animation_View_Data Elm_Animation_View_Data;
+
+struct _Elm_Animation_View_Data
+{
+   Eo* obj;                           //Elm_Animation_View Object
+   Eo* vg;                            //Evas_Object_Vg
+   Elm_Animation_View_State state;
+   Elm_Transit *transit;
+   Eina_Stringshare *file;
+   double speed;
+   double keyframe;
+   double frame_cnt;
+   int repeat_times;
+   double frame_duration;
+
+   Eina_Bool play_back : 1;
+   Eina_Bool auto_play : 1;
+   Eina_Bool auto_play_pause: 1;
+   Eina_Bool auto_repeat : 1;
+};
+
+#define ELM_ANIMATION_VIEW_DATA_GET(o, sd) \
+  Elm_Animation_View_Data * sd = eo_data_scope_get(o, ELM_ANIMATION_VIEW_CLASS)
+
+#define ELM_ANIMATION_VIEW_DATA_GET_OR_RETURN(o, ptr)   \
+  ELM_ANIMATION_VIEW_DATA_GET(o, ptr);                  \
+  if (EINA_UNLIKELY(!ptr))                              \
+    {                                                   \
+       ERR("No widget data for object %p (%s)",         \
+           o, evas_object_type_get(o));                 \
+       return;                                          \
+    }
+
+#endif