hermet pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=8900cf0715e97640eb6226023a6005b4c6021e42
commit 8900cf0715e97640eb6226023a6005b4c6021e42 Author: Hermet Park <hermetp...@gmail.com> Date: Wed Aug 21 17:39:43 2019 +0900 efl_ui_animation_view: introduce a new widget for controlling vector animation. Summary: This is a new convenient ui control that designed to load vector resources -svg, json-, and control animations if it supports. Please turn on evas-loaders-json in meson options, if you'd like to use Lottie Animation. Co-authored-by: JunsuChoi <jsuya.c...@samsung.com> @feature Reviewers: #committers, jsuya, zmike, bu5hm4n Reviewed By: #committers, bu5hm4n Subscribers: zmike, bu5hm4n, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9451 --- src/lib/elementary/Efl_Ui.h | 1 + src/lib/elementary/Elementary.h | 2 + src/lib/elementary/efl_ui_animation_view.c | 735 +++++++++++++++++++++ src/lib/elementary/efl_ui_animation_view.eo | 281 ++++++++ src/lib/elementary/efl_ui_animation_view.h | 33 + .../elementary/efl_ui_animation_view_eo.legacy.c | 162 +++++ .../elementary/efl_ui_animation_view_eo.legacy.h | 517 +++++++++++++++ src/lib/elementary/efl_ui_animation_view_legacy.h | 49 ++ src/lib/elementary/efl_ui_animation_view_private.h | 41 ++ src/lib/elementary/meson.build | 6 + src/tests/elementary/spec/efl_test_gfx_view.c | 39 ++ src/tests/elementary/spec/efl_ui_spec_suite.h | 1 + src/tests/elementary/spec/meson.build | 1 + 13 files changed, 1868 insertions(+) diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h index 3d0b0ba113..b79ed12ea6 100644 --- a/src/lib/elementary/Efl_Ui.h +++ b/src/lib/elementary/Efl_Ui.h @@ -209,6 +209,7 @@ EAPI void efl_ui_focus_relation_free(Efl_Ui_Focus_Relations *rel); # include <efl_ui_text_async.eo.h> # endif +# include <efl_ui_animation_view.h> # include <efl_ui_clock.h> # include <efl_ui_image_factory.eo.h> # include <efl_ui_video.h> diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h index 63e9e88d14..929825692d 100644 --- a/src/lib/elementary/Elementary.h +++ b/src/lib/elementary/Elementary.h @@ -212,6 +212,7 @@ typedef Eo Efl_Ui_Focus_Manager; #include <elm_button.h> #include <elm_cache.h> #include <elm_calendar.h> +#include <efl_ui_animation_view.h> #include <efl_ui_calendar.h> #include <elm_check.h> #include <elm_clock.h> @@ -350,6 +351,7 @@ typedef Eo Efl_Ui_Focus_Manager; # include <efl_ui_dnd.eo.h> # include <efl_ui_dnd_container.eo.h> # include <efl_ui_relative_layout.eo.h> +# include <efl_ui_animation_view.eo.h> # include <efl_ui_tab_bar.eo.h> # include <efl_ui_tab_page.eo.h> # include <efl_ui_tab_page_part_tab.eo.h> diff --git a/src/lib/elementary/efl_ui_animation_view.c b/src/lib/elementary/efl_ui_animation_view.c new file mode 100644 index 0000000000..418d8adc42 --- /dev/null +++ b/src/lib/elementary/efl_ui_animation_view.c @@ -0,0 +1,735 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#define EFL_ACCESS_OBJECT_PROTECTED + +#include <Elementary.h> + +#include "elm_priv.h" +#include "efl_ui_animation_view_private.h" + +#define MY_CLASS EFL_UI_ANIMATION_VIEW_CLASS + +#define MY_CLASS_NAME "Efl_Ui_Animation_View" +#define MY_CLASS_NAME_LEGACY "efl_ui_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 Efl_Ui_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 +_sizing_eval(Eo *obj, void *data) +{ + Efl_Ui_Animation_View_Data *pd = data; + if (!efl_file_loaded_get(obj)) return; + + double hw,hh; + efl_gfx_hint_weight_get(obj, &hw, &hh); + + Eina_Size2D size = efl_canvas_vg_object_default_size_get(pd->vg); + + Eina_Size2D min = {-1, -1}; + if (hw == 0) min.w = size.w; + if (hh == 0) min.h = size.h; + + efl_gfx_hint_size_min_set(obj, min); +} + +static void +_size_hint_event_cb(void *data, const Efl_Event *event) +{ + _sizing_eval(event->object, data); +} + +static void +_transit_go_facade(Eo* obj, Efl_Ui_Animation_View_Data *pd) +{ + pd->repeat_times = 0; + if (pd->play_back) + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK; + else + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PLAY; + evas_object_smart_callback_call(obj, SIG_PLAY_START, NULL); + if (pd->transit) elm_transit_go(pd->transit); +} + +static Eina_Bool +_visible_check(Eo *obj) +{ + if (!efl_gfx_entity_visible_get(obj)) return EINA_FALSE; + + //TODO: Check Smart parents visibilities? + + Eina_Size2D size = efl_gfx_entity_size_get(obj); + if (size.w == 0 || size.h == 0) return EINA_FALSE; + + Evas_Coord output_w, output_h; + evas_output_size_get(evas_object_evas_get(obj), &output_w, &output_h); + + Eina_Position2D pos = efl_gfx_entity_position_get(obj); + + //Outside viewport + if ((pos.x + size.w < 0) || (pos.x > output_w) || + (pos.y + size.h < 0) || (pos.y > output_h)) + return EINA_FALSE; + + //Inside viewport + return EINA_TRUE; +} + +static void +_auto_play(Eo *obj, Efl_Ui_Animation_View_Data *pd, Eina_Bool vis) +{ + if (!pd->auto_play || !pd->transit) return; + + //Resume Animation + if (vis) + { + if (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PAUSE && pd->auto_play_pause) + { + elm_transit_paused_set(pd->transit, EINA_FALSE); + if (pd->play_back) + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK; + else + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PLAY; + pd->auto_play_pause = EINA_FALSE; + evas_object_smart_callback_call(obj, SIG_PLAY_RESUME, NULL); + } + } + //Pause Animation + else + { + if ((pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY) || + (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK)) + { + elm_transit_paused_set(pd->transit, EINA_TRUE); + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PAUSE; + pd->auto_play_pause = EINA_TRUE; + evas_object_smart_callback_call(obj, SIG_PLAY_PAUSE, NULL); + } + } +} + +static void +_transit_del_cb(Elm_Transit_Effect *effect, Elm_Transit *transit) +{ + Eo *obj = (Eo *) effect; + EFL_UI_ANIMATION_VIEW_DATA_GET(obj, pd); + if (!pd) return; + + if ((pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY && pd->progress == 1) || + (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK && pd->progress == 0)) + evas_object_smart_callback_call(obj, SIG_PLAY_DONE, NULL); + + if (pd->transit != transit) return; + + Efl_Ui_Animation_View_State prev_state = pd->state; + pd->state = EFL_UI_ANIMATION_VIEW_STATE_STOP; + pd->transit = NULL; + pd->auto_play_pause = EINA_FALSE; + + if (prev_state != EFL_UI_ANIMATION_VIEW_STATE_STOP) + { + evas_object_smart_callback_call(obj, SIG_PLAY_STOP, NULL); + pd->progress = 0; + } +} + +static void +_transit_cb(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress) +{ + Eo *obj = (Eo *) effect; + EFL_UI_ANIMATION_VIEW_DATA_GET(obj, pd); + + if (!pd || !pd->vg) + { + ERR("Vector Object is removed in wrong way!, Efl_Ui_Animation_View = %p", obj); + elm_transit_del(transit); + return; + } + + if (pd->play_back) + { + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK; + progress = 1 - progress; + } + else pd->state = EFL_UI_ANIMATION_VIEW_STATE_PLAY; + + pd->progress = progress; + int minframe = (pd->frame_cnt - 1) * pd->min_progress; + int maxframe = (pd->frame_cnt - 1) * pd->max_progress; + + int update_frame = (int)((maxframe - minframe) * progress) + minframe; + int current_frame = evas_object_vg_animated_frame_get(pd->vg); + evas_object_vg_animated_frame_set(pd->vg, update_frame); + + 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(obj, SIG_PLAY_REPEAT, NULL); + pd->repeat_times = repeat_times; + } + } + + //transit_cb is always called with a progress value 0 ~ 1. + //SIG_PLAY_UPDATE callback is called only when there is a real change. + if (update_frame != current_frame) + evas_object_smart_callback_call(obj, SIG_PLAY_UPDATE, NULL); +} + +EOLIAN static void +_efl_ui_animation_view_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Animation_View_Data *priv) +{ + efl_canvas_group_add(efl_super(obj, MY_CLASS)); + 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); + efl_event_callback_add(obj, EFL_GFX_ENTITY_EVENT_HINTS_CHANGED, _size_hint_event_cb, priv); + + priv->vg = vg; + priv->speed = 1; + priv->frame_duration = 0; + priv->min_progress = 0.0; + priv->max_progress = 1.0; +} + +EOLIAN static void +_efl_ui_animation_view_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Animation_View_Data *pd EINA_UNUSED) +{ + if (pd->transit) + { + Elm_Transit *transit = pd->transit; + pd->transit = NULL; //Skip perform transit_del_cb() + elm_transit_del(transit); + } + pd->state = EFL_UI_ANIMATION_VIEW_STATE_NOT_READY; + + efl_canvas_group_del(efl_super(obj, MY_CLASS)); +} + +EOLIAN static void +_efl_ui_animation_view_efl_object_destructor(Eo *obj, + Efl_Ui_Animation_View_Data *pd EINA_UNUSED) +{ + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static Eo * +_efl_ui_animation_view_efl_object_constructor(Eo *obj, + Efl_Ui_Animation_View_Data *pd EINA_UNUSED) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY); + evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks); + + return obj; +} + +static void +_update_frame_duration(Efl_Ui_Animation_View_Data *pd) +{ + int frame_count = evas_object_vg_animated_frame_count_get(pd->vg); + int min_frame = (frame_count - 1) * pd->min_progress; + int max_frame = (frame_count - 1) * pd->max_progress; + double frame_rate = round((double)frame_count / evas_object_vg_animated_frame_duration_get(pd->vg, 0, 0)); + + pd->frame_duration = (double)(max_frame - min_frame) / frame_rate; + if (pd->transit) + elm_transit_duration_set(pd->transit, pd->frame_duration * (1/pd->speed)); +} + +static Eina_Bool +_ready_play(Eo *obj, Efl_Ui_Animation_View_Data *pd) +{ + pd->auto_play_pause = EINA_FALSE; + pd->state = EFL_UI_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_effect_add(transit, _transit_cb, obj, _transit_del_cb); + elm_transit_progress_value_set(transit, pd->progress); + elm_transit_objects_final_state_keep_set(transit, EINA_TRUE); + pd->transit = transit; + if (pd->min_progress != 0.0 || pd->max_progress != 1.0) + _update_frame_duration(pd); + else + elm_transit_duration_set(transit, pd->frame_duration * (1/pd->speed)); + + return EINA_TRUE; + } + return EINA_FALSE; +} + +EOLIAN static void +_efl_ui_animation_view_efl_file_unload(Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + pd->state = EFL_UI_ANIMATION_VIEW_STATE_NOT_READY; + pd->frame_cnt = 0; + pd->frame_duration = 0; + if (pd->transit) elm_transit_del(pd->transit); +} + +EOLIAN static Eina_Error +_efl_ui_animation_view_efl_file_load(Eo *obj, Efl_Ui_Animation_View_Data *pd) +{ + Eina_Error err; + Eina_Bool ret; + const char *file; + const char *key; + + if (efl_file_loaded_get(obj)) return 0; + + err = efl_file_load(efl_super(obj, MY_CLASS)); + if (err) return err; + + file = efl_file_get(obj); + key = efl_file_key_get(obj); + ret = efl_file_simple_load(pd->vg, file, key); + if (!ret) + { + efl_file_unload(obj); + return eina_error_get(); + } + + pd->progress = 0; + + _sizing_eval(obj, pd); + + if (!_ready_play(obj, pd)) return 1; + + if (pd->auto_play) + { + _transit_go_facade(obj, pd); + + if (!_visible_check(obj)) + { + elm_transit_paused_set(pd->transit, EINA_TRUE); + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PAUSE; + pd->auto_play_pause = EINA_TRUE; + evas_object_smart_callback_call(obj, SIG_PLAY_PAUSE, NULL); + } + } + return 0; +} + +EOLIAN static void +_efl_ui_animation_view_efl_gfx_entity_position_set(Eo *obj, + Efl_Ui_Animation_View_Data *pd, + Eina_Position2D pos EINA_UNUSED) +{ + if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y)) + return; + + efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos); + + _auto_play(obj, pd, _visible_check(obj)); +} + +EOLIAN static void +_efl_ui_animation_view_efl_gfx_entity_size_set(Eo *obj, + Efl_Ui_Animation_View_Data *pd, + Eina_Size2D size) +{ + if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, size.w, size.h)) + return; + + efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), size); + + _sizing_eval(obj, pd); + + _auto_play(obj, pd, _visible_check(obj)); +} + +EOLIAN static void +_efl_ui_animation_view_efl_gfx_entity_visible_set(Eo *obj, + Efl_Ui_Animation_View_Data *pd, + Eina_Bool vis) +{ + if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis)) + return; + + efl_gfx_entity_visible_set(efl_super(obj, MY_CLASS), vis); + + _auto_play(obj, pd, _visible_check(obj)); +} + +EOLIAN static void +_efl_ui_animation_view_efl_gfx_view_view_size_set(Eo *obj EINA_UNUSED, + Efl_Ui_Animation_View_Data *pd, + Eina_Size2D size) +{ + Eina_Rect viewbox; + viewbox.x = viewbox.y =0; + viewbox.w = size.w; + viewbox.h = size.h; + + efl_canvas_vg_object_viewbox_set(pd->vg, viewbox); +} + +EOLIAN Eina_Size2D +_efl_ui_animation_view_efl_gfx_view_view_size_get(const Eo *obj EINA_UNUSED, + Efl_Ui_Animation_View_Data *pd) +{ + Eina_Rect viewbox = efl_canvas_vg_object_viewbox_get(pd->vg); + + return EINA_SIZE2D(viewbox.w, viewbox.h); +} + +EOLIAN static void +_efl_ui_animation_view_auto_repeat_set(Eo *obj EINA_UNUSED, Efl_Ui_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 +_efl_ui_animation_view_auto_repeat_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->auto_repeat; +} + +EOLIAN static void +_efl_ui_animation_view_auto_play_set(Eo *obj EINA_UNUSED, Efl_Ui_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 +_efl_ui_animation_view_auto_play_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->auto_play; +} + +EOLIAN static Eina_Bool +_efl_ui_animation_view_play(Eo *obj, Efl_Ui_Animation_View_Data *pd) +{ + if (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY) return EINA_FALSE; + + Eina_Bool rewind = EINA_FALSE; + if (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK) rewind = EINA_TRUE; + + pd->play_back = EINA_FALSE; + pd->auto_play_pause = EINA_FALSE; + + if (!efl_file_loaded_get(obj)) return EINA_FALSE; + if (!pd->transit && !_ready_play(obj, pd)) return EINA_FALSE; + + if (pd->state == EFL_UI_ANIMATION_VIEW_STATE_STOP) + _transit_go_facade(obj, pd); + else if (rewind) + elm_transit_progress_value_set(pd->transit, pd->progress); + + return EINA_TRUE; +} + +EOLIAN static Eina_Bool +_efl_ui_animation_view_stop(Eo *obj, Efl_Ui_Animation_View_Data *pd) +{ + if (!pd->transit) return EINA_FALSE; + + if ((pd->state == EFL_UI_ANIMATION_VIEW_STATE_NOT_READY) || + (pd->state == EFL_UI_ANIMATION_VIEW_STATE_STOP)) + return EINA_FALSE; + + evas_object_vg_animated_frame_set(pd->vg, 0); + pd->progress = 0; + pd->state = EFL_UI_ANIMATION_VIEW_STATE_STOP; + evas_object_smart_callback_call(obj, SIG_PLAY_STOP, NULL); + elm_transit_del(pd->transit); + + return EINA_TRUE; +} + +EOLIAN static Eina_Bool +_efl_ui_animation_view_pause(Eo *obj, Efl_Ui_Animation_View_Data *pd) +{ + if (!pd->transit) return EINA_FALSE; + + if ((pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY) || + (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK)) + { + elm_transit_paused_set(pd->transit, EINA_TRUE); + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PAUSE; + pd->auto_play_pause = EINA_FALSE; + evas_object_smart_callback_call(obj, SIG_PLAY_PAUSE, NULL); + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EOLIAN static Eina_Bool +_efl_ui_animation_view_resume(Eo *obj, Efl_Ui_Animation_View_Data *pd) +{ + if (!pd->transit) return EINA_FALSE; + + if (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PAUSE) + { + elm_transit_paused_set(pd->transit, EINA_FALSE); + if (pd->play_back) + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK; + else + pd->state = EFL_UI_ANIMATION_VIEW_STATE_PLAY; + pd->auto_play_pause = EINA_FALSE; + + evas_object_smart_callback_call(obj, SIG_PLAY_RESUME, NULL); + + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EOLIAN static Eina_Bool +_efl_ui_animation_view_play_back(Eo *obj, Efl_Ui_Animation_View_Data *pd) +{ + if (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY_BACK) return EINA_FALSE; + + Eina_Bool rewind = EINA_FALSE; + if (pd->state == EFL_UI_ANIMATION_VIEW_STATE_PLAY) rewind = EINA_TRUE; + + pd->play_back = EINA_TRUE; + pd->auto_play_pause = EINA_FALSE; + + if (!efl_file_loaded_get(obj)) return EINA_FALSE; + if (!pd->transit && !_ready_play(obj, pd)) return EINA_FALSE; + + if (pd->state == EFL_UI_ANIMATION_VIEW_STATE_STOP) + { + if (pd->progress == 0) pd->progress = 1.0; + _transit_go_facade(obj, pd); + } + else if (rewind) + elm_transit_progress_value_set(pd->transit, 1 - pd->progress); + + return EINA_TRUE; +} + +EOLIAN static Eina_Bool +_efl_ui_animation_view_speed_set(Eo *obj EINA_UNUSED, Efl_Ui_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 +_efl_ui_animation_view_progress_set(Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd, double progress) +{ + if (progress < 0) progress = 0; + else if (progress > 1) progress = 1; + if (pd->progress == progress) return; + + pd->progress = progress; + + if (pd->frame_cnt > 0) + evas_object_vg_animated_frame_set(pd->vg, (int) ((pd->frame_cnt - 1) * progress)); + + if (pd->transit) + { + if (pd->play_back) + elm_transit_progress_value_set(pd->transit, 1 - progress); + else + elm_transit_progress_value_set(pd->transit, progress); + } +} + +EOLIAN static double +_efl_ui_animation_view_progress_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->progress; +} + +EOLIAN static void +_efl_ui_animation_view_frame_set(Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd, int frame_num) +{ + efl_ui_animation_view_progress_set(obj, (double) frame_num / (double) (evas_object_vg_animated_frame_count_get(pd->vg) - 1)); +} + +EOLIAN static int +_efl_ui_animation_view_frame_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + double progress = (pd->progress * (pd->max_progress - pd->min_progress)) + pd->min_progress; + return (int) ((double) (evas_object_vg_animated_frame_count_get(pd->vg) - 1) * progress); +} + +EOLIAN static double +_efl_ui_animation_view_speed_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->speed; +} + +EOLIAN static double +_efl_ui_animation_view_duration_time_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->frame_duration; +} + +EOLIAN static Eina_Size2D +_efl_ui_animation_view_default_view_size_get(const Eo *obj EINA_UNUSED, + Efl_Ui_Animation_View_Data *pd EINA_UNUSED) +{ + return efl_canvas_vg_object_default_size_get(pd->vg); +} + +EOLIAN static Efl_Ui_Animation_View_State +_efl_ui_animation_view_state_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->state; +} + +EOLIAN static Eina_Bool +_efl_ui_animation_view_is_playing_back(Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->play_back; +} + +EOLIAN static int +_efl_ui_animation_view_frame_count_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return efl_gfx_frame_controller_frame_count_get(pd->vg); +} + +EOLIAN static void +_efl_ui_animation_view_min_progress_set(Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd, double min_progress) +{ + if (min_progress < 0.0 || min_progress > 1.0 || min_progress > pd->max_progress) return; + + pd->min_progress = min_progress; + _update_frame_duration(pd); +} + +EOLIAN static double +_efl_ui_animation_view_min_progress_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->min_progress; +} + +EOLIAN static void +_efl_ui_animation_view_max_progress_set(Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd, double max_progress) +{ + if (max_progress < 0.0 || max_progress > 1.0 || max_progress < pd->min_progress) return; + + pd->max_progress = max_progress; + _update_frame_duration(pd); +} + +EOLIAN static double +_efl_ui_animation_view_max_progress_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->max_progress; +} + +EOLIAN static void +_efl_ui_animation_view_min_frame_set(Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd, int min_frame) +{ + int frame_count = evas_object_vg_animated_frame_count_get(pd->vg); + if (min_frame < 0) min_frame = 0; + else + { + int max_frame = (frame_count - 1) * pd->max_progress; + if (min_frame > max_frame) min_frame = max_frame; + } + + pd->min_progress = (double)min_frame / (double)(frame_count - 1); + _update_frame_duration(pd); +} + +EOLIAN static int +_efl_ui_animation_view_min_frame_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->min_progress * (evas_object_vg_animated_frame_count_get(pd->vg) - 1); +} + +EOLIAN static void +_efl_ui_animation_view_max_frame_set(Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd, int max_frame) +{ + int frame_count = evas_object_vg_animated_frame_count_get(pd->vg); + if (max_frame > frame_count - 1) max_frame = frame_count - 1; + else + { + int min_frame = (frame_count - 1) * pd->min_progress; + if (min_frame > max_frame) max_frame = min_frame; + } + + pd->max_progress = (double)max_frame / (double)(frame_count - 1); + _update_frame_duration(pd); +} + +EOLIAN static int +_efl_ui_animation_view_max_frame_get(const Eo *obj EINA_UNUSED, Efl_Ui_Animation_View_Data *pd) +{ + return pd->max_progress * (evas_object_vg_animated_frame_count_get(pd->vg) - 1); +} + +EAPI Elm_Animation_View* +elm_animation_view_add(Evas_Object *parent) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); + return elm_legacy_add(MY_CLASS, parent); +} + +EAPI Eina_Bool +elm_animation_view_file_set(Elm_Animation_View *obj, const char *file, const char *key) +{ + return efl_file_simple_load(obj, file, key); +} + +EAPI Elm_Animation_View_State +elm_animation_view_state_get(Elm_Animation_View *obj) +{ + return efl_ui_animation_view_state_get(obj); +} + +/* Internal EO APIs and hidden overrides */ + +#define EFL_UI_ANIMATION_VIEW_EXTRA_OPS \ + EFL_CANVAS_GROUP_ADD_DEL_OPS(efl_ui_animation_view) + +#include "efl_ui_animation_view_eo.legacy.c" +#include "efl_ui_animation_view.eo.c" diff --git a/src/lib/elementary/efl_ui_animation_view.eo b/src/lib/elementary/efl_ui_animation_view.eo new file mode 100644 index 0000000000..67321e7c97 --- /dev/null +++ b/src/lib/elementary/efl_ui_animation_view.eo @@ -0,0 +1,281 @@ + +enum Efl.Ui.Animation_View_State +{ + not_ready, [[Animation is not ready to play. (Probably, it didn't file set yet or failed to read file.]] + play, [[Animation is on playing. see @Efl.Ui.Animation_View.play]] + play_back, [[Animation is on playing back (rewinding). see @Efl.Ui.Animation_View.play_back]] + pause, [[Animation has been paused. To continue animation, call @Efl.Ui.Animation_View.resume. see @Efl.Ui.Animation_View.pause]] + stop [[Animation view successfully loaded a file then readied for playing. Otherwise after finished animation or stopped forcely by request. see @Efl.Ui.Animation_View.stop]] +} + +class @beta Efl.Ui.Animation_View extends Efl.Ui.Widget implements Efl.Gfx.View, Efl.File +{ + [[Elementary Animation view class. + Animation view 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. + ]] + event_prefix: efl_ui_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. + + $true Enable auto play mode, disable otherwise. + + Warning: This auto play will be only affected to the next animation source. + So must be called before setting animation file. + ]] + set { + } + get { + } + values { + auto_play: bool; [[Auto play mode, Default value is $false]] + } + } + @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. + + $true Enable auto play mode, disable otherwise. + ]] + set { + } + get { + } + values { + auto_repeat: bool; [[Loop mode, Defalut is $false.]] + } + } + @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. + + $true when it's successful. $false otherwise. + + Warning: speed must be greater than zero. + ]] + set { + return: bool; + } + get { + } + values { + speed: double; [[ Speed factor. Default value is 1.0]] + } + } + @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 progress { + [[Set current progress position of animation view object. + + When you required to jump on a certain frame instantly, + you can change current position by using this API. + + Warning: The range of progress is 0 ~ 1. + ]] + set { + } + get { + } + values { + progress: double; [[Progress position. Value must be 0 ~ 1.]] + } + } + @property frame { + [[Number of current frame. + + Ranges from 0 to @.frame_count - 1. + ]] + set { + } + get { + } + values { + frame_num: int; [[Current frame number.]] + } + } + 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.]] + } + @property default_view_size { + [[The default view size that specified from vector resource. + ]] + get { + } + values { + size: Eina.Size2D; + } + } + @property state { + [[Current animation view state. + see @Efl.Ui.Animation_View_State + ]] + get{ + } + values { + state: Efl.Ui.Animation_View_State; [[Current animation view state]] + } + } + is_playing_back { + [[Returns the status whether current animation is on playing forward or backward. + warning: If animation view is not on playing, it will return $false. + ]] + return: bool; [[$true, if animation on playing back, $false otherwise.]] + } + @property frame_count { + [[The index of end frame of the animation view, if it's animated. + note : frame number starts with 0. + ]] + get { + } + values { + frame_count: int; [[The number of frames. 0, if it's not animated.]] + } + } + @property min_progress { + [[The start progress of the play. + Default value is 0. + ]] + set { + } + get { + } + values { + min_progress: double; [[The minimum progress. Value must be 0 ~ 1.]] + } + } + @property max_progress { + [[The last progress of the play. + Default value is 1. + ]] + set { + } + get { + } + values { + max_progress: double; [[The maximum progress. Value must be 0 ~ 1.]] + } + } + @property min_frame { + [[The start frame of the play. + Default value is 0. + ]] + set { + } + get { + } + values { + min_frame: int; [[The minimum frame for play. Value must be 0 ~ @.max_frame]] + } + } + @property max_frame { + [[The last frame of the play. + Default value is @.frame_count - 1 + ]] + set { + } + get { + } + values { + max_frame: int; [[The maximum frame for play. Value must be @.min_frame ~ (@.frame_count - 1)]] + } + } + + } + implements { + Efl.Object.constructor; + Efl.Object.destructor; + Efl.File.load; + Efl.File.unload; + Efl.Gfx.Entity.visible { set; } + Efl.Gfx.Entity.position { set; } + Efl.Gfx.Entity.size { set; } + Efl.Gfx.View.view_size { set; get; } + } + events { + play,start: void; [[Called when animation is just started]] + play,repeat: void; [[Called when animation is just repeated]] + play,done: void; [[Called when animation is just finished]] + play,pause: void; [[Called when animation is just paused]] + play,resume: void; [[Called when animation is just resumed]] + play,stop: void; [[Called when animation is just stopped]] + play,update: void; [[Called when animation is just updated]] + } +} diff --git a/src/lib/elementary/efl_ui_animation_view.h b/src/lib/elementary/efl_ui_animation_view.h new file mode 100644 index 0000000000..9241791bf4 --- /dev/null +++ b/src/lib/elementary/efl_ui_animation_view.h @@ -0,0 +1,33 @@ +/** + * @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 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 + */ +#ifndef EFL_NOLEGACY_API_SUPPORT +#include "efl_ui_animation_view_legacy.h" +#endif +/** + * @} + */ diff --git a/src/lib/elementary/efl_ui_animation_view_eo.legacy.c b/src/lib/elementary/efl_ui_animation_view_eo.legacy.c new file mode 100644 index 0000000000..87ed3232d1 --- /dev/null +++ b/src/lib/elementary/efl_ui_animation_view_eo.legacy.c @@ -0,0 +1,162 @@ + +EAPI void +elm_animation_view_auto_play_set(Efl_Ui_Animation_View *obj, Eina_Bool auto_play) +{ + efl_ui_animation_view_auto_play_set(obj, auto_play); +} + +EAPI Eina_Bool +elm_animation_view_auto_play_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_auto_play_get(obj); +} + +EAPI void +elm_animation_view_auto_repeat_set(Efl_Ui_Animation_View *obj, Eina_Bool auto_repeat) +{ + efl_ui_animation_view_auto_repeat_set(obj, auto_repeat); +} + +EAPI Eina_Bool +elm_animation_view_auto_repeat_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_auto_repeat_get(obj); +} + +EAPI Eina_Bool +elm_animation_view_speed_set(Efl_Ui_Animation_View *obj, double speed) +{ + return efl_ui_animation_view_speed_set(obj, speed); +} + +EAPI double +elm_animation_view_speed_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_speed_get(obj); +} + +EAPI double +elm_animation_view_duration_time_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_duration_time_get(obj); +} + +EAPI void +elm_animation_view_progress_set(Efl_Ui_Animation_View *obj, double progress) +{ + efl_ui_animation_view_progress_set(obj, progress); +} + +EAPI double +elm_animation_view_progress_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_progress_get(obj); +} + +EAPI void +elm_animation_view_frame_set(Efl_Ui_Animation_View *obj, int frame_num) +{ + efl_ui_animation_view_frame_set(obj, frame_num); +} + +EAPI int +elm_animation_view_frame_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_frame_get(obj); +} + +EAPI Eina_Bool +elm_animation_view_play(Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_play(obj); +} + +EAPI Eina_Bool +elm_animation_view_play_back(Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_play_back(obj); +} + +EAPI Eina_Bool +elm_animation_view_pause(Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_pause(obj); +} + +EAPI Eina_Bool +elm_animation_view_resume(Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_resume(obj); +} + +EAPI Eina_Bool +elm_animation_view_stop(Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_stop(obj); +} + +EAPI Eina_Size2D +elm_animation_view_default_size_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_default_view_size_get(obj); +} + +EAPI Eina_Bool +elm_animation_view_is_playing_back(Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_is_playing_back(obj); +} + +EAPI int +elm_animation_view_frame_count_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_frame_count_get(obj); +} + +EAPI void +elm_animation_view_min_progress_set(Efl_Ui_Animation_View *obj, double min_progress) +{ + efl_ui_animation_view_min_progress_set(obj, min_progress); +} + +EAPI double +elm_animation_view_min_progress_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_min_progress_get(obj); +} + +EAPI void +elm_animation_view_max_progress_set(Efl_Ui_Animation_View *obj, double max_progress) +{ + efl_ui_animation_view_max_progress_set(obj, max_progress); +} + +EAPI double +elm_animation_view_max_progress_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_max_progress_get(obj); +} + +EAPI void +elm_animation_view_min_frame_set(Efl_Ui_Animation_View *obj, int min_frame) +{ + efl_ui_animation_view_min_frame_set(obj, min_frame); +} + +EAPI int +elm_animation_view_min_frame_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_min_frame_get(obj); +} + +EAPI void +elm_animation_view_max_frame_set(Efl_Ui_Animation_View *obj, int max_frame) +{ + efl_ui_animation_view_max_frame_set(obj, max_frame); +} + +EAPI int +elm_animation_view_max_frame_get(const Efl_Ui_Animation_View *obj) +{ + return efl_ui_animation_view_max_frame_get(obj); +} diff --git a/src/lib/elementary/efl_ui_animation_view_eo.legacy.h b/src/lib/elementary/efl_ui_animation_view_eo.legacy.h new file mode 100644 index 0000000000..78dd2f1d5d --- /dev/null +++ b/src/lib/elementary/efl_ui_animation_view_eo.legacy.h @@ -0,0 +1,517 @@ +#ifndef _EFL_UI_ANIMATION_VIEW_EO_LEGACY_H_ +#define _EFL_UI_ANIMATION_VIEW_EO_LEGACY_H_ + +#ifndef _ELM_ANIMATION_VIEW_EO_CLASS_TYPE +#define _ELM_ANIMATION_VIEW_EO_CLASS_TYPE + +typedef Eo Elm_Animation_View; + +#endif + +#ifndef _ELM_ANIMATION_VIEW_EO_TYPES +#define _ELM_ANIMATION_VIEW_EO_TYPES + +/** + * @brief Defines the state of animation view + * + * @ingroup Elm_Animation_View + */ +typedef enum +{ + ELM_ANIMATION_VIEW_STATE_NOT_READY = 0, /**< Animation is not ready to + * play. (Probably, it didn't file + * set yet or failed to read file. + * + * @since 1.23 */ + ELM_ANIMATION_VIEW_STATE_PLAY, /**< Animation is on playing. see + * @ref elm_animation_view_play + * + * @since 1.23 */ + ELM_ANIMATION_VIEW_STATE_PLAY_BACK, /**< Animation is on playing back + * (rewinding). see + * @ref elm_animation_view_play_back + * + * @since 1.23 */ + ELM_ANIMATION_VIEW_STATE_PAUSE, /**< Animation has been paused. To continue + * animation, call + * @ref elm_animation_view_resume. see + * @ref elm_animation_view_pause + * + * @since 1.23 */ + 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 + * @ref elm_animation_view_stop + * + * @since 1.23 */ +} Elm_Animation_View_State; + + +#endif + +/** + * @brief Animation will be started automatically when it's possible. + * + * If @ref elm_animation_view_auto_play_get is @c true, animation will be + * started when it's readied. The condition of @c 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 setting animation file + * + * Set auto play mode of an animation view object. @c true Enable auto play + * mode, disable otherwise + * + * @param[in] obj The object. + * @param[in] auto_play Auto play mode, Default value is @c false + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI void elm_animation_view_auto_play_set(Elm_Animation_View *obj, Eina_Bool auto_play); + +/** + * @brief Animation will be started automatically when it's possible. + * + * If @ref elm_animation_view_auto_play_get is @c true, animation will be + * started when it's readied. The condition of @c 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 setting animation file + * + * Returns auto play mode of an animation view object. + * + * @param[in] obj The object. + * + * @return Auto play mode, Default value is @c false + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_auto_play_get(const Elm_Animation_View *obj); + +/** + * @brief Turn on/off animation looping. + * + * If @ref elm_animation_view_auto_repeat_get is @c true, it repeats animation + * when animation frame is reached to end. This auto repeat mode is valid to + * both play and play_back cases. + * + * Enable loop mode if @c true, disable otherwise. + * + * @param[in] obj The object. + * @param[in] auto_repeat Loop mode, Defalut is @c false. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI void elm_animation_view_auto_repeat_set(Elm_Animation_View *obj, Eina_Bool auto_repeat); + +/** + * @brief Turn on/off animation looping. + * + * If @ref elm_animation_view_auto_repeat_get is @c true, it repeats animation + * when animation frame is reached to end. This auto repeat mode is valid to + * both play and play_back cases. + * + * Returns auto repeat mode of an animation view object. + * + * @param[in] obj The object. + * + * @return Loop mode, Defalut is @c false. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_auto_repeat_get(const Elm_Animation_View *obj); + +/** + * @brief Control animation speed. + * + * Control animation speed by multiplying @c speed value. If you want to play + * animation double-time faster, you can give @c speed 2. If you want to play + * animation double-time slower, you can give @c speed 0.5. + * + * @warning speed must be greater than zero. + * + * @param[in] obj The object. + * @param[in] speed Speed factor. Default value is 1.0 + * + * @return @c true when it's successful. @c false otherwise. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_speed_set(Elm_Animation_View *obj, double speed); + +/** + * @brief Control animation speed. + * + * Control animation speed by multiplying @c speed value. If you want to play + * animation double-time faster, you can give @c speed 2. If you want to play + * animation double-time slower, you can give @c speed 0.5. + * + * @warning speed must be greater than zero. + * + * Returns current animation speed of an animation view object. + * + * @param[in] obj The object. + * + * @return Speed factor. Default value is 1.0 + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI double elm_animation_view_speed_get(const Elm_Animation_View *obj); + +/** + * @brief 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. + * + * Returns current duration of an animation in seconds. + * + * @param[in] obj The object. + * + * @return duration time in the seconds + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI double elm_animation_view_duration_time_get(const Elm_Animation_View *obj); + +/** + * @brief Set current progress position of animation view object. + * + * When you required to jump on a certain frame instantly, you can change + * current position by using this API. + * + * @warning The range of progress is 0 ~ 1. + * + * Set the current progress position of an animation view object. + * + * @param[in] obj The object. + * @param[in] progress Progress position. Value must be 0 ~ 1. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI void elm_animation_view_progress_set(Elm_Animation_View *obj, double progress); + +/** + * @brief Set current progress position of animation view object. + * + * When you required to jump on a certain frame instantly, you can change + * current position by using this API. + * + * @warning The range of progress is 0 ~ 1. + * + * Returns current progress position of an animation view object. + * + * @param[in] obj The object. + * + * @return Progress position. Value must be 0 ~ 1. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI double elm_animation_view_progress_get(const Elm_Animation_View *obj); + +/** + * @brief Number of current frame. + * + * Ranges from 0 to @ref elm_animation_view_frame_count_get - 1. + * + * Set the current frame of an animation view object. + * + * @param[in] obj The object. + * @param[in] frame_num Current frame number. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI void elm_animation_view_frame_set(Elm_Animation_View *obj, int frame_num); + +/** + * @brief Number of current frame. + * + * Ranges from 0 to @ref elm_animation_view_frame_count_get - 1. + * + * Returns the current frame of an animation view object. + * + * @param[in] obj The object. + * + * @return Current frame number. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI int elm_animation_view_frame_get(const Elm_Animation_View *obj); + +/** + * @brief 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. + * + * @param[in] obj The object. + * + * @return @c true when it's successful. @c false otherwise. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_play(Elm_Animation_View *obj); + +/** + * @brief 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. + * + * @param[in] obj The object. + * + * @return @c true when it's successful. @c false otherwise. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_play_back(Elm_Animation_View *obj); + +/** + * @brief 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. + * + * @param[in] obj The object. + * + * @return @c true when it's successful. @c false otherwise. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_pause(Elm_Animation_View *obj); + +/** + * @brief Resume paused animation to continue animation. + * + * @warning This resume must be called on animation paused status. + * + * @param[in] obj The object. + * + * @return @c true when it's successful. @c false otherwise. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_resume(Elm_Animation_View *obj); + +/** + * @brief 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. + * + * @param[in] obj The object. + * + * @return @c true when it's successful. @c false otherwise. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_stop(Elm_Animation_View *obj); + +/** Get the default view size that specified from vector resource. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Size2D elm_animation_view_default_size_get(const Elm_Animation_View *obj); + + +/** + * @brief Returns the status whether current animation is on playing forward or + * backward. warning: If animation view is not on playing, it will return + * @c false. + * + * @param[in] obj The object. + * + * @return @c true, if animation on playing back, @c false otherwise. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI Eina_Bool elm_animation_view_is_playing_back(Elm_Animation_View *obj); + +/** + * @brief Get the index of end frame of the animation view, if it's animated. + * note : frame number starts with 0. + * + * @param[in] obj The object. + * + * @return The number of frames. 0, if it's not animated. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI int elm_animation_view_frame_count_get(const Elm_Animation_View *obj); + +/** + * @brief The start progress of the play. Default value is 0. + * + * Set start progress of an animation object. + * + * @param[in] obj The object. + * @param[in] min_progress The minimum progress. Value must be 0 ~ 1. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI void elm_animation_view_min_progress_set(Elm_Animation_View *obj, double min_progress); + +/** + * @brief The start progress of the play. Default value is 0. + * + * Returns start progress of an animation object. + * + * @param[in] obj The object. + * + * @return The minimum progress. Value must be 0 ~ 1. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI double elm_animation_view_min_progress_get(const Elm_Animation_View *obj); + +/** + * @brief The last progress of the play. Default value is 1. + * + * Set last progress of an animation object. + * + * @param[in] obj The object. + * @param[in] max_progress The maximum progress. Value must be 0 ~ 1. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI void elm_animation_view_max_progress_set(Elm_Animation_View *obj, double max_progress); + +/** + * @brief The last progress of the play. Default value is 1. + * + * Returns last progress of an animation object. + * + * @param[in] obj The object. + * + * @return The maximum progress. Value must be 0 ~ 1. + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI double elm_animation_view_max_progress_get(const Elm_Animation_View *obj); + +/** + * @brief The start frame of the play. Default value is 0. + * + * Set minimum frame of an animation object. + * + * @param[in] obj The object. + * @param[in] min_frame The minimum frame for play. Value must be 0 ~ + * @ref elm_animation_view_max_frame_get + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI void elm_animation_view_min_frame_set(Elm_Animation_View *obj, int min_frame); + +/** + * @brief The start frame of the play. Default value is 0. + * + * Returns minimum frame of an animation object. + * + * @param[in] obj The object. + * + * @return The minimum frame for play. Value must be 0 ~ + * @ref elm_animation_view_max_frame_get + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI int elm_animation_view_min_frame_get(const Elm_Animation_View *obj); + +/** + * @brief The last frame of the play. Default value is + * @ref elm_animation_view_frame_count_get - 1 + * + * Set maximum frame of an animation object. + * + * @param[in] obj The object. + * @param[in] max_frame The maximum frame for play. Value must be + * @ref elm_animation_view_min_frame_get ~ (@ref elm_animation_view_frame_count_get - 1) + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI void elm_animation_view_max_frame_set(Elm_Animation_View *obj, int max_frame); + +/** + * @brief The last frame of the play. Default value is + * @ref elm_animation_view_frame_count_get - 1 + * + * Returns maximum frame of an animation object. + * + * @param[in] obj The object. + * + * @return The maximum frame for play. Value must be + * @ref elm_animation_view_min_frame_get ~ (@ref elm_animation_view_frame_count_get - 1) + * + * @since 1.23 + * + * @ingroup Elm_Animation_View + */ +EAPI int elm_animation_view_max_frame_get(const Elm_Animation_View *obj); + +#endif diff --git a/src/lib/elementary/efl_ui_animation_view_legacy.h b/src/lib/elementary/efl_ui_animation_view_legacy.h new file mode 100644 index 0000000000..95054168c5 --- /dev/null +++ b/src/lib/elementary/efl_ui_animation_view_legacy.h @@ -0,0 +1,49 @@ + +#include "efl_ui_animation_view_eo.legacy.h" + +/** + * 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.23 + */ +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.23 +*/ +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.23 + */ +EAPI Elm_Animation_View_State elm_animation_view_state_get(Elm_Animation_View *obj); + diff --git a/src/lib/elementary/efl_ui_animation_view_private.h b/src/lib/elementary/efl_ui_animation_view_private.h new file mode 100644 index 0000000000..0de9b2afc8 --- /dev/null +++ b/src/lib/elementary/efl_ui_animation_view_private.h @@ -0,0 +1,41 @@ +#ifndef EFL_UI_ANIMATION_VIEW_PRIVATE_H +#define EFL_UI_ANIMATION_VIEW_PRIVATE_H + +#include "Elementary.h" +#include "efl_ui_animation_view.eo.h" + +typedef struct _Efl_Ui_Animation_View_Data Efl_Ui_Animation_View_Data; + +struct _Efl_Ui_Animation_View_Data +{ + Eo* vg; //Evas_Object_Vg + Efl_Ui_Animation_View_State state; + Elm_Transit *transit; + Eina_Stringshare *file; + double speed; + double progress; + double frame_cnt; + int repeat_times; + double frame_duration; + double min_progress; + double max_progress; + + Eina_Bool play_back : 1; + Eina_Bool auto_play : 1; + Eina_Bool auto_play_pause: 1; + Eina_Bool auto_repeat : 1; +}; + +#define EFL_UI_ANIMATION_VIEW_DATA_GET(o, sd) \ + Efl_Ui_Animation_View_Data * sd = efl_data_scope_safe_get(o, EFL_UI_ANIMATION_VIEW_CLASS) + +#define EFL_UI_ANIMATION_VIEW_DATA_GET_OR_RETURN(o, ptr) \ + EFL_UI_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 diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index 0f0831687c..35fb166827 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -38,6 +38,7 @@ endforeach pub_eo_files = [ 'efl_ui_widget.eo', + 'efl_ui_animation_view.eo', 'efl_ui_bg.eo', 'efl_ui_button.eo', 'efl_ui_calendar.eo', @@ -298,6 +299,7 @@ elementary_headers_unstable = [ 'efl_ui_widget_flip.h', 'elm_widget_flipselector.h', 'efl_ui_widget_frame.h', + 'efl_ui_animation_view_private.h', 'elm_widget_gengrid.h', 'elm_widget_genlist.h', 'elm_widget_glview.h', @@ -402,6 +404,8 @@ elementary_pub_headers = [ 'elc_naviframe_common.h', 'elc_popup.h', 'elc_popup_legacy.h', + 'efl_ui_animation_view.h', + 'efl_ui_animation_view_legacy.h', 'elm_access.h', 'elm_actionslider.h', 'elm_actionslider_legacy.h', @@ -591,6 +595,7 @@ elementary_pub_headers = [ 'elm_win_legacy.h', 'elm_helper.h', 'elm_part_helper.h', + 'efl_ui_animation_view_eo.legacy.h', 'efl_ui_bg_eo.legacy.h', 'efl_ui_bg_legacy_eo.legacy.h', 'efl_ui_button_eo.legacy.h', @@ -730,6 +735,7 @@ elementary_src = [ 'elc_popup.c', 'elc_scrolled_entry.c', 'elm_access.c', + 'efl_ui_animation_view.c', 'elm_actionslider.c', 'elm_atspi_app_object.c', 'elm_atspi_bridge.c', diff --git a/src/tests/elementary/spec/efl_test_gfx_view.c b/src/tests/elementary/spec/efl_test_gfx_view.c new file mode 100644 index 0000000000..fc411138b6 --- /dev/null +++ b/src/tests/elementary/spec/efl_test_gfx_view.c @@ -0,0 +1,39 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include <Efl_Ui.h> +#include "efl_ui_spec_suite.h" +#include "suite_helpers.h" + +/* spec-meta-start + {"test-interface":"Efl.Gfx.View", + "test-widgets": ["Efl.Ui.Animation_View"]} + spec-meta-end */ + +EFL_START_TEST(view_size) +{ +#define TUPLE_CHECK(W, H) \ + do { \ + Eina_Size2D sz; \ + efl_gfx_view_size_set(widget, EINA_SIZE2D(W, H)); \ + sz = efl_gfx_view_size_get(widget); \ + ck_assert(W == sz.w); \ + ck_assert(H == sz.h); \ + } while(0); + + TUPLE_CHECK(100, 100); + TUPLE_CHECK(100, 200); + TUPLE_CHECK(200, 100); + TUPLE_CHECK(800, 700); + TUPLE_CHECK(10, 50); + +#undef TUPLE_CHECK +} +EFL_END_TEST + +void +efl_gfx_view_behavior_test(TCase *tc) +{ + tcase_add_test(tc, view_size); +} diff --git a/src/tests/elementary/spec/efl_ui_spec_suite.h b/src/tests/elementary/spec/efl_ui_spec_suite.h index 009e4e0ec5..b840adcefd 100644 --- a/src/tests/elementary/spec/efl_ui_spec_suite.h +++ b/src/tests/elementary/spec/efl_ui_spec_suite.h @@ -14,6 +14,7 @@ void efl_pack_behavior_test(TCase *tc); void efl_pack_linear_behavior_test(TCase *tc); void efl_content_behavior_test(TCase *tc); void efl_gfx_arrangement_behavior_test(TCase *tc); +void efl_gfx_view_behavior_test(TCase *tc); void efl_ui_clickable_behavior_test(TCase *tc); void efl_ui_format_behavior_test(TCase *tc); void efl_ui_range_display_behavior_test(TCase *tc); diff --git a/src/tests/elementary/spec/meson.build b/src/tests/elementary/spec/meson.build index 0da3494dfd..33be7aa013 100644 --- a/src/tests/elementary/spec/meson.build +++ b/src/tests/elementary/spec/meson.build @@ -11,6 +11,7 @@ efl_ui_suite_behavior_test_files = files([ 'efl_test_single_selectable.c', 'efl_test_multi_selectable.c', 'efl_test_selectable.c', + 'efl_test_gfx_view.c', ]) efl_ui_suite_behavior_src = files([ --