diff --git a/src/examples/evas/efl-canvas-animation.c b/src/examples/evas/efl-canvas-animation.c new file mode 100644 index 0000000000..2cc2355956 --- /dev/null +++ b/src/examples/evas/efl-canvas-animation.c @@ -0,0 +1,179 @@ +/** + * Example of animation in efl canvas + * + * You'll need at least one engine built for it (excluding the buffer + * one). See stdout/stderr for output. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#define WIDTH (640) +#define HEIGHT (480) + +struct example_data +{ + Ecore_Evas *ee; + Evas *evas; + Evas_Object *bg, *scale; + double current_speed; +}; + +static struct example_data d; + +static Evas_Object * /* new rectangle to be put in the box */ +_new_rectangle_add(Evas *e) +{ + Efl_Canvas_Rectangle *rect = efl_add(EFL_CANVAS_RECTANGLE_CLASS, e); + + efl_gfx_entity_size_set(rect, EINA_SIZE2D(10, 10)); + efl_gfx_color_set(rect, 0, 255, 0, 255); + efl_gfx_entity_visible_set(rect, EINA_TRUE); + + return rect; +} + +/* use the following commands to interact with this example - 'h' is + * the key for help */ +static void +_on_keydown(void *data EINA_UNUSED, const Efl_Event *ev) +{ + if (strcmp(efl_input_key_sym_get(ev->info) , "r") == 0) + { + Efl_Canvas_Animation *animation = efl_canvas_object_animation_get(d.scale); + double current_pos = efl_canvas_object_animation_progress_get(d.scale); + d.current_speed *= -1; + efl_canvas_object_animation_start(d.scale, animation, d.current_speed, 1.0 - current_pos); + } + if (strcmp(efl_input_key_sym_get(ev->info), "p") == 0) + { + efl_canvas_object_animation_pause_set(d.scale, !efl_canvas_object_animation_pause_get(d.scale)); + } +} + +static void +_on_delete(Ecore_Evas *ee EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static void /* adjust canvas' contents on resizes */ +_canvas_resize_cb(Ecore_Evas *ee) +{ + int w, h; + + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + + efl_gfx_entity_geometry_set(d.bg, EINA_RECT(0, 0, w, h)); +} + +static void +print_help(void) +{ + printf("evas-animation example\n Press r to reverse the animation of the red rect.\n Press p to pause the animation of the red rect.\n"); +} + +int +main(void) +{ + if (!ecore_evas_init()) + return EXIT_FAILURE; + + /* this will give you a window with an Evas canvas under the first + * engine available */ + d.ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + if (!d.ee) + goto panic; + + print_help(); + + ecore_evas_name_class_set(d.ee, "Evas Animation example", "Evas Animation Example"); + ecore_evas_callback_delete_request_set(d.ee, _on_delete); + ecore_evas_callback_resize_set(d.ee, _canvas_resize_cb); + ecore_evas_show(d.ee); + + d.evas = ecore_evas_get(d.ee); + + d.bg = _new_rectangle_add(d.evas); + efl_gfx_color_set(d.bg, 255, 255, 255, 255); + efl_gfx_entity_visible_set(d.bg, EINA_TRUE); + efl_canvas_object_key_focus_set(d.bg, EINA_TRUE); + efl_event_callback_add(d.bg, EFL_EVENT_KEY_DOWN, _on_keydown, NULL); + + _canvas_resize_cb(d.ee); + + Evas_Object *scale_rect = _new_rectangle_add(d.evas); + efl_gfx_entity_geometry_set(scale_rect, EINA_RECT(50, 50, 50, 50)); + efl_canvas_object_animation_start(scale_rect, + efl_new(EFL_CANVAS_ANIMATION_SCALE_CLASS, + efl_animation_scale_set(efl_added, EINA_VECTOR2(1.0, 1.0), EINA_VECTOR2(3.0, 3.0), scale_rect, EINA_VECTOR2(0.5, 0.5)), + efl_animation_start_delay_set(efl_added, 5.0), + efl_animation_duration_set(efl_added, 2.0), + efl_animation_repeat_count_set(efl_added, EFL_ANIMATION_REPEAT_INFINITE) + ), + 1.0, 0.0); + + Evas_Object *scale_rect2 = _new_rectangle_add(d.evas); + efl_gfx_entity_geometry_set(scale_rect2, EINA_RECT(50, 200, 50, 50)); + efl_canvas_object_animation_start(scale_rect2, + efl_new(EFL_CANVAS_ANIMATION_SCALE_CLASS, + efl_animation_scale_set(efl_added, EINA_VECTOR2(1.0, 1.0), EINA_VECTOR2(3.0, 3.0), scale_rect2, EINA_VECTOR2(0.5, 0.5)), + efl_animation_duration_set(efl_added, 2.0), + efl_animation_repeat_count_set(efl_added, EFL_ANIMATION_REPEAT_INFINITE), + efl_animation_repeat_mode_set(efl_added, EFL_CANVAS_ANIMATION_REPEAT_MODE_REVERSE) + ), + 1.0, 0.0); + + Evas_Object *scale_rect3 = _new_rectangle_add(d.evas); + efl_gfx_entity_geometry_set(scale_rect3, EINA_RECT(50, 350, 50, 50)); + efl_canvas_object_animation_start(scale_rect3, + efl_new(EFL_CANVAS_ANIMATION_SCALE_CLASS, + efl_animation_scale_set(efl_added, EINA_VECTOR2(1.0, 1.0), EINA_VECTOR2(3.0, 3.0), scale_rect3, EINA_VECTOR2(0.5, 0.5)), + efl_animation_duration_set(efl_added, 2.0), + efl_animation_repeat_count_set(efl_added, 3), + efl_animation_repeat_mode_set(efl_added, EFL_CANVAS_ANIMATION_REPEAT_MODE_REVERSE) + ), + 1.0, 0.0); + + Evas_Object *scale_rect4 = _new_rectangle_add(d.evas); + efl_gfx_entity_geometry_set(scale_rect4, EINA_RECT(200, 50, 50, 50)); + efl_canvas_object_animation_start(scale_rect4, + efl_new(EFL_CANVAS_ANIMATION_SCALE_CLASS, + efl_animation_scale_set(efl_added, EINA_VECTOR2(1.0, 1.0), EINA_VECTOR2(3.0, 3.0), scale_rect4, EINA_VECTOR2(0.5, 0.5)), + efl_animation_duration_set(efl_added, 2.0), + efl_animation_final_state_keep_set(efl_added, EINA_TRUE) + ), + 1.0, 0.0); + + + Evas_Object *scale_rect5 = d.scale = _new_rectangle_add(d.evas); + efl_gfx_color_set(scale_rect5, 255, 0, 0, 255); + efl_gfx_entity_geometry_set(scale_rect5, EINA_RECT(200, 200, 50, 50)); + efl_canvas_object_animation_start(scale_rect5, + efl_new(EFL_CANVAS_ANIMATION_SCALE_CLASS, + efl_animation_scale_set(efl_added, EINA_VECTOR2(1.0, 1.0), EINA_VECTOR2(5.0, 5.0), scale_rect5, EINA_VECTOR2(0.5, 0.5)), + efl_animation_duration_set(efl_added, 5.0), + efl_animation_repeat_count_set(efl_added, EFL_ANIMATION_REPEAT_INFINITE) + ), + 1.0, 0.0); + d.current_speed = 1.0; + + ecore_main_loop_begin(); + ecore_evas_shutdown(); + return 0; + +panic: + fprintf(stderr, "error: Requires at least one Evas engine built and linked" + " to ecore-evas for this example to run properly.\n"); + return -2; +} + diff --git a/src/examples/evas/meson.build b/src/examples/evas/meson.build index 659f9a525e..93539e73b3 100644 --- a/src/examples/evas/meson.build +++ b/src/examples/evas/meson.build @@ -50,6 +50,7 @@ examples = [ 'evas-vg-batman', 'evas-vg-simple', 'evas-vg-json', + 'efl-canvas-animation', ] foreach example : examples diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h index 5a725cc205..13ecde563a 100644 --- a/src/lib/evas/Evas_Eo.h +++ b/src/lib/evas/Evas_Eo.h @@ -223,7 +223,7 @@ struct _Efl_Canvas_Object_Animation_Event #include "gesture/efl_gesture_events.eo.h" #include "canvas/efl_canvas_object.eo.h" - +#include "canvas/efl_canvas_object_animation.eo.h" #include "canvas/efl_canvas_animation.eo.h" #include "canvas/efl_canvas_animation_alpha.eo.h" #include "canvas/efl_canvas_animation_rotate.eo.h" diff --git a/src/lib/evas/canvas/efl_canvas_object.eo b/src/lib/evas/canvas/efl_canvas_object.eo index 785c4967cd..dbee3db658 100644 --- a/src/lib/evas/canvas/efl_canvas_object.eo +++ b/src/lib/evas/canvas/efl_canvas_object.eo @@ -11,7 +11,7 @@ struct Efl.Event_Animator_Tick { abstract Efl.Canvas.Object extends Efl.Loop_Consumer implements Efl.Gfx.Entity, Efl.Gfx.Color, Efl.Gfx.Stack, Efl.Input.Interface, Efl.Gfx.Hint, - Efl.Gfx.Mapping, Efl.Canvas.Pointer, Efl.Gesture.Events + Efl.Gfx.Mapping, Efl.Canvas.Pointer, Efl.Gesture.Events, Efl.Canvas.Object_Animation { [[Efl canvas object abstract class diff --git a/src/lib/evas/canvas/efl_canvas_object_animation.c b/src/lib/evas/canvas/efl_canvas_object_animation.c new file mode 100644 index 0000000000..b86912db60 --- /dev/null +++ b/src/lib/evas/canvas/efl_canvas_object_animation.c @@ -0,0 +1,197 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "evas_common_private.h" +#include "evas_private.h" +#include "efl_canvas_object_animation.eo.h" +#include + +#define MY_CLASS EFL_CANVAS_OBJECT_ANIMATION_MIXIN + + +typedef struct +{ + Efl_Canvas_Animation *animation; + double speed; + double progress; + double run_start_time; + double start_pos; + int remaining_repeats; + Efl_Loop_Timer *timer; + Eina_Bool pause_state : 1; +} Efl_Canvas_Object_Animation_Indirect_Data; + +typedef struct +{ + Efl_Canvas_Object_Animation_Indirect_Data *in; +} Efl_Canvas_Object_Animation_Data; + +static void _end(Efl_Canvas_Object_Animation *obj, Efl_Canvas_Object_Animation_Data *pd); + + +static void +_animator_cb(void *data, const Efl_Event *ev EINA_UNUSED) +{ + Eo *obj = data; + Efl_Canvas_Object_Animation_Data *pd = efl_data_scope_get(obj, MY_CLASS); + double duration, elapsed_time, vector, current; + + EINA_SAFETY_ON_NULL_RETURN(pd->in); + current = ecore_loop_time_get(); + EINA_SAFETY_ON_FALSE_RETURN(pd->in->run_start_time <= current); + + duration = efl_animation_duration_get(pd->in->animation) / pd->in->speed; + elapsed_time = current - pd->in->run_start_time; + vector = elapsed_time / duration; + + /* When animation player starts, _animator_cb() is called immediately so + * both elapsed time and progress are 0.0. + * Since it is the beginning of the animation if progress is 0.0, the + * following codes for animation should be executed. */ + if (pd->in->speed < 0.0) + vector += 1.0; + pd->in->progress = CLAMP(0.0, vector, 1.0); + + /* The previously applied map effect should be reset before applying the + * current map effect. Otherwise, the incrementally added map effects + * increase numerical error. */ + efl_gfx_mapping_reset(obj); + efl_animation_apply(pd->in->animation, pd->in->progress, obj); + + efl_event_callback_call(obj, EFL_CANVAS_OBJECT_ANIMATION_EVENT_ANIMATION_PROGRESS_UPDATED, &pd->in->progress); + + //Not end. Keep going. + if ((pd->in->speed < 0 && EINA_DBL_EQ(pd->in->progress, 0)) || + (pd->in->speed > 0 && EINA_DBL_EQ(pd->in->progress, 1.0))) + { + //Repeat animation + if ((efl_animation_repeat_count_get(pd->in->animation) == EFL_ANIMATION_REPEAT_INFINITE) || + (pd->in->remaining_repeats > 0)) + { + pd->in->remaining_repeats--; + + if (efl_animation_repeat_mode_get(pd->in->animation) == EFL_CANVAS_ANIMATION_REPEAT_MODE_REVERSE) + pd->in->speed *= -1; + + pd->in->run_start_time = current; + } + else + { + efl_canvas_object_animation_stop(obj); + } + } +} + +static void +_end(Efl_Canvas_Object_Animation *obj, Efl_Canvas_Object_Animation_Data *pd) +{ + EINA_SAFETY_ON_NULL_RETURN(pd->in); + efl_event_callback_del(obj, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, _animator_cb, obj); +} + +static void +_start(Efl_Canvas_Object_Animation *obj, Efl_Canvas_Object_Animation_Data *pd, double delay) +{ + EINA_SAFETY_ON_NULL_RETURN(pd->in); + pd->in->run_start_time = ecore_loop_time_get() - efl_animation_duration_get(pd->in->animation)*delay; + efl_event_callback_add(obj, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, _animator_cb, obj); + _animator_cb(obj, NULL); +} + +static Eina_Value +_start_fcb(Eo *o, void *data EINA_UNUSED, const Eina_Value v) +{ + Efl_Canvas_Object_Animation_Data *pd = efl_data_scope_safe_get(o, MY_CLASS); + if (!pd->in) return v; //animation was stopped before anything started + _start(o, pd, pd->in->start_pos); + return v; +} + +EOLIAN static Efl_Canvas_Animation* +_efl_canvas_object_animation_animation_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Object_Animation_Data *pd) +{ + if (!pd->in) return NULL; + return pd->in->animation; +} + +EOLIAN static double +_efl_canvas_object_animation_animation_progress_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Object_Animation_Data *pd) +{ + if (pd->in && pd->in->animation) + return (pd->in->speed < 0) ? fabs(1.0 - pd->in->progress) : pd->in->progress; + else + return -1.0; +} + +EOLIAN static void +_efl_canvas_object_animation_animation_pause_set(Eo *obj, Efl_Canvas_Object_Animation_Data *pd, Eina_Bool pause) +{ + EINA_SAFETY_ON_NULL_RETURN(pd->in); + + if (pd->in->pause_state == pause) return; + + if (pause) + _end(obj, pd); + else + _start(obj, pd,(pd->in->speed < 0) ? 1.0 - pd->in->progress : pd->in->progress); + pd->in->pause_state = pause; +} + +EOLIAN static Eina_Bool +_efl_canvas_object_animation_animation_pause_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Object_Animation_Data *pd) +{ + if (!pd->in) return EINA_FALSE; + + return pd->in->pause_state; +} + +EOLIAN static void +_efl_canvas_object_animation_animation_start(Eo *obj, Efl_Canvas_Object_Animation_Data *pd, Efl_Canvas_Animation *animation, double speed, double start_pos) +{ + Efl_Canvas_Object_Animation_Indirect_Data *in; + if (pd->in && pd->in->animation) + efl_canvas_object_animation_stop(obj); + EINA_SAFETY_ON_FALSE_RETURN(!pd->in); + in = pd->in = calloc(1, sizeof(Efl_Canvas_Object_Animation_Indirect_Data)); + + EINA_SAFETY_ON_NULL_RETURN(animation); + EINA_SAFETY_ON_FALSE_RETURN(start_pos >= 0.0 && start_pos <= 1.0); + EINA_SAFETY_ON_FALSE_RETURN(!EINA_DBL_EQ(speed, 0.0)); + EINA_SAFETY_ON_FALSE_RETURN(efl_playable_seekable_get(animation)); + + in->pause_state = EINA_FALSE; + in->animation = efl_ref(animation); + in->remaining_repeats = efl_animation_repeat_count_get(animation); // -1 because one run is already going on + in->speed = speed; + in->start_pos = start_pos; + efl_event_callback_call(obj, EFL_CANVAS_OBJECT_ANIMATION_EVENT_ANIMATION_CHANGED, in->animation); + + if (efl_animation_start_delay_get(animation) > 0.0) + { + Eina_Future *f = efl_loop_timeout(efl_loop_get(obj), efl_animation_start_delay_get(animation)); + + efl_future_then(obj, f, .success = _start_fcb); + } + else + _start(obj, pd, start_pos); +} + +EOLIAN static void +_efl_canvas_object_animation_animation_stop(Eo *obj, Efl_Canvas_Object_Animation_Data *pd) +{ + if (!pd->in) return; + + if (!efl_animation_final_state_keep_get(pd->in->animation)) + efl_gfx_mapping_reset(obj); + _end(obj, pd); + efl_unref(pd->in->animation); + pd->in->animation = NULL; + + efl_event_callback_call(obj, EFL_CANVAS_OBJECT_ANIMATION_EVENT_ANIMATION_CHANGED, pd->in->animation); + + free(pd->in); + pd->in = NULL; +} + +#include "efl_canvas_object_animation.eo.c" diff --git a/src/lib/evas/canvas/efl_canvas_object_animation.eo b/src/lib/evas/canvas/efl_canvas_object_animation.eo new file mode 100644 index 0000000000..49146a6b81 --- /dev/null +++ b/src/lib/evas/canvas/efl_canvas_object_animation.eo @@ -0,0 +1,60 @@ +mixin @beta Efl.Canvas.Object_Animation requires Efl.Object +{ + methods { + @property animation { + [[The animation that is currently played on the canvas object. + + $null in case that there is no animation running.]] + get { + + } + values { + animation : Efl.Canvas.Animation; [[The animation which is currently applied on this object.]] + } + } + @property animation_progress { + [[The current progress of the animation, between 0.0 and 1.0. + + Even if the animation is going backwards (speed < 0.0). the progress will still go from 0.0 to 1.0. + + If there is no animation going on, this will return -1.0. + ]] + get { + + } + values { + progress : double; [[The progress the animation applying is currently in.]] + } + } + @property animation_pause { + [[Pause the animation + + The animation will not be unset. When $pause is unset, the animation will be resumed at the same progress it has right now. + ]] + values { + pause : bool; + } + } + animation_start { + [[Start a new animation. + + If there is a animation going on, this is stopped. The previous @.animation object will be replaced. The lifetime is adjusted accordingly. + ]] + params { + animation : Efl.Canvas.Animation @move; [[The animation to start. When not needed anymore, the reference that was passed is given up.]] + speed : double; [[The speed of the playback. `1.0` is normal playback. Negative values mean backward playback.]] + starting_progress : double; [[The progress to start, must be between 0.0 and 1.0.]] + } + } + animation_stop { + [[Stop the animation. + + After this call, @.animation will return $null. The reference that was taken during @.animation_start will be given up on. + ]] + } + } + events { + animation,changed: Efl.Canvas.Animation; [[The animation object got changed.]] + animation_progress,updated : double; [[The animation progress got changed.]] + } +} diff --git a/src/lib/evas/canvas/meson.build b/src/lib/evas/canvas/meson.build index 1edaeca69e..c13d3335a7 100644 --- a/src/lib/evas/canvas/meson.build +++ b/src/lib/evas/canvas/meson.build @@ -56,6 +56,7 @@ pub_eo_files = [ 'efl_gfx_mapping.eo', 'efl_canvas_event_grabber.eo', 'efl_canvas_text.eo', + 'efl_canvas_object_animation.eo', ] evas_canvas_eo_files = pub_eo_files @@ -207,6 +208,7 @@ evas_src += files([ 'evas_canvas3d_primitive.c', 'evas_canvas3d_node_callback.h', 'evas_canvas3d_eet.c', + 'efl_canvas_object_animation.c', ]) evas_include_directories += include_directories('.') diff --git a/src/tests/evas/evas_test_object.c b/src/tests/evas/evas_test_object.c index d2de52a58a..7024488916 100644 --- a/src/tests/evas/evas_test_object.c +++ b/src/tests/evas/evas_test_object.c @@ -5,10 +5,17 @@ #include #include +#define EFL_LOOP_PROTECTED //needed to set the loop time, we need that to simulate time passing for animation,tick +#include #include "evas_suite.h" #include "evas_tests_helpers.h" +static int called_changed; +static Efl_Canvas_Animation *animation_changed_ev; +static int called_running; +static double animation_running_position; + EFL_START_TEST(evas_object_various) { Evas *evas = EVAS_TEST_INIT_EVAS(); @@ -51,8 +58,159 @@ EFL_START_TEST(evas_object_freeze_events) } EFL_END_TEST +EFL_START_TEST(evas_object_animation_simple) +{ + Evas *evas = EVAS_TEST_INIT_EVAS(); + Evas_Object *obj = evas_object_rectangle_add(evas); + Efl_Canvas_Animation *animation = efl_add(EFL_CANVAS_ANIMATION_CLASS, evas); + + ck_assert_ptr_eq(efl_canvas_object_animation_get(obj) , NULL); + ck_assert(EINA_DBL_EQ(efl_canvas_object_animation_progress_get(obj), -1.0)); + + efl_canvas_object_animation_start(obj, animation, 1.0, 0.0); + ck_assert_ptr_eq(efl_canvas_object_animation_get(obj) , animation); + ck_assert(EINA_DBL_EQ(efl_canvas_object_animation_progress_get(obj), 0.0)); + + efl_canvas_object_animation_stop(obj); + ck_assert_ptr_eq(efl_canvas_object_animation_get(obj) , NULL); + ck_assert(EINA_DBL_EQ(efl_canvas_object_animation_progress_get(obj), -1.0)); + + efl_canvas_object_animation_start(obj, animation, 1.0, 0.0); + efl_canvas_object_animation_stop(obj); + + efl_canvas_object_animation_start(obj, animation, -1.0, 1.0); + efl_canvas_object_animation_stop(obj); + efl_canvas_object_animation_stop(obj); +} +EFL_END_TEST + +EFL_START_TEST(evas_object_animation_progress) +{ + Evas *evas = EVAS_TEST_INIT_EVAS(); + Evas_Object *obj = evas_object_rectangle_add(evas); + Efl_Canvas_Animation *animation = efl_add(EFL_CANVAS_ANIMATION_CLASS, evas, efl_animation_duration_set(efl_added, 1.0)); + + efl_canvas_object_animation_start(obj, animation, 1.0, 0.0); + efl_loop_time_set(efl_main_loop_get(), efl_loop_time_get(efl_main_loop_get()) + 0.5); + efl_event_callback_call(obj, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, NULL); + ck_assert(EINA_DBL_EQ(efl_canvas_object_animation_progress_get(obj), 0.5)); + efl_canvas_object_animation_stop(obj); +} +EFL_END_TEST + +static inline void +_simulate_time_passing(Eo *obj, double start, double jump) +{ + efl_loop_time_set(efl_main_loop_get(), start + jump); + efl_event_callback_call(obj, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, NULL); +} + +static inline void +_simulate_assert_time_passing(Eo *obj, double start, double jump, double expected_position) +{ + _simulate_time_passing(obj, start, jump); + ck_assert_int_eq((efl_canvas_object_animation_progress_get(obj)-expected_position)*10000, 0); +} + +EFL_START_TEST(evas_object_animation_pause) +{ + Evas *evas = EVAS_TEST_INIT_EVAS(); + Evas_Object *obj = evas_object_rectangle_add(evas); + double start = efl_loop_time_get(efl_main_loop_get()); + Efl_Canvas_Animation *animation = efl_add(EFL_CANVAS_ANIMATION_CLASS, evas, efl_animation_duration_set(efl_added, 1.0)); + + efl_canvas_object_animation_start(obj, animation, 1.0, 0.0); + + _simulate_assert_time_passing(obj, start, 0.2, 0.2); + efl_canvas_object_animation_pause_set(obj, EINA_TRUE); + + _simulate_assert_time_passing(obj, start, 0.5, 0.2); + efl_canvas_object_animation_pause_set(obj, EINA_FALSE); + + _simulate_assert_time_passing(obj, start, 0.7, 0.4); + efl_canvas_object_animation_stop(obj); +} +EFL_END_TEST + +EFL_START_TEST(evas_object_animation_error) +{ + Evas *evas = EVAS_TEST_INIT_EVAS(); + Evas_Object *obj = evas_object_rectangle_add(evas); + Efl_Canvas_Animation *animation = efl_add(EFL_CANVAS_ANIMATION_CLASS, evas); + EXPECT_ERROR_START; + efl_canvas_object_animation_start(obj, NULL, 1.0, 0.0); + EXPECT_ERROR_END; + + EXPECT_ERROR_START; + efl_canvas_object_animation_start(obj, animation, 0.0, 0.0); + EXPECT_ERROR_END; + efl_canvas_object_animation_stop(obj); + + EXPECT_ERROR_START; + efl_canvas_object_animation_start(obj, animation, 1.0, 2.0); + EXPECT_ERROR_END; + efl_canvas_object_animation_stop(obj); + + EXPECT_ERROR_START; + efl_canvas_object_animation_start(obj, animation, 1.0, -1.0); + EXPECT_ERROR_END; + efl_canvas_object_animation_stop(obj); +} +EFL_END_TEST + +static void +_anim_changed_cb(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) +{ + animation_changed_ev = event->info; + called_changed ++; +} + +static void +_anim_running_cb(void *data EINA_UNUSED, const Efl_Event *event) +{ + animation_running_position = *((double*) event->info); + called_running ++; +} + +EFL_CALLBACKS_ARRAY_DEFINE(animation_stats_cb, + {EFL_CANVAS_OBJECT_ANIMATION_EVENT_ANIMATION_CHANGED, _anim_changed_cb }, + {EFL_CANVAS_OBJECT_ANIMATION_EVENT_ANIMATION_PROGRESS_UPDATED, _anim_running_cb }, +) + +EFL_START_TEST(evas_object_animation_events) +{ + Evas *evas = EVAS_TEST_INIT_EVAS(); + Evas_Object *obj = evas_object_rectangle_add(evas); + double start = efl_loop_time_get(efl_main_loop_get()); + Efl_Canvas_Animation *animation = efl_add(EFL_CANVAS_ANIMATION_CLASS, evas, efl_animation_duration_set(efl_added, 1.0)); + + efl_event_callback_array_add(obj, animation_stats_cb(), NULL); + + efl_canvas_object_animation_start(obj, animation, 1.0, 0.0); + + ck_assert_int_eq(called_changed, 1); + ck_assert_ptr_eq(animation_changed_ev, animation); + ck_assert_int_eq(called_running, 1); + ck_assert(EINA_DBL_EQ(animation_running_position, 0.0)); + + _simulate_time_passing(obj, start, 1.0); + + ck_assert_int_eq(called_changed, 2); + ck_assert_ptr_eq(animation_changed_ev, NULL); + ck_assert_int_eq(called_running, 2); + ck_assert(EINA_DBL_EQ(animation_running_position, 1.0)); + ck_assert_ptr_eq(efl_canvas_object_animation_get(obj), NULL); + ck_assert(EINA_DBL_EQ(efl_canvas_object_animation_progress_get(obj), -1.0)); +} +EFL_END_TEST + void evas_test_object(TCase *tc) { tcase_add_test(tc, evas_object_various); tcase_add_test(tc, evas_object_freeze_events); + tcase_add_test(tc, evas_object_animation_simple); + tcase_add_test(tc, evas_object_animation_progress); + tcase_add_test(tc, evas_object_animation_pause); + tcase_add_test(tc, evas_object_animation_error); + tcase_add_test(tc, evas_object_animation_events); }