diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index 6935c627f..121dd0395 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -1,10 +1,26 @@ DISTCLEANFILES += src/bin/e_fm_shared_types.h +efx_files = \ +src/bin/efx/efx_bumpmapping.c \ +src/bin/efx/efx.c \ +src/bin/efx/efx_fade.c \ +src/bin/efx/efx_helpers.c \ +src/bin/efx/efx_move.c \ +src/bin/efx/efx_pan.c \ +src/bin/efx/e_efx_private.h \ +src/bin/efx/efx_queue.c \ +src/bin/efx/efx_resize.c \ +src/bin/efx/efx_rotate.c \ +src/bin/efx/efx_spin.c \ +src/bin/efx/efx_util.c \ +src/bin/efx/efx_zoom.c + E_CPPFLAGS = \ -I$(top_builddir) \ -I$(top_builddir)/src/bin \ -I$(top_srcdir) \ -I$(top_srcdir)/src/bin \ +-I$(top_srcdir)/src/bin/efx \ -I$(top_srcdir)/src/bin/generated \ @e_cflags@ \ @cf_cflags@ \ @@ -43,6 +59,7 @@ internal_bin_PROGRAMS += src/bin/enlightenment_ckpasswd endif ENLIGHTENMENTHEADERS = \ +src/bin/efx/e_Efx.h \ src/bin/e_about.h \ src/bin/e_acpi.h \ src/bin/e_actions.h \ @@ -359,7 +376,8 @@ src/bin/e_xkb.c \ src/bin/e_xinerama.c \ src/bin/e_zoomap.c \ src/bin/e_zone.c \ -$(ENLIGHTENMENTHEADERS) +$(ENLIGHTENMENTHEADERS) \ +$(efx_files) if ! HAVE_WAYLAND_ONLY enlightenment_src += \ diff --git a/src/bin/e.h b/src/bin/e.h index 6b7ea51c8..34887bcf6 100644 --- a/src/bin/e.h +++ b/src/bin/e.h @@ -129,6 +129,7 @@ void *alloca (size_t); # include # include # include +# include "e_Efx.h" # ifdef HAVE_WAYLAND # include diff --git a/src/bin/e_fm/Makefile.mk b/src/bin/e_fm/Makefile.mk index 0eec4f4db..218329f31 100644 --- a/src/bin/e_fm/Makefile.mk +++ b/src/bin/e_fm/Makefile.mk @@ -3,6 +3,7 @@ EFM_CPPFLAGS = \ -I$(top_builddir)/src/bin \ -I$(top_srcdir) \ -I$(top_srcdir)/src/bin \ +-I$(top_srcdir)/src/bin/efx \ @e_cflags@ \ @cf_cflags@ \ @VALGRIND_CFLAGS@ \ diff --git a/src/bin/e_main.c b/src/bin/e_main.c index 3e36684e9..2781b86ec 100644 --- a/src/bin/e_main.c +++ b/src/bin/e_main.c @@ -372,6 +372,15 @@ main(int argc, char **argv) else e_first_frame = NULL; + TS("EFX Init"); + if (!e_efx_init()) + { + e_error_message_show(_("Enlightenment cannot initialize EFX!\n")); + _e_main_shutdown(-1); + } + TS("EFX Init Done"); + _e_main_shutdown_push((void*)e_efx_shutdown); + TS("EIO Init"); if (!eio_init()) { diff --git a/src/bin/efx/e_Efx.h b/src/bin/efx/e_Efx.h new file mode 100644 index 000000000..f668fdbf7 --- /dev/null +++ b/src/bin/efx/e_Efx.h @@ -0,0 +1,1076 @@ +#ifndef E_EFX_H +#define E_EFX_H + +#include +#include + +#ifdef EAPI +# undef EAPI +#endif /* ifdef EAPI */ + +#ifdef _WIN32 +# ifdef EFL_E_EFX_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else /* ifdef DLL_EXPORT */ +# define EAPI +# endif /* ! DLL_EXPORT */ +# else /* ifdef EFL_BUILD */ +# define EAPI __declspec(dllimport) +# endif /* ! EFL_BUILD */ +#else /* ifdef _WIN32 */ +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else /* if __GNUC__ >= 4 */ +# define EAPI +# endif /* if __GNUC__ >= 4 */ +# else /* ifdef __GNUC__ */ +# define EAPI +# endif /* ifdef __GNUC__ */ +#endif /* ! _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif /* ifdef __cplusplus */ + +/** + * @mainpage E_Efx Library Documentation + * + * @version 1.7.99 + * @date 2012 + * + * E_Efx is the effects libraries. + * + * For a better reference, check the following groups: + * @li @ref E_Efx + * @li @ref E_Efx_Queue + * @li @ref E_Efx_Follow + * @li @ref E_Efx_Fade + * @li @ref E_Efx_Rotation + * @li @ref E_Efx_Move + * @li @ref E_Efx_Resize + * + * Please see the @ref authors page for contact details. + */ + +/** + * @page authors Authors + * + * @author Mike Blumenkrantz + * @author Vincent "caro" Torri + * + * Please contact to get in + * contact with the developers and maintainers. + */ + +/** + * @file + * @brief These routines are used for E_Efx library interaction. + */ + +/** + * @defgroup E_Efx General types and functions. + * + * @{ + */ + +/** + * Helper macro for simplifying specifying coordinate points as parameters + * @param X The x coordinate + * @param Y The y coordinate + * @ingroup E_Efx + */ +#define E_EFX_POINT(X, Y) \ + &(Evas_Point){(X), (Y)} + +/** + * Helper macro for simplifying specifying colors as parameters + * @param R The red value + * @param G The blue value + * @param B The green value + * @ingroup E_Efx + */ +#define E_EFX_COLOR(R, G, B) \ + &(E_Efx_Color){(R), (G), (B)} + +/** + * @typedef E_Efx_Map_Data + * @ingroup E_Efx + */ +typedef struct E_Efx_Map_Data E_Efx_Map_Data; + +/** + * @struct E_Efx_Map_Data + * + * This struct is provided to callbacks upon the completion of certain types + * of effects. + * It contains information about the current position of an object. + * + * @ingroup E_Efx + */ +struct E_Efx_Map_Data +{ + double rotation; /**< The current rotation (in degrees) of the object */ + Evas_Point *rotate_center; /**< The current rotation center for the object */ + double zoom; /**< The current zoom amount of an object */ + Evas_Point *zoom_center; /**< The current zoom center for the object */ + Evas_Point *move_center; /**< The current move vertex for the object */ + Evas_Point pan; /**< The current pan for the object */ +}; + +/** + * @typedef E_Efx_End_Cb + * + * This is the callback type used to notify a user about the end of an effect. + * It is called instantly upon an effect terminating, but only if the effect + * has run to its full duration. Ending callbacks are NOT called upon + * stopping/resetting an effect. + * + * @param data The data passed when starting the effect + * @param e The current map data for an object + * @param obj The object + * + * @ingroup E_Efx + */ +typedef void (*E_Efx_End_Cb)(void *data, E_Efx_Map_Data *e, Evas_Object *obj); + +/** + * @enum _E_Efx_Effect_Speed + * @typedef E_Efx_Effect_Speed + * + * These values are used to set the speed at which an effect will occur. + * More information can be found by reading about Ecore_Animator objects. + * + * @ingroup E_Efx + */ +typedef enum _E_Efx_Effect_Speed +{ + E_EFX_EFFECT_SPEED_LINEAR = ECORE_POS_MAP_LINEAR, + E_EFX_EFFECT_SPEED_ACCELERATE = ECORE_POS_MAP_ACCELERATE, + E_EFX_EFFECT_SPEED_DECELERATE = ECORE_POS_MAP_DECELERATE, + E_EFX_EFFECT_SPEED_SINUSOIDAL = ECORE_POS_MAP_SINUSOIDAL +} E_Efx_Effect_Speed; + +/** + * @brief + * Initialize the library + * + * This function must be called before any other e_efx functions. + * @return The number of times the library has been initialized, + * or @c 0 on failure. + * + * @see e_efx_shutdown() + * + * @ingroup E_Efx + */ +EAPI int e_efx_init(void); + +/** + * @brief + * Uninitialize the library + * + * This function unregisters the log domain and performs other cleanup + * routines. + * + * @see e_efx_init() + * + * @ingroup E_Efx + */ +EAPI void e_efx_shutdown(void); + +/** + * @brief + * Attempt to automatically move+resize an object according to its map + * + * This function attempts to move an object to its mapped position and resize + * it according to its mapped zoom. It will, after calculating, reset the zoom + * and rotate effects on the object, + * preserving only its orientation. Ideally, you will not notice any visible + * change after running this function, + * but it should be used carefully, as successive effects on a realized + * object will likely not behave as intended. + * + * @param obj The object on which to realize effects + * + * @ingroup E_Efx + */ +EAPI void e_efx_realize(Evas_Object *obj); + + +/** + * @brief + * Reapply any E_EFX clips + * + * Call this function any time your object changes its clipping to ensure + * that effects which require clips continue to function as expected. + * + * @param obj The object to reapply clips for + * + * @ingroup E_Efx + */ +EAPI void e_efx_reclip(Evas_Object *obj); + +/** + * @brief + * Add bumpmapping on an object at a point + * + * This function will generate a bumpmap effect on @p obj at the coordinates + * given. + * @note The map is generated and displayed immediately upon calling this + * function + * @warning The calculations for this function are slow, and should not be used + * for realtime bumpmap generation; see the bumpmap test for details. + * + * @param obj The object to generate the map for + * @param x The X coordinate to center the map on + * @param y The Y coordinate to center the map on + * @return @c EINA_TRUE on successful map generation, else @c EINA_FALSE + * + * @ingroup E_Efx + */ +EAPI Eina_Bool e_efx_bumpmap(Evas_Object *obj, Evas_Coord x, Evas_Coord y); + +/** + * @} + */ + +/** + * @typedef E_Efx_Color + * + * Handle to color used in effects. + * + * @ingroup E_Efx_Fade + */ +typedef struct E_Efx_Color E_Efx_Color; + +/** + * @struct E_Efx_Color + * + * This struct contains RGB data for setting colors in effects. + * + * @ingroup E_Efx_Fade + */ +struct E_Efx_Color +{ + unsigned char r; /**< Red */ + unsigned char g; /**< Green */ + unsigned char b; /**< Blue */ +}; + + +/** + * @defgroup E_Efx_Queue E_Efx Effects Queue + * @ingroup E_Efx + * + * @{ + * + * With E_Efx it's possible to queue many effects with @ref e_efx_queue_append() + * and @ref e_efx_queue_prepend() and run them all with @ref e_efx_queue_run(), + * making complex animations much easier to be acomplished. + */ + +/** + * @typedef E_Efx_Queued_Effect + * + * Effect handle, used to create and queue an effect. + * + * @ingroup E_Efx_Queue + */ +typedef struct E_Efx_Queued_Effect E_Efx_Queued_Effect; + +/** + * @typedef E_Efx_Queue_Data + * + * Queue data handle, used to specify a queued effect. + * + * @ingroup E_Efx_Queue + */ +typedef struct E_Efx_Queue_Data E_Efx_Queue_Data; + +/** + * Helper macro to perform a C99 cast which simplifies the queue + * effect parameter in queue-related functions. + * @param EFFECT The effect + * @ingroup E_Efx_Queue + */ +#define E_EFX_QUEUED_EFFECT(EFFECT) \ + &(E_Efx_Queued_Effect){EFFECT} + +/** + * @enum _E_Efx_Effect_Type + * @typedef E_Efx_Effect_Type + * + * These values are used to set the speed at which an effect will occur. + * More information can be found by reading about Ecore_Animator objects. + * + * @ingroup E_Efx_Queue + */ +typedef enum _E_Efx_Effect_Type +{ + E_EFX_EFFECT_TYPE_ROTATE, + E_EFX_EFFECT_TYPE_ZOOM, + E_EFX_EFFECT_TYPE_MOVE, + E_EFX_EFFECT_TYPE_PAN, + E_EFX_EFFECT_TYPE_FADE, + E_EFX_EFFECT_TYPE_RESIZE +} E_Efx_Effect_Type; + +/** + * @struct E_Efx_Queued_Effect + * + * This struct contains all the data necessary to create and queue + * an effect. + * + * @ingroup E_Efx_Queue + */ +struct E_Efx_Queued_Effect +{ + E_Efx_Effect_Type type; + union + { + struct + { + double degrees; + Evas_Point *center; + } rotation; + struct + { + double start; + double end; + Evas_Point *center; + } zoom; + struct + { + Evas_Point point; + } movement; + struct + { + E_Efx_Color color; + unsigned char alpha; + } fade; + struct + { + Evas_Point *point; + int w, h; + } resize; + } effect; +}; + +/** + * @brief + * Begin processing the queue + * + * Call this function after queuing some effects to start the animation + * sequence. + * + * @param obj The object to process the queue for + * + * @ingroup E_Efx_Queue + */ +EAPI void e_efx_queue_run(Evas_Object *obj); + +/** + * @brief + * Append an effect to the end of the queue + * + * Use this function to add a new effect to the end of the queue. + * The queue can be empty when using this function. + * + * @param obj The object to queue an effect for + * @param speed The effect speed + * @param effect The parameters of the desired effect + * @param total_time The time the effect should occur over + * @param cb The optional callback to call after this particular effect has + * completed + * @param data The data to pass to the callback + * @return The queued effect, or @c NULL on failure + * + * @see e_efx_queue_prepend() + * @see e_efx_queue_delete() + * + * @ingroup E_Efx_Queue + */ +EAPI E_Efx_Queue_Data *e_efx_queue_append(Evas_Object *obj, E_Efx_Effect_Speed speed, const E_Efx_Queued_Effect *effect, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @brief + * Add an effect to the start of the queue + * + * Use this function to add a new effect to the start of the queue. + * The queue can be empty when using this function. + * + * @note If a queued effect is currently executing, the new effect will be + * added after it + * + * @param obj The object to queue an effect for + * @param speed The effect speed + * @param effect The parameters of the desired effect + * @param total_time The time the effect should occur over + * @param cb The optional callback to call after this particular effect has + * completed + * @param data The data to pass to the callback + * @return The queued effect, or @c NULL on failure + * + * @see e_efx_queue_append() + * @see e_efx_queue_delete() + * + * @ingroup E_Efx_Queue + */ +EAPI E_Efx_Queue_Data *e_efx_queue_prepend(Evas_Object *obj, E_Efx_Effect_Speed speed, const E_Efx_Queued_Effect *effect, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @brief + * Promote an inactive effect to the start of the queue + * + * Use this function on an effect that is not currently executing to + * move it to the head of the queue. + * @note If another effect is currently executing, @p eqd will be moved + * directly after it. + * @param obj The object owning the effect + * @param eqd The effect + * + * @ingroup E_Efx_Queue + */ +EAPI void e_efx_queue_promote(Evas_Object *obj, E_Efx_Queue_Data *eqd); + +/** + * @brief + * Demote an inactive effect to the end of the queue + * + * Use this function on an effect that is not currently executing to + * move it to the tail of the queue. + * + * @param obj The object owning the effect + * @param eqd The effect + * + * @ingroup E_Efx_Queue + */ +EAPI void e_efx_queue_demote(Evas_Object *obj, E_Efx_Queue_Data *eqd); + +/** + * @brief + * Delete an effect from the queue + * + * This function will delete and unqueue a previously queued effect. + * @note Currently executing effects cannot be deleted; they must be manually + * stopped using the proper stop/reset function. + * @param obj The object owning the effect + * @param eqd The effect + * + * @ingroup E_Efx_Queue + */ +EAPI void e_efx_queue_delete(Evas_Object *obj, E_Efx_Queue_Data *eqd); + +/** + * @brief + * Delete all queued effects which are not currently executing + * + * This function will delete and unqueue all previously queued effects. + * + * @note Currently executing effects cannot be deleted; they must be manually + * stopped using the proper stop/reset function. + * + * @param obj The object owning the effects + * + * @ingroup E_Efx_Queue + */ +EAPI void e_efx_queue_clear(Evas_Object *obj); + +/** + * @brief + * Attach an effect to other. + * + * Append @p effect to subeffects list of @p eqd. + * + * @param eqd The effect + * @param speed The effect speed + * @param effect The parameters of the desired effect + * @param total_time The time the effect should occur over + * @param cb The optional callback to call after this particular effect has + * completed + * @param data The data to pass to the callback + * @return @c EINA_TRUE on success or @c EINA_FALSE on error. + * + * @ingroup E_Efx_Queue + */ +EAPI Eina_Bool e_efx_queue_effect_attach(E_Efx_Queue_Data *eqd, E_Efx_Effect_Speed speed, const E_Efx_Queued_Effect *effect, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @} + */ + +/** + * @defgroup E_Efx_Follow E_Efx Follow + * @ingroup E_Efx + * + * @{ + * + * Using @ref e_efx_follow() it's possible to cause objects to mimic others. + */ + +/** + * @brief + * Cause one object to mimic the actions of another + * + * Using this function, @p follower will copy every effect set on @p obj + * until @ref e_efx_unfollow() is called on @p follower. Note that passing + * a "follower" object as @p obj will cause the object passed as @p follower + * to be chained to the follower's top-most "owner" object. + * + * @note Effects from an "owner" object will supercede any similar effects + * explicitly set on a "follower" object, and they will also probably + * break each other. Don't chain owners to other owners unless you know + * what you are doing. + * + * @param obj The object to follow the actions of + * @param follower The object to do the following + * @return @c EINA_TRUE on success, else @c EINA_FALSE + * + * @ingroup E_Efx_Follow + */ +EAPI Eina_Bool e_efx_follow(Evas_Object *obj, Evas_Object *follower); + +/** + * @brief + * Unchain a following object from its owner + * + * This function will cause @p obj to stop following its owner object. + * It takes effect immediately and cannot fail. + * + * @param obj The follower object + * + * @ingroup E_Efx_Follow + */ +EAPI void e_efx_unfollow(Evas_Object *obj); + +/** + * @brief + * Retrieve the list of following objects + * + * This function returns a copy of the list of objects following @p obj. + * The returned list must be manually freed with eina_list_free. + * + * @param obj The owner object + * @return A list of follower Evas_Objects, or @c NULL + * + * @ingroup E_Efx_Follow + */ +EAPI Eina_List *e_efx_followers_get(Evas_Object *obj); + +/** + * @brief + * Retrieve an object's leader object + * + * Use this function to return the object which @p obj is currently following. + * + * @param obj The object + * @return The leader object or NULL on failure + * + * @ingroup E_Efx_Follow + */ +EAPI Evas_Object *e_efx_leader_get(Evas_Object *obj); + +/** + * @} + */ + +/** + * @defgroup E_Efx_Fade E_Efx Fade Effect + * @ingroup E_Efx + * + * @{ + * + * Fade effects are very frequently on elaborated interfaces. Using + * @ref e_efx_fade() it's possible to change color and alpha channel leading + * to fade in / out transitions. + */ + +/** + * Helper macro to simplify specifying a fade effect for queue + * @param R Red + * @param G Green + * @param B Blue + * @param A Alpha + * @ingroup E_Efx_Fade + */ +#define E_EFX_EFFECT_FADE(R, G, B, A) \ + .type = E_EFX_EFFECT_TYPE_FADE, .effect.fade = { .color = { .r = (R), .g = (G), .b = (B) }, .alpha = (A) } + +/** + * @brief + * Commence a fade effect + * + * Fade is an effect which allows the changing of color tint and alpha through + * the use of a clip set on an object. With this effect it is possible to + * have an object fade in/out or become tinted with another color. + * + * @note Black objects will only have their alpha values affected. + * + * @param obj The object to use for fading + * @param speed The speed to fade at + * @param ec The color to fade to + * @param alpha The alpha to fade to + * @param total_time The time the effect should occur over + * @param cb The optional callback to call when the effect completes + * @param data Optional data to pass to @p cb + * @return @c EINA_TRUE on successful queue of the animation, else + * @c EINA_FALSE + * + * @ingroup E_Efx_Fade + */ +EAPI Eina_Bool e_efx_fade(Evas_Object *obj, E_Efx_Effect_Speed speed, E_Efx_Color *ec, unsigned char alpha, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @brief + * Stop fading of an object and remove the clip + * + * Use this function to immediately stop the fade of an object and restore + * its original color/alpha. + * + * @param obj An object + * + * @ingroup E_Efx_Fade + */ +EAPI void e_efx_fade_reset(Evas_Object *obj); + +/** + * Stop fading of an object + * + * Use this function to immediately stop the fade of an object without + * restoring its original color/alpha. + * + * @param obj An object + * + * @ingroup E_Efx_Fade + */ +EAPI void e_efx_fade_stop(Evas_Object *obj); + +/** + * @} + */ + +/** + * @defgroup E_Efx_Rotation E_Efx Rotation Effects + * @ingroup E_Efx + * + * @{ + * + * There are two ways of rotation an object: using @ref e_efx_rotate(), + * where the object will rotate per specified degrees around a central point, + * or @ref e_efx_spin_start(), making the object rotates specified degrees per + * second until it's explicitly stopped. + */ + +/** + * Helper macro to simplify specifying a rotation effect for queue + * @param DEGREES Number of degrees to rotate + * @param CENTER An Evas_Point* to rotate around, or @c NULL + * @ingroup E_Efx_Rotation + */ +#define E_EFX_EFFECT_ROTATE(DEGREES, CENTER) \ + .type = E_EFX_EFFECT_TYPE_ROTATE, .effect.rotation = { .degrees = (DEGREES), .center = (CENTER) } + +/** + * @brief + * Rotate an object + * + * This function allows rotation of an object around an optional point with + * specified rotation amount, speed of effect, and duration of effect. + * + * @note @p cb will ONLY be called upon successful completion of the effect. + * @note The actual location of the object will not change; this is a map effect + * + * @param obj The object to rotate + * @param speed The speed to rotate at + * @param degrees The amount to rotate + * @param center The optional point to rotate around + * @param total_time The time that the effect should occur over + * @param cb The optional callback to call when the effect completes + * @param data Optional data to pass to @p cb + * @return @c EINA_TRUE on successful queue of the animation, else + * @c EINA_FALSE + * + * @ingroup E_Efx_Rotation + */ +EAPI Eina_Bool e_efx_rotate(Evas_Object *obj, E_Efx_Effect_Speed speed, double degrees, const Evas_Point *center, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @brief + * Stop rotation of an object and remove the map + * + * Use this function to immediately stop the rotation of an object and restore + * its original position + * + * @param obj An object + * + * @ingroup E_Efx_Rotation + */ +EAPI void e_efx_rotate_reset(Evas_Object *obj); + +/** + * @brief + * Stop rotation of an object + * + * Use this function to immediately stop the rotation of an object without restoring its original position + * @param obj An object + * + * @ingroup E_Efx_Rotation + */ +EAPI void e_efx_rotate_stop(Evas_Object *obj); + +/** + * @brief + * Spin an object + * + * This function allows rotation of an object around an optional point. + * The object + * will rotate at @p dps degrees per second until manually stopped. + * @note The actual location of the object will not change; this is a map effect + * + * @param obj The object to rotate + * @param dps The degrees per second to rotate + * @param center The optional point to rotate around + * @return @c EINA_TRUE on successful queue of the animation, else + * @c EINA_FALSE + * + * @ingroup E_Efx_Rotation + */ +EAPI Eina_Bool e_efx_spin_start(Evas_Object *obj, long dps, const Evas_Point *center); + +/** + * @brief + * Stop rotation of an object and remove the map + * + * Use this function to immediately stop the rotation of an object and restore + * its original position + * + * @param obj An object + * + * @ingroup E_Efx_Rotation + */ +EAPI void e_efx_spin_reset(Evas_Object *obj); + +/** + * @brief + * Stop rotation of an object + * + * Use this function to immediately stop the rotation of an object without + * restoring its original position + * + * @param obj An object + * + * @ingroup E_Efx_Rotation + */ +EAPI void e_efx_spin_stop(Evas_Object *obj); + +/** + * @} + */ + +/** + * @defgroup E_Efx_Zoom E_Efx Zoom Effects + * @ingroup E_Efx + * + * @{ + * + * It's possible to add zoom in / out effects using @ref e_efx_zoom() + */ + +/** + * Helper macro to simplify specifying a zoom effect for queue + * @param START Starting zoom factor + * @param END Ending zoom factor + * @param CENTER An Evas_Point* to zoom at, or @c NULL + * @ingroup E_Efx_Zoom + */ +#define E_EFX_EFFECT_ZOOM(START, END, CENTER) \ + .type = E_EFX_EFFECT_TYPE_ZOOM, .effect.zoom = { .start = (START), .end = (END), .center = (CENTER) } + +/** + * @brief + * Zoom an object + * + * This function allows zooming of an object at an optional point with + * specified zoom amount, starting amount, speed of effect, and time to + * complete effect. + * + * @note @p cb will ONLY be called upon successful completion of the effect. + * @note The actual location of the object will not change; this is a map effect + * + * @param obj The object to zoom + * @param speed The speed to zoom at + * @param starting_zoom The zoom amount to start at, or 0 to use the + * previously existing zoom amount (defaults to 1.0) + * @param ending_zoom The zoom amount to end at + * @param zoom_point The optional point to center the zoom on + * @param total_time The time that the effect should occur over + * @param cb The optional callback to call when the effect completes + * @param data Optional data to pass to @p cb + * @return @c EINA_TRUE on successful queue of the animation, else + * @c EINA_FALSE + * + * @ingroup E_Efx_Zoom + */ +EAPI Eina_Bool e_efx_zoom(Evas_Object *obj, E_Efx_Effect_Speed speed, double starting_zoom, double ending_zoom, const Evas_Point *zoom_point, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @brief + * Stop zooming of an object and remove the map + * + * Use this function to immediately stop the zoom of an object and restore its + * original position + * + * @param obj An object + * + * @ingroup E_Efx_Zoom + */ +EAPI void e_efx_zoom_reset(Evas_Object *obj); + +/** + * @brief + * Stop zooming of an object + * + * Use this function to immediately stop the zoom of an object without + * restoring its original position + * + * @param obj An object + * + * @ingroup E_Efx_Zoom + */ +EAPI void e_efx_zoom_stop(Evas_Object *obj); + +/** + * @} + */ + +/** + * @defgroup E_Efx_Move E_Efx Movement Effects + * @ingroup E_Efx + * + * @{ + * + * Object movement can be done directly using @ref e_efx_move() or using + * @ref e_efx_pan(); + * A "pan" is a motion which shifts the view of an object from one point to + * another. + */ + +/** + * Helper macro to simplify specifying a movement effect for queue + * @param X x coordinate to move to + * @param Y y coordinate to move to + * @ingroup E_Efx_Move + */ +#define E_EFX_EFFECT_MOVE(X, Y) \ + .type = E_EFX_EFFECT_TYPE_MOVE, .effect.movement.point = { .x = (X), .y = (Y) } + +/** + * Helper macro to simplify specifying a pan effect for queue + * @param X horizontal distance to pan + * @param Y vertical distance to pan + * @ingroup E_Efx_Move + */ +#define E_EFX_EFFECT_PAN(X, Y) \ + .type = E_EFX_EFFECT_TYPE_PAN, .effect.movement.point = { .x = (X), .y = (Y) } + +/** + * @brief + * Move an object + * + * This function animates the movement of an object to a specified point using + * a designated speed of effect and time to complete the effect. + * + * @note @p cb will ONLY be called upon successful completion of the effect. + * @note The actual location of the object WILL change; this is NOT a map effect + * + * @param obj The object to zoom + * @param speed The speed to move at + * @param end_point The point to move to + * @param total_time The time that the effect should occur over + * @param cb The optional callback to call when the effect completes + * @param data Optional data to pass to @p cb + * @return @c EINA_TRUE on successful queue of the animation, else + * @c EINA_FALSE + * + * @ingroup E_Efx_Move + */ +EAPI Eina_Bool e_efx_move(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *end_point, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @brief + * Move an object in circle + * + * This function animates the movement of an object around a specified + * point using a designated degrees, speed of effect and time to complete + * the effect. + * + * @note @p cb will ONLY be called upon successful completion of the effect. + * @note The actual location of the object WILL change; this is NOT a map effect + * + * @param obj The object to zoom + * @param speed The speed to move at + * @param center The center point to move around + * @param degrees The amount of degrees to move around the center + * @param total_time The time that the effect should occur over + * @param cb The optional callback to call when the effect completes + * @param data Optional data to pass to @p cb + * @return @c EINA_TRUE on successful queue of the animation, else + * @c EINA_FALSE + * + * @ingroup E_Efx_Move + */ +EAPI Eina_Bool e_efx_move_circle(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *center, int degrees, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @brief + * Stop moving of an object + * + * Use this function to immediately stop the move of an object and restore its + * original position + * + * @param obj An object + * + * @ingroup E_Efx_Move + */ +EAPI void e_efx_move_reset(Evas_Object *obj); + +/** + * @brief + * Stop moving of an object + * + * Use this function to immediately stop the move of an object without + * restoring its original position + * + * @param obj An object + * + * @ingroup E_Efx_Move + */ +EAPI void e_efx_move_stop(Evas_Object *obj); + +/** + * @brief + * Initialize an object for panning + * + * Use this function immediately after creating an object if you plan + * to place other layers on top of it. This prevents the newly-created pan + * object from obscuring other objects. No visible changes will occur from + * calling this function. + * + * @param obj The object to set up for panning + * @return @c EINA_TRUE on success, else @c EINA_FALSE + * + * @ingroup E_Efx_Move + */ +EAPI Eina_Bool e_efx_pan_init(Evas_Object *obj); + +/** + * @brief + * Commence a pan effect + * + * A "pan" is a motion which shifts the view of an object from one point to + * another. + * This function sets up (calling e_efx_pan_init() if necessary) and runs a pan + * effect + * which will shift the view of the canvas in the directions specified by + * @p distance. + * + * @param obj The object to use for panning + * @param speed The speed to pan at + * @param distance The relative X and Y distance to move during the pan + * @param total_time The time that the effect should occur over + * @param cb The optional callback to call when the effect completes + * @param data Optional data to pass to @p cb + * @return @c EINA_TRUE on successful queue of the animation, else + * @c EINA_FALSE + * + * @ingroup E_Efx_Move + */ +EAPI Eina_Bool e_efx_pan(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *distance, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @} + */ + +/** + * @defgroup E_Efx_Resize E_Efx Resize Effect + * @ingroup E_Efx + * + * @{ + * + * FIXME DESC + * + */ + +/** + * Helper macro to simplify specifying a resize effect for queue + * @param POSITION The position for the resized top-left corner to end in + * @param W The final width of the object + * @param H The final height of the object + * @ingroup E_Efx_Resize + */ +#define E_EFX_EFFECT_RESIZE(POSITION, W, H) \ + .type = E_EFX_EFFECT_TYPE_RESIZE, .effect.resize = { .point = (POSITION), .w = (W), .h = (H) } + +/** + * @brief + * Resize an object + * + * This function animates the resizing of an object to a specified width and + * height using a designated speed of effect and time to complete the effect. + * + * @note @p cb will ONLY be called upon successful completion of the effect. + * @note The actual size of the object WILL change; this is NOT a map effect + * + * @param obj The object to zoom + * @param speed The speed to move at + * @param position The point to move to. If not provided, the object won't move. + * @param w The final object width + * @param h The final object height + * @param total_time The time that the effect should occur over + * @param cb The optional callback to call when the effect completes + * @param data Optional data to pass to @p cb + * @return @c EINA_TRUE on successful queue of the animation, else + * @c EINA_FALSE + * + * @ingroup E_Efx_Resize + */ +EAPI Eina_Bool e_efx_resize(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *position, int w, int h, double total_time, E_Efx_End_Cb cb, const void *data); + +/** + * @brief + * Stop resizing of an object + * + * Use this function to immediately stop the resize of an object and restore its + * original size + * + * @param obj An object + * + * @ingroup E_Efx_Resize + */ +EAPI void e_efx_resize_reset(Evas_Object *obj); + +/** + * @brief + * Stop resizing of an object + * + * Use this function to immediately stop the resize of an object without + * restoring its original size + * + * @param obj An object + * + * @ingroup E_Efx_Resize + */ +EAPI void e_efx_resize_stop(Evas_Object *obj); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#undef EAPI + +#endif diff --git a/src/bin/efx/e_efx_private.h b/src/bin/efx/e_efx_private.h new file mode 100644 index 000000000..4b5e6a5c4 --- /dev/null +++ b/src/bin/efx/e_efx_private.h @@ -0,0 +1,128 @@ +#ifndef E_EFX_PRIVATE_H +#define E_EFX_PRIVATE_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include + +#include "e_Efx.h" + +#define DBG(...) EINA_LOG_DOM_DBG(_e_efx_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_e_efx_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_e_efx_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_e_efx_log_dom, __VA_ARGS__) +#define CRI(...) EINA_LOG_DOM_CRIT(_e_efx_log_dom, __VA_ARGS__) + +#ifdef EAPI +# undef EAPI +#endif /* ifdef EAPI */ + +#ifdef _WIN32 +# ifdef EFL_E_EFX_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else /* ifdef DLL_EXPORT */ +# define EAPI +# endif /* ! DLL_EXPORT */ +# else /* ifdef EFL_BUILD */ +# define EAPI __declspec(dllimport) +# endif /* ! EFL_BUILD */ +#else /* ifdef _WIN32 */ +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else /* if __GNUC__ >= 4 */ +# define EAPI +# endif /* if __GNUC__ >= 4 */ +# else /* ifdef __GNUC__ */ +# define EAPI +# endif /* ifdef __GNUC__ */ +#endif /* ! _WIN32 */ +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +static const char *e_efx_speed_str[] = +{ + "LINEAR", "ACCELERATE", "DECELERATE", "SINUSOIDAL" +}; + +extern int _e_efx_log_dom; + +typedef struct E_EFX E_EFX; + +struct E_EFX +{ + Evas_Object *obj; + E_EFX *owner; + void *spin_data; + void *rotate_data; + void *zoom_data; + void *move_data; + void *bumpmap_data; + void *pan_data; + void *fade_data; + void *resize_data; + E_Efx_Map_Data map_data; + Eina_List *followers; + Eina_List *queue; +}; + +void _e_efx_zoom_calc(void *, void *, Evas_Object *obj, Evas_Map *map); +void _e_efx_rotate_calc(void *, void *, Evas_Object *obj, Evas_Map *map); +void _e_efx_spin_calc(void *, void *, Evas_Object *obj, Evas_Map *map); +void _e_efx_resize_adjust(E_EFX *e, int *x, int *y); + +#define E_EFX_MAPS_APPLY_ALL EINA_TRUE, EINA_TRUE, EINA_TRUE +#define E_EFX_MAPS_APPLY_ROTATE EINA_TRUE, EINA_FALSE, EINA_FALSE +#define E_EFX_MAPS_APPLY_SPIN EINA_FALSE, EINA_TRUE, EINA_FALSE +#define E_EFX_MAPS_APPLY_ZOOM EINA_FALSE, EINA_FALSE, EINA_TRUE +#define E_EFX_MAPS_APPLY_ROTATE_SPIN EINA_TRUE, EINA_TRUE, EINA_FALSE +void e_efx_maps_apply(E_EFX *e, Evas_Object *obj, Evas_Map *map, Eina_Bool rotate, Eina_Bool spin, Eina_Bool zoom); + +E_EFX *e_efx_new(Evas_Object *obj); +void e_efx_free(E_EFX *e); +Evas_Map *e_efx_map_new(Evas_Object *obj); +void e_efx_map_set(Evas_Object *obj, Evas_Map *map); +Eina_Bool e_efx_rotate_center_init(E_EFX *e, const Evas_Point *center); +Eina_Bool e_efx_zoom_center_init(E_EFX *e, const Evas_Point *center); +Eina_Bool e_efx_move_center_init(E_EFX *e, const Evas_Point *center); +void e_efx_rotate_helper(E_EFX *e, Evas_Object *obj, Evas_Map *map, double degrees); +void e_efx_clip_setup(Evas_Object *obj, Evas_Object *clip); +void e_efx_fade_reclip(void *efd); + +#define E_EFX_QUEUE_CHECK(X) do \ + { \ + Eina_Bool run; \ + E_EFX *ee = (X)->e; \ + run = e_efx_queue_complete((X)->e, (X)); \ + if ((X)->cb) (X)->cb((X)->data, &(X)->e->map_data, (X)->e->obj); \ + if (run) e_efx_queue_process(ee); \ + } while (0) +Eina_Bool e_efx_queue_complete(E_EFX *e, void *effect_data); +void e_efx_queue_process(E_EFX *e); + +static inline void +_size_debug(Evas_Object *obj) +{ + Evas_Coord x, y, w, h; + evas_object_geometry_get(obj, &x, &y, &w, &h); + DBG("%s %p: x=%d,y=%d,w=%d,h=%d", evas_object_visible_get(obj) ? "vis" : "hid", obj, x, y, w, h); +} + +static inline void +_color_debug(Evas_Object *obj) +{ + Evas_Coord r, g, b, a; + evas_object_color_get(obj, &r, &g, &b, &a); + DBG("%d/%d/%d/%d", MIN(r, a), MIN(g, a), MIN(b, a), a); +} + +#define HIT DBG("HIT") + +#endif diff --git a/src/bin/efx/efx.c b/src/bin/efx/efx.c new file mode 100644 index 000000000..7c2971e19 --- /dev/null +++ b/src/bin/efx/efx.c @@ -0,0 +1,65 @@ +#include "e_efx_private.h" + +int _e_efx_log_dom = -1; +static int _e_efx_init_count = 0; + +static uint64_t _e_efx_obj_count = 0; + +E_EFX * +e_efx_new(Evas_Object *obj) +{ + E_EFX *e; + e = calloc(1, sizeof(E_EFX)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL); + e->obj = obj; + evas_object_data_set(obj, "e_efx-data", e); + _e_efx_obj_count++; + return e; +} + +void +e_efx_free(E_EFX *e) +{ + E_EFX *ef; + if (e->zoom_data || e->resize_data || e->rotate_data || e->spin_data || e->move_data || e->bumpmap_data || e->pan_data || e->fade_data || e->queue) return; + DBG("freeing e_efx for %p", e->obj); + EINA_LIST_FREE(e->followers, ef) + e_efx_free(ef); + evas_object_data_del(e->obj, "e_efx-data"); + e_efx_map_set(e->obj, NULL); + free(e->map_data.rotate_center); + free(e->map_data.zoom_center); + if (!(--_e_efx_obj_count)) + { + if (!_e_efx_init_count) + e_efx_shutdown(); + } + free(e); +} + +EAPI int +e_efx_init(void) +{ + if (++_e_efx_init_count > 1) return _e_efx_init_count; + + if (eina_init() < 1) goto err; + + _e_efx_log_dom = eina_log_domain_register("e_efx", EINA_COLOR_GREEN); + if (_e_efx_log_dom < 0) goto lgerr; + return _e_efx_init_count; +lgerr: + eina_shutdown(); +err: + return --_e_efx_init_count; + (void)e_efx_speed_str; +} + +EAPI void +e_efx_shutdown(void) +{ + if (_e_efx_init_count && (--_e_efx_init_count != 0)) return; + if (_e_efx_obj_count) return; + eina_log_domain_unregister(_e_efx_log_dom); + _e_efx_log_dom = -1; + eina_shutdown(); +} diff --git a/src/bin/efx/efx_bumpmapping.c b/src/bin/efx/efx_bumpmapping.c new file mode 100644 index 000000000..b25477096 --- /dev/null +++ b/src/bin/efx/efx_bumpmapping.c @@ -0,0 +1,186 @@ +#include "e_efx_private.h" +#include + +#define DATA8 unsigned char +#define A_VAL(p) (((DATA8 *)(p))[3]) +#define R_VAL(p) (((DATA8 *)(p))[2]) +#define G_VAL(p) (((DATA8 *)(p))[1]) +#define B_VAL(p) (((DATA8 *)(p))[0]) + +typedef struct E_Efx_Bumpmap_Data +{ + E_EFX *e; + int x; + int y; + int z; + int depth; + int red; + int green; + int blue; + int ambient; + unsigned int *img_data; +} E_Efx_Bumpmap_Data; + +static void +_bumpmap(E_Efx_Bumpmap_Data *ebd) +{ + Evas_Object *o; + int w; + int h; + int i, j; + + int x; + int y; + int z; + int depth; + int red; + int green; + int blue; + int ambient; + + int z_2, lightx, lighty; + int mx; + int my; + unsigned int *d1; + unsigned int *src; + unsigned int *mp; + unsigned int *mpy; + unsigned int *mpp; + + x = ebd->x; + y = ebd->y; + z = ebd->z; + + red = ebd->red / 0x100; + green = ebd->green / 0x100; + blue = ebd->blue / 0x100; + ambient = ebd->ambient / 0x100; + depth = ebd->depth / 0x100; + depth /= (255 * (255 + 255 + 255)); + z_2 = z * z; + + o = ebd->e->obj; + evas_object_image_size_get(o, &w, &h); + if ((!w) || (!h)) return; + + d1 = malloc(w * h * sizeof(int)); + memcpy(d1, ebd->img_data, w * h * sizeof(int)); + src = d1; + + mpp = ebd->img_data; + + my = h; + lighty = -y; + for (j = h; --j >= 0;) + { + mp = mpp; + mpp += w; + if (--my <= 0) + { + mpp -= w * h; + my = h; + } + mpy = mpp; + mx = w; + lightx = -x; + i = w - 1; + do + { + double v; + int r, g, b, gr, x1, y_1; + + gr = A_VAL(mp) * (R_VAL(mp) + G_VAL(mp) + B_VAL(mp)); + y_1 = depth * (A_VAL(mpy) * (R_VAL(mpy) + + G_VAL(mpy) + + B_VAL(mpy)) - gr); + mp++; + mpy++; + if (--mx <= 0) + { + mp -= w; + mpy -= w; + mx = w; + } + x1 = depth * (A_VAL(mp) * (R_VAL(mp) + + G_VAL(mp) + B_VAL(mp)) - gr); + v = x1 * lightx + y_1 * lighty + z; + v /= sqrt(((x1 * x1) + (y_1 * y_1) + 1) * ((lightx * lightx) + (lighty * lighty) + z_2)); + v += ambient; + r = v * R_VAL(src) * red; + g = v * G_VAL(src) * green; + b = v * B_VAL(src) * blue; + if (r < 0) + r = 0; + else if (r > 255) + r = 255; + if (g < 0) + g = 0; + else if (g > 255) + g = 255; + if (b < 0) + b = 0; + else if (b > 255) + b = 255; + R_VAL(src) = r; + G_VAL(src) = g; + B_VAL(src) = b; + + lightx++; + src++; + } while (--i >= 0); + lighty++; + } + + evas_object_image_data_set(o, d1); + evas_object_image_data_update_add(o, 0, 0, w, h); +} + +EAPI Eina_Bool +e_efx_bumpmap(Evas_Object *obj, Evas_Coord x, Evas_Coord y) +{ + E_EFX *e; + E_Efx_Bumpmap_Data *ebd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) + e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + + if (!e->bumpmap_data) + e->bumpmap_data = calloc(1, sizeof(E_Efx_Bumpmap_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->bumpmap_data, EINA_FALSE); + ebd = e->bumpmap_data; + ebd->e = e; + ebd->x = x; + ebd->y = y; + ebd->z = 30; + ebd->depth = 0x200; + ebd->red = 0x200; + ebd->green = 0x200; + ebd->blue = 0x200; + ebd->ambient = 0; + if (!ebd->img_data) + { + unsigned int *m; + int w; + int h; + + evas_object_image_size_get(obj, &w, &h); + m = (unsigned int *)evas_object_image_data_get(obj, 1); + ebd->img_data = (unsigned int *)malloc(w * h * sizeof(unsigned int)); + if (!ebd->img_data) + { + free(ebd); + return EINA_FALSE; + } + printf("memcpy\n"); + memcpy(ebd->img_data, m, (w * h * sizeof(unsigned int))); + } + + _bumpmap(ebd); + + return EINA_TRUE; + (void)e_efx_speed_str; +} diff --git a/src/bin/efx/efx_fade.c b/src/bin/efx/efx_fade.c new file mode 100644 index 000000000..158b68921 --- /dev/null +++ b/src/bin/efx/efx_fade.c @@ -0,0 +1,184 @@ +#include "e_efx_private.h" + +typedef struct E_Efx_Fade_Data +{ + E_EFX *e; + E_Efx_Effect_Speed speed; + Ecore_Animator *anim; + Evas_Object *clip; + E_Efx_Color start; + E_Efx_Color color; + unsigned char alpha[2]; + E_Efx_End_Cb cb; + void *data; +} E_Efx_Fade_Data; + + +static void +_clip_setup(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + E_EFX *e; + E_Efx_Fade_Data *efd; + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return; + efd = e->fade_data; + e_efx_clip_setup(obj, efd->clip); +} + +static void +_obj_del(E_Efx_Fade_Data *efd, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + if (efd->anim) ecore_animator_del(efd->anim); + evas_object_event_callback_del_full(efd->e->obj, EVAS_CALLBACK_RESIZE, (Evas_Object_Event_Cb)_clip_setup, efd); + evas_object_event_callback_del_full(efd->e->obj, EVAS_CALLBACK_MOVE, (Evas_Object_Event_Cb)_clip_setup, efd); + if (efd->clip) + { + Evas_Object *clip; + + clip = evas_object_clip_get(efd->clip); + evas_object_clip_unset(efd->e->obj); + evas_object_del(efd->clip); + efd->clip = NULL; + if (clip && (!obj)) //obj is only passed during actual del + evas_object_clip_set(efd->e->obj, clip); + } + efd->e->fade_data = NULL; + if ((!efd->e->owner) && (!efd->e->followers)) e_efx_free(efd->e); + free(efd); +} + +static Eina_Bool +_fade_cb(E_Efx_Fade_Data *efd, double pos) +{ + double factor; + unsigned char r, g, b, a; + + if (pos < 1.0) + { + r = efd->start.r; + g = efd->start.g; + b = efd->start.b; + a = efd->alpha[0]; + factor = ecore_animator_pos_map(pos, efd->speed, 0, 0); + if (efd->color.r != efd->start.r) + r -= lround(factor * ((int)efd->start.r - (int)efd->color.r)); + if (efd->color.g != efd->start.g) + g -= lround(factor * ((int)efd->start.g - (int)efd->color.g)); + if (efd->color.b != efd->start.b) + b -= lround(factor * ((int)efd->start.b - (int)efd->color.b)); + if (efd->alpha[0] != efd->alpha[1]) + a -= lround(factor * ((int)efd->alpha[0] - (int)efd->alpha[1])); + evas_object_color_set(efd->clip, MIN(r, a), MIN(g, a), MIN(b, a), a); +// _color_debug(efd->clip); + return EINA_TRUE; + } + else + /* lround will usually be off by 1 at the end, so we manually set this here */ + evas_object_color_set(efd->clip, MIN(efd->color.r, efd->alpha[1]), MIN(efd->color.g, efd->alpha[1]), MIN(efd->color.b, efd->alpha[1]), efd->alpha[1]); + + efd->anim = NULL; + E_EFX_QUEUE_CHECK(efd); + return EINA_TRUE; +} + +static void +_fade_stop(Evas_Object *obj, Eina_Bool reset) +{ + E_EFX *e; + E_Efx_Fade_Data *efd; + + e = evas_object_data_get(obj, "e_efx-data"); + if ((!e) || (!e->fade_data)) return; + efd = e->fade_data; + if (reset) + { + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, efd); + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_RESIZE, (Evas_Object_Event_Cb)_clip_setup, efd); + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOVE, (Evas_Object_Event_Cb)_clip_setup, efd); + if (e_efx_queue_complete(efd->e, efd)) + e_efx_queue_process(efd->e); + _obj_del(efd, NULL, NULL, NULL); + INF("reset faded object %p", obj); + } + else + { + INF("stopped faded object %p", obj); + if (efd->anim) ecore_animator_del(efd->anim); + if (e_efx_queue_complete(efd->e, efd)) + e_efx_queue_process(efd->e); + } +} + +void +e_efx_fade_reclip(void *fade_data) +{ + E_Efx_Fade_Data *efd = fade_data; + Evas_Object *clip; + + clip = evas_object_clip_get(efd->e->obj); + if (clip == efd->clip) return; + evas_object_clip_set(efd->e->obj, efd->clip); + if (clip) + evas_object_clip_set(efd->clip, clip); + e_efx_clip_setup(efd->e->obj, efd->clip); +} + +EAPI Eina_Bool +e_efx_fade(Evas_Object *obj, E_Efx_Effect_Speed speed, E_Efx_Color *ec, unsigned char alpha, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Fade_Data *efd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + efd = e->fade_data; + if (!efd) + { + e->fade_data = efd = calloc(1, sizeof(E_Efx_Fade_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(efd, EINA_FALSE); + evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->fade_data); + evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, (Evas_Object_Event_Cb)_clip_setup, e->fade_data); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, (Evas_Object_Event_Cb)_clip_setup, e->fade_data); + efd->clip = evas_object_rectangle_add(evas_object_evas_get(obj)); + } + + efd->e = e; + e_efx_fade_reclip(efd); + evas_object_show(efd->clip); + efd->alpha[1] = alpha; + efd->cb = cb; + efd->data = (void*)data; + evas_object_color_get(efd->clip, (int*)&efd->start.r, (int*)&efd->start.g, (int*)&efd->start.b, (int*)&alpha); + efd->alpha[0] = (unsigned char)alpha; + if (ec) + { + efd->color.r = ec->r; + efd->color.g = ec->g; + efd->color.b = ec->b; + } + else efd->color = (E_Efx_Color){255, 255, 255}; + INF("fade: %p || %d/%d/%d/%d => %d/%d/%d/%d %s over %gs", obj, efd->start.r, efd->start.g, efd->start.b, efd->alpha[0], efd->color.r, efd->color.g, efd->color.b, efd->alpha[1], e_efx_speed_str[speed], total_time); + if (efd->anim) ecore_animator_del(efd->anim); + efd->anim = NULL; + if (total_time) + efd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_fade_cb, efd); + else + _fade_cb(efd, 1.0); + + return EINA_TRUE; +} + +EAPI void +e_efx_fade_reset(Evas_Object *obj) +{ + _fade_stop(obj, EINA_TRUE); +} + +EAPI void +e_efx_fade_stop(Evas_Object *obj) +{ + _fade_stop(obj, EINA_FALSE); +} diff --git a/src/bin/efx/efx_helpers.c b/src/bin/efx/efx_helpers.c new file mode 100644 index 000000000..1dc6d1fd7 --- /dev/null +++ b/src/bin/efx/efx_helpers.c @@ -0,0 +1,115 @@ +#include "e_efx_private.h" + +Eina_Bool +e_efx_rotate_center_init(E_EFX *e, const Evas_Point *center) +{ + if (center) + { + if (!e->map_data.rotate_center) e->map_data.rotate_center = malloc(sizeof(Evas_Point)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->map_data.rotate_center, EINA_FALSE); + e->map_data.rotate_center->x = center->x, e->map_data.rotate_center->y = center->y; + } + else + { + free(e->map_data.rotate_center); + e->map_data.rotate_center = NULL; + } + return EINA_TRUE; +} + +Eina_Bool +e_efx_zoom_center_init(E_EFX *e, const Evas_Point *center) +{ + if (center) + { + if (!e->map_data.zoom_center) e->map_data.zoom_center = malloc(sizeof(Evas_Point)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->map_data.zoom_center, EINA_FALSE); + e->map_data.zoom_center->x = center->x, e->map_data.zoom_center->y = center->y; + } + else + { + free(e->map_data.zoom_center); + e->map_data.zoom_center = NULL; + } + return EINA_TRUE; +} + +Eina_Bool +e_efx_move_center_init(E_EFX *e, const Evas_Point *center) +{ + if (center) + { + if (!e->map_data.move_center) e->map_data.move_center = malloc(sizeof(Evas_Point)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->map_data.move_center, EINA_FALSE); + e->map_data.move_center->x = center->x, e->map_data.move_center->y = center->y; + } + else + { + free(e->map_data.move_center); + e->map_data.move_center = NULL; + } + return EINA_TRUE; +} + +Evas_Map * +e_efx_map_new(Evas_Object *obj) +{ + Evas_Map *map; + + map = evas_map_new(4); + evas_map_smooth_set(map, EINA_FALSE); + evas_map_util_points_populate_from_object(map, obj); + return map; + (void)e_efx_speed_str; +} + +void +e_efx_map_set(Evas_Object *obj, Evas_Map *map) +{ + evas_object_map_set(obj, map); + evas_object_map_enable_set(obj, !!map); + if (map) evas_map_free(map); +} + +void +e_efx_rotate_helper(E_EFX *e, Evas_Object *obj, Evas_Map *map, double degrees) +{ + + if (e->map_data.rotate_center) + evas_map_util_rotate(map, degrees, e->map_data.rotate_center->x, e->map_data.rotate_center->y); + else + { + Evas_Coord x, y, w, h; + evas_object_geometry_get(obj, &x, &y, &w, &h); + evas_map_util_rotate(map, degrees, x + (w / 2), y + (h / 2)); + } + //DBG("rotation: %g", degrees); +// _size_debug(e->obj); +} + +void +e_efx_maps_apply(E_EFX *e, Evas_Object *obj, Evas_Map *map, Eina_Bool rotate, Eina_Bool spin, Eina_Bool zoom) +{ + Eina_Bool new = EINA_FALSE; + if ((!e->owner) && (!e->rotate_data) && (!e->spin_data) && (!e->zoom_data)) return; + if (!map) + { + map = e_efx_map_new(obj); + new = EINA_TRUE; + } + if (rotate && (e->rotate_data || (e->owner && e->owner->rotate_data))) _e_efx_rotate_calc(e->rotate_data, e->owner ? e->owner->rotate_data : NULL, obj, map); + if (spin && (e->spin_data || (e->owner && e->owner->spin_data))) _e_efx_spin_calc(e->spin_data, e->owner ? e->owner->spin_data : NULL, obj, map); + if (zoom && (e->zoom_data || (e->owner && e->owner->zoom_data))) _e_efx_zoom_calc(e->zoom_data, e->owner ? e->owner->zoom_data : NULL, obj, map); + if (new) e_efx_map_set(obj, map); +// DBG("%p: %s %s %s", obj, rotate ? "rotate" : "", spin ? "spin" : "", zoom ? "zoom" : ""); +} + +void +e_efx_clip_setup(Evas_Object *obj, Evas_Object *clip) +{ + Evas_Coord x, y, w, h; + if ((!obj) || (!clip)) return; + evas_object_geometry_get(obj, &x, &y, &w, &h); + evas_object_move(clip, x - w, y - h); + evas_object_resize(clip, 3 * w, 3 * h); +} diff --git a/src/bin/efx/efx_move.c b/src/bin/efx/efx_move.c new file mode 100644 index 000000000..d83714904 --- /dev/null +++ b/src/bin/efx/efx_move.c @@ -0,0 +1,225 @@ +#include "e_efx_private.h" + +typedef struct E_Efx_Move_Data +{ + E_EFX *e; + Ecore_Animator *anim; + E_Efx_Effect_Speed speed; + Evas_Point start; + Evas_Point change; + Evas_Point current; + int degrees; + E_Efx_End_Cb cb; + void *data; +} E_Efx_Move_Data; + +static void +_obj_del(E_Efx_Move_Data *emd, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if (emd->anim) ecore_animator_del(emd->anim); + emd->e->move_data = NULL; + if ((!emd->e->owner) && (!emd->e->followers)) e_efx_free(emd->e); + free(emd); +} + +static void +_move(Evas_Object *obj, int x, int y) +{ + Evas_Coord ox, oy; + + evas_object_geometry_get(obj, &ox, &oy, NULL, NULL); + evas_object_move(obj, ox + x, oy + y); + //DBG("%p to (%d,%d)", obj, ox + x, oy + y); +} + +static Eina_Bool +_move_circle_cb(E_Efx_Move_Data *emd, double pos) +{ + double pct, degrees; + Eina_List *l; + E_EFX *e; + double x, y, r, rad; + Evas_Coord xx, yy, ox, oy, w, h; + + + pct = ecore_animator_pos_map(pos, emd->speed, 0, 0); + degrees = pct * emd->degrees; + evas_object_geometry_get(emd->e->obj, &ox, &oy, &w, &h); + r = (degrees * M_PI) / 180.0; + rad = sqrt((emd->current.x + w/2.0 - emd->e->map_data.move_center->x) * (emd->current.x + w/2.0 - emd->e->map_data.move_center->x) + + (emd->current.y + h/2.0 - emd->e->map_data.move_center->y) * (emd->current.y + h/2.0 - emd->e->map_data.move_center->y)); + x = emd->e->map_data.move_center->x + rad * cos(r); + y = emd->e->map_data.move_center->y + rad * sin(r); + x -= (double)w / 2.; + y -= (double)h / 2.; + xx = lround(x); + yy = lround(y); + //DBG("move: %g || %g,%g", degrees, x, y); + evas_object_move(emd->e->obj, xx, yy); + e_efx_maps_apply(emd->e, emd->e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + EINA_LIST_FOREACH(emd->e->followers, l, e) + { + _move(e->obj, xx - ox, yy - oy); + e_efx_maps_apply(e, e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + } + + if (pos < 1.0) return EINA_TRUE; + + E_EFX_QUEUE_CHECK(emd); + return EINA_TRUE; +} + +static Eina_Bool +_move_cb(E_Efx_Move_Data *emd, double pos) +{ + int x, y; + double pct; + Eina_List *l; + E_EFX *e; + + pct = ecore_animator_pos_map(pos, emd->speed, 0, 0); + x = lround(pct * (double)emd->change.x) - emd->current.x; + y = lround(pct * (double)emd->change.y) - emd->current.y; + _e_efx_resize_adjust(emd->e, &x, &y); + _move(emd->e->obj, x, y); + e_efx_maps_apply(emd->e, emd->e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + EINA_LIST_FOREACH(emd->e->followers, l, e) + { + _move(e->obj, x, y); + e_efx_maps_apply(e, e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + } + + emd->current.x += x; + emd->current.y += y; + if (pos < 1.0) return EINA_TRUE; + + emd->anim = NULL; + E_EFX_QUEUE_CHECK(emd); + return EINA_TRUE; +} + +static void +_move_stop(Evas_Object *obj, Eina_Bool reset) +{ + E_EFX *e; + E_Efx_Move_Data *emd; + + e = evas_object_data_get(obj, "e_efx-data"); + if ((!e) || (!e->move_data)) return; + emd = e->move_data; + if (reset) + { + evas_object_move(obj, emd->start.x, emd->start.y); + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, emd); + if (e_efx_queue_complete(emd->e, emd)) + e_efx_queue_process(emd->e); + _obj_del(emd, NULL, NULL, NULL); + INF("reset moved object %p", obj); + } + else + { + INF("stopped moved object %p", obj); + if (emd->anim) ecore_animator_del(emd->anim); + if (e_efx_queue_complete(emd->e, emd)) + e_efx_queue_process(emd->e); + } +} + +EAPI Eina_Bool +e_efx_move(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *end_point, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Move_Data *emd; + Evas_Coord x, y; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + if (!end_point) return EINA_FALSE; + if (total_time < 0.0) return EINA_FALSE; + if (speed > E_EFX_EFFECT_SPEED_SINUSOIDAL) return EINA_FALSE; + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + + evas_object_geometry_get(obj, &x, &y, NULL, NULL); + INF("move: %p - (%d,%d) -> (%d,%d) over %gs: %s", obj, x, y, end_point->x, end_point->y, total_time, e_efx_speed_str[speed]); + if (!total_time) + { + evas_object_move(obj, end_point->x, end_point->y); + return EINA_TRUE; + } + if (!e->move_data) + { + e->move_data = calloc(1, sizeof(E_Efx_Move_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->move_data, EINA_FALSE); + evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->move_data); + } + emd = e->move_data; + emd->e = e; + emd->speed = speed; + emd->change.x = end_point->x - x; + emd->change.y = end_point->y - y; + emd->current.x = emd->current.y = 0; + emd->cb = cb; + emd->data = (void*)data; + if (emd->anim) ecore_animator_del(emd->anim); + emd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_move_cb, emd); + return EINA_TRUE; +} + + +EAPI Eina_Bool +e_efx_move_circle(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *center, int degrees, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Move_Data *emd; + Evas_Coord x, y; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + if (!degrees) return EINA_FALSE; + if (!center) return EINA_FALSE; + if (total_time < 0.0) return EINA_FALSE; + if (speed > E_EFX_EFFECT_SPEED_SINUSOIDAL) return EINA_FALSE; + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + if (!e_efx_move_center_init(e, center)) return EINA_FALSE; + + evas_object_geometry_get(obj, &x, &y, NULL, NULL); + INF("move: %p - (%d,%d) %d over %gs: %s", obj, x, y, degrees, total_time, e_efx_speed_str[speed]); + if (!total_time) + { + // evas_object_move(obj, end_point->x, end_point->y); + return EINA_TRUE; + } + if (!e->move_data) + { + e->move_data = calloc(1, sizeof(E_Efx_Move_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->move_data, EINA_FALSE); + evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->move_data); + } + emd = e->move_data; + emd->e = e; + emd->speed = speed; + emd->start.x = emd->current.x = x; + emd->start.y = emd->current.y = y; + emd->degrees = degrees; + emd->cb = cb; + emd->data = (void*)data; + if (emd->anim) ecore_animator_del(emd->anim); + emd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_move_circle_cb, emd); + return EINA_TRUE; +} + +EAPI void +e_efx_move_reset(Evas_Object *obj) +{ + _move_stop(obj, EINA_TRUE); +} + +EAPI void +e_efx_move_stop(Evas_Object *obj) +{ + _move_stop(obj, EINA_FALSE); +} diff --git a/src/bin/efx/efx_pan.c b/src/bin/efx/efx_pan.c new file mode 100644 index 000000000..cf16de550 --- /dev/null +++ b/src/bin/efx/efx_pan.c @@ -0,0 +1,390 @@ +#include "e_efx_private.h" + +#define PAN_FUNC_CHECK Smart_Data *sd; sd = evas_object_smart_data_get(obj); if ((!obj) || (!sd) || (evas_object_type_get(obj) && strcmp(evas_object_type_get(obj), "e_efx_pan"))) +#define PAN_CB_SETUP Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return + +typedef struct Smart_Data +{ + E_EFX *e; + Evas_Object *smart_obj; + Evas_Object *child_obj; + Evas_Coord x, y, w, h; + Evas_Coord child_w, child_h, px, py, dx, dy; +} Smart_Data; + +typedef struct E_Efx_Pan_Data +{ + E_EFX *e; + Evas_Object *pan; + Ecore_Animator *anim; + E_Efx_Effect_Speed speed; + Evas_Point change; + Evas_Point current; + int degrees; + E_Efx_End_Cb cb; + void *data; +} E_Efx_Pan_Data; + +static void _smart_pan_child_set(Evas_Object *obj, Evas_Object *child); + +/* local subsystem functions */ +static void _smart_child_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _smart_child_resize_hook(void *data, Evas *e, Evas_Object *obj, void *event_info); + +static void _smart_reconfigure(Smart_Data *sd); +static void _smart_add(Evas_Object *obj); +static void _smart_del(Evas_Object *obj); +static void _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y); +static void _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h); +static void _smart_show(Evas_Object *obj); +static void _smart_hide(Evas_Object *obj); +static void _smart_color_set(Evas_Object *obj, int r, int g, int b, int a); +static void _smart_clip_set(Evas_Object *obj, Evas_Object * clip); +static void _smart_clip_unset(Evas_Object *obj); +static void _smart_init(void); + +/* local subsystem globals */ +static Evas_Smart *_smart = NULL; + +/* local subsystem functions */ +static void +_smart_child_del_hook(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Smart_Data *sd; + + sd = data; + sd->child_obj = NULL; +} + +static void +_smart_child_resize_hook(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Smart_Data *sd; + Evas_Coord w, h; + + sd = data; + evas_object_geometry_get(sd->child_obj, NULL, NULL, &w, &h); + if ((w != sd->child_w) || (h != sd->child_h)) + { + sd->child_w = w; + sd->child_h = h; + _smart_reconfigure(sd); + } +} + +static void +_smart_reconfigure(Smart_Data *sd) +{ + Eina_List *l; + E_EFX *e; + Evas_Coord x, y; + + evas_object_move(sd->child_obj, sd->x - sd->px, sd->y - sd->py); + e_efx_maps_apply(sd->e, sd->child_obj, NULL, E_EFX_MAPS_APPLY_ALL); + //DBG("DELTA: (%d,%d)", sd->dx, sd->dy); + EINA_LIST_FOREACH(sd->e->followers, l, e) + { + evas_object_geometry_get(e->obj, &x, &y, NULL, NULL); + evas_object_move(e->obj, x - sd->dx, y - sd->dy); + e_efx_maps_apply(e, e->obj, NULL, E_EFX_MAPS_APPLY_ALL); +// _size_debug(e->obj); + } +} + +static void +_smart_add(Evas_Object *obj) +{ + Smart_Data *sd; + + sd = calloc(1, sizeof(Smart_Data)); + if (!sd) return; + sd->smart_obj = obj; + sd->x = 0; + sd->y = 0; + sd->w = 0; + sd->h = 0; + evas_object_smart_data_set(obj, sd); +} + +static void +_smart_del(Evas_Object *obj) +{ + PAN_CB_SETUP; + _smart_pan_child_set(obj, NULL); + free(sd); +} + +static void +_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) +{ + PAN_CB_SETUP; + sd->x = x; + sd->y = y; + _smart_reconfigure(sd); +} + +static void +_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) +{ + PAN_CB_SETUP; + sd->w = w; + sd->h = h; + _smart_reconfigure(sd); +} + +static void +_smart_show(Evas_Object *obj) +{ + PAN_CB_SETUP; + if (sd->child_obj) + evas_object_show(sd->child_obj); +} + +static void +_smart_hide(Evas_Object *obj) +{ + PAN_CB_SETUP; + if (sd->child_obj) + evas_object_hide(sd->child_obj); +} + +static void +_smart_color_set(Evas_Object *obj, int r, int g, int b, int a) +{ + PAN_CB_SETUP; + if (sd->child_obj) + evas_object_color_set(sd->child_obj, r, g, b, a); +} + +static void +_smart_clip_set(Evas_Object *obj, Evas_Object *clip) +{ + PAN_CB_SETUP; + if (sd->child_obj) + evas_object_clip_set(sd->child_obj, clip); +} + +static void +_smart_clip_unset(Evas_Object *obj) +{ + PAN_CB_SETUP; + if (sd->child_obj) + evas_object_clip_unset(sd->child_obj); +} + +/* never need to touch this */ + +static void +_smart_init(void) +{ + if (_smart) return; + { + static const Evas_Smart_Class sc = + { + "e_efx_pan", + EVAS_SMART_CLASS_VERSION, + _smart_add, + _smart_del, + _smart_move, + _smart_resize, + _smart_show, + _smart_hide, + _smart_color_set, + _smart_clip_set, + _smart_clip_unset, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + }; + _smart = evas_smart_class_new(&sc); + } +} + + +static Evas_Object * +_smart_pan_add(Evas *evas) +{ + _smart_init(); + return evas_object_smart_add(evas, _smart); +} + +static void +_smart_pan_child_set(Evas_Object *obj, Evas_Object *child) +{ + PAN_FUNC_CHECK return; + if (child == sd->child_obj) return; + if (sd->child_obj) + { + evas_object_clip_unset(sd->child_obj); + evas_object_smart_member_del(sd->child_obj); + evas_object_event_callback_del_full(sd->child_obj, EVAS_CALLBACK_FREE, _smart_child_del_hook, sd); + evas_object_event_callback_del_full(sd->child_obj, EVAS_CALLBACK_RESIZE, _smart_child_resize_hook, sd); + sd->child_obj = NULL; + } + if (child) + { + Evas_Coord w, h; + int r, g, b, a; + + sd->child_obj = child; + evas_object_smart_member_add(sd->child_obj, sd->smart_obj); + evas_object_geometry_get(sd->child_obj, NULL, NULL, &w, &h); + sd->child_w = w; + sd->child_h = h; + evas_object_event_callback_add(child, EVAS_CALLBACK_FREE, _smart_child_del_hook, sd); + evas_object_event_callback_add(child, EVAS_CALLBACK_RESIZE, _smart_child_resize_hook, sd); + evas_object_color_get(sd->smart_obj, &r, &g, &b, &a); + evas_object_color_set(sd->child_obj, r, g, b, a); + evas_object_clip_set(sd->child_obj, evas_object_clip_get(sd->smart_obj)); + if (evas_object_visible_get(sd->smart_obj)) evas_object_show(sd->child_obj); + else evas_object_hide(sd->child_obj); + _smart_reconfigure(sd); + } +} + +static void +_smart_pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y) +{ + PAN_FUNC_CHECK return; + if ((x == sd->px) && (y == sd->py)) return; + sd->dx = x - sd->px; + sd->dy = y - sd->py; + sd->px = x; + sd->py = y; + _smart_reconfigure(sd); +} + +static void +_smart_pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y) +{ + PAN_FUNC_CHECK return; + if (x) *x = sd->px; + if (y) *y = sd->py; +} + +/* +static void +_smart_pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y) +{ + PAN_FUNC_CHECK return; + if (x) + { + if (sd->w < sd->child_w) *x = sd->child_w - sd->w; + else *x = 0; + } + if (y) + { + if (sd->h < sd->child_h) *y = sd->child_h - sd->h; + else *y = 0; + } +} +*/ + +static void +_obj_del(E_Efx_Pan_Data *epd, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if (epd->anim) ecore_animator_del(epd->anim); + if (epd->pan) + { + evas_object_del(epd->pan); + epd->pan = NULL; + } + epd->e->pan_data = NULL; + if ((!epd->e->owner) && (!epd->e->followers)) e_efx_free(epd->e); + free(epd); +} + +static Eina_Bool +_pan_cb(E_Efx_Pan_Data *epd, double pos) +{ + int x, y, px = 0, py = 0; + double pct; + + pct = ecore_animator_pos_map(pos, epd->speed, 0, 0); + x = lround(pct * (double)epd->change.x) - epd->current.x; + y = lround(pct * (double)epd->change.y) - epd->current.y; + _smart_pan_get(epd->pan, &px, &py); + //DBG("PAN: (%d,%d) += (%d,%d)", px, py, x, y); + _smart_pan_set(epd->pan, px + x, py + y); + epd->e->map_data.pan.x = px + x; + epd->e->map_data.pan.y = py + y; + + epd->current.x += x; + epd->current.y += y; + if (pos < 1.0) return EINA_TRUE; + + epd->anim = NULL; + E_EFX_QUEUE_CHECK(epd); + return EINA_TRUE; +} + +static E_EFX * +_e_efx_pan_init(Evas_Object *obj) +{ + E_EFX *e; + E_Efx_Pan_Data *epd; + Smart_Data *sd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL); + + if (!e->pan_data) + { + e->pan_data = calloc(1, sizeof(E_Efx_Pan_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->pan_data, EINA_FALSE); + evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->pan_data); + epd = e->pan_data; + epd->pan = _smart_pan_add(evas_object_evas_get(obj)); + sd = evas_object_smart_data_get(epd->pan); + sd->e = e; + _smart_pan_child_set(epd->pan, obj); + evas_object_show(epd->pan); + } + return e; +} + +EAPI Eina_Bool +e_efx_pan_init(Evas_Object *obj) +{ + return !!_e_efx_pan_init(obj); +} + +EAPI Eina_Bool +e_efx_pan(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *distance, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Pan_Data *epd; + Evas_Coord x = 0, y = 0; + + if (!distance) return EINA_FALSE; + if (total_time < 0.0) return EINA_FALSE; + if (speed > E_EFX_EFFECT_SPEED_SINUSOIDAL) return EINA_FALSE; + + e = _e_efx_pan_init(obj); + if (!e) return EINA_FALSE; + epd = e->pan_data; + epd->e = e; + _smart_pan_get(epd->pan, &x, &y); + INF("pan: %p - (%d,%d) += (%d,%d) over %gs: %s", obj, x, y, distance->x, distance->y, total_time, e_efx_speed_str[speed]); + if (!total_time) + { + _smart_pan_set(epd->pan, x + distance->x, y + distance->y); + return EINA_TRUE; + } + + epd->speed = speed; + epd->change.x = distance->x; + epd->change.y = distance->y; + epd->current.x = epd->current.y = 0; + epd->cb = cb; + epd->data = (void*)data; + if (epd->anim) ecore_animator_del(epd->anim); + epd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_pan_cb, epd); + return EINA_TRUE; +} diff --git a/src/bin/efx/efx_queue.c b/src/bin/efx/efx_queue.c new file mode 100644 index 000000000..fed73027c --- /dev/null +++ b/src/bin/efx/efx_queue.c @@ -0,0 +1,301 @@ +#include "e_efx_private.h" + +struct E_Efx_Queue_Data +{ + E_EFX *e; + E_Efx_Queued_Effect effect; + E_Efx_Effect_Speed speed; + double time; + E_Efx_End_Cb cb; + void *data; + + Eina_List *subeffects; + void *effect_data; + Eina_Bool active : 1; +}; + +static void +_queue_advance(E_Efx_Queue_Data *eqd) +{ + E_Efx_Queue_Data *run; + Eina_List *l; + + INF("queue_advance: %p", eqd->e->obj); + switch (eqd->effect.type) + { + case E_EFX_EFFECT_TYPE_ROTATE: + e_efx_rotate(eqd->e->obj, eqd->speed, eqd->effect.effect.rotation.degrees, eqd->effect.effect.rotation.center, eqd->time, eqd->cb, eqd->data); + eqd->effect_data = eqd->e->rotate_data; + break; + case E_EFX_EFFECT_TYPE_ZOOM: + e_efx_zoom(eqd->e->obj, eqd->speed, eqd->effect.effect.zoom.start, eqd->effect.effect.zoom.end, eqd->effect.effect.zoom.center, eqd->time, eqd->cb, eqd->data); + eqd->effect_data = eqd->e->zoom_data; + break; + case E_EFX_EFFECT_TYPE_MOVE: + e_efx_move(eqd->e->obj, eqd->speed, &eqd->effect.effect.movement.point, eqd->time, eqd->cb, eqd->data); + eqd->effect_data = eqd->e->move_data; + break; + case E_EFX_EFFECT_TYPE_PAN: + e_efx_pan(eqd->e->obj, eqd->speed, &eqd->effect.effect.movement.point, eqd->time, eqd->cb, eqd->data); + eqd->effect_data = eqd->e->pan_data; + break; + case E_EFX_EFFECT_TYPE_FADE: + e_efx_fade(eqd->e->obj, eqd->speed, &eqd->effect.effect.fade.color, eqd->effect.effect.fade.alpha, eqd->time, eqd->cb, eqd->data); + eqd->effect_data = eqd->e->fade_data; + break; + case E_EFX_EFFECT_TYPE_RESIZE: + default: + e_efx_resize(eqd->e->obj, eqd->speed, eqd->effect.effect.resize.point, eqd->effect.effect.resize.w, eqd->effect.effect.resize.h, eqd->time, eqd->cb, eqd->data); + eqd->effect_data = eqd->e->resize_data; + } + eqd->active = EINA_TRUE; + EINA_LIST_FOREACH(eqd->subeffects, l, run) + _queue_advance(run); +} + +void +e_efx_queue_process(E_EFX *e) +{ + E_Efx_Queue_Data *eqd; + + eqd = eina_list_data_get(e->queue); + if (!eqd) return; + if (eqd->active) return; + + _queue_advance(eqd); +} + +void +eqd_free(E_Efx_Queue_Data *eqd) +{ + E_Efx_Queue_Data *sub; + if (!eqd) return; + if (eqd->effect.type == E_EFX_EFFECT_TYPE_ROTATE) + free(eqd->effect.effect.rotation.center); + else if (eqd->effect.type == E_EFX_EFFECT_TYPE_ZOOM) + free(eqd->effect.effect.zoom.center); + else if (eqd->effect.type == E_EFX_EFFECT_TYPE_RESIZE) + free(eqd->effect.effect.resize.point); + EINA_LIST_FREE(eqd->subeffects, sub) + eqd_free(sub); + free(eqd); +} + +Eina_Bool +e_efx_queue_complete(E_EFX *e, void *effect_data) +{ + E_Efx_Queue_Data *eqd; + + eqd = eina_list_data_get(e->queue); + if (!eqd) + { + e_efx_free(e); + return EINA_FALSE; + } + DBG("%p: %p", e->obj, effect_data); + if (eqd->effect_data != effect_data) return EINA_FALSE; + e->queue = eina_list_remove_list(e->queue, e->queue); + eqd_free(eqd); + return !!e->queue; +} + +E_Efx_Queue_Data * +eqd_new(E_EFX *e, E_Efx_Effect_Speed speed, const E_Efx_Queued_Effect *effect, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_Efx_Queue_Data *eqd; + + eqd = calloc(1, sizeof(E_Efx_Queue_Data)); + memcpy(&eqd->effect, effect, sizeof(E_Efx_Queued_Effect)); + eqd->e = e; + if (effect->type == E_EFX_EFFECT_TYPE_ROTATE) + { + if (effect->effect.rotation.center) + { + eqd->effect.effect.rotation.center = malloc(sizeof(Evas_Point)); + if (!eqd->effect.effect.rotation.center) goto error; + memcpy(eqd->effect.effect.rotation.center, effect->effect.rotation.center, sizeof(Evas_Point)); + } + } + else if (effect->type == E_EFX_EFFECT_TYPE_ZOOM) + { + if (effect->effect.zoom.center) + { + eqd->effect.effect.zoom.center = malloc(sizeof(Evas_Point)); + if (!eqd->effect.effect.zoom.center) goto error; + memcpy(eqd->effect.effect.zoom.center, effect->effect.zoom.center, sizeof(Evas_Point)); + } + } + else if (effect->type == E_EFX_EFFECT_TYPE_RESIZE) + { + if (effect->effect.resize.point) + { + eqd->effect.effect.resize.point = malloc(sizeof(Evas_Point)); + if (!eqd->effect.effect.resize.point) goto error; + memcpy(eqd->effect.effect.resize.point, effect->effect.resize.point, sizeof(Evas_Point)); + } + } + eqd->speed = speed; + eqd->time = total_time; + eqd->cb = cb; + eqd->data = (void*)data; + return eqd; +error: + free(eqd); + e_efx_free(e); + return NULL; +} + + +EAPI void +e_efx_queue_run(Evas_Object *obj) +{ + E_EFX *e; + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return; + e_efx_queue_process(e); +} + +EAPI E_Efx_Queue_Data * +e_efx_queue_append(Evas_Object *obj, E_Efx_Effect_Speed speed, const E_Efx_Queued_Effect *effect, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Queue_Data *eqd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(effect, NULL); + EINA_SAFETY_ON_FALSE_RETURN_VAL(total_time >= 0.0, NULL); + if (effect->type > E_EFX_EFFECT_TYPE_RESIZE) return NULL; + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL); + + eqd = eqd_new(e, speed, effect, total_time, cb, data); + EINA_SAFETY_ON_NULL_RETURN_VAL(eqd, NULL); + + e->queue = eina_list_append(e->queue, eqd); + return eqd; + (void)e_efx_speed_str; +} + +EAPI E_Efx_Queue_Data * +e_efx_queue_prepend(Evas_Object *obj, E_Efx_Effect_Speed speed, const E_Efx_Queued_Effect *effect, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Queue_Data *eqd, *eqd2; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(effect, NULL); + EINA_SAFETY_ON_FALSE_RETURN_VAL(total_time >= 0.0, NULL); + if (effect->type > E_EFX_EFFECT_TYPE_RESIZE) return NULL; + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL); + + eqd = eqd_new(e, speed, effect, total_time, cb, data); + EINA_SAFETY_ON_NULL_RETURN_VAL(eqd, NULL); + + if (e->queue) + { + eqd2 = eina_list_data_get(e->queue); + if (eqd2->active) + e->queue = eina_list_append_relative_list(e->queue, eqd, e->queue); + else + e->queue = eina_list_prepend(e->queue, eqd); + } + else + e->queue = eina_list_append(e->queue, eqd); + return eqd; + (void)e_efx_speed_str; +} + +EAPI void +e_efx_queue_promote(Evas_Object *obj, E_Efx_Queue_Data *eqd) +{ + E_EFX *e; + + EINA_SAFETY_ON_NULL_RETURN(obj); + EINA_SAFETY_ON_NULL_RETURN(eqd); + e = evas_object_data_get(obj, "e_efx-data"); + EINA_SAFETY_ON_NULL_RETURN(e); + EINA_SAFETY_ON_NULL_RETURN(e->queue); + EINA_SAFETY_ON_TRUE_RETURN(eqd->active); + + if (e->queue->data == eqd) return; + + e->queue = eina_list_remove(e->queue, eqd); + e->queue = eina_list_append_relative_list(e->queue, eqd, e->queue); +} + +EAPI void +e_efx_queue_demote(Evas_Object *obj, E_Efx_Queue_Data *eqd) +{ + E_EFX *e; + + EINA_SAFETY_ON_NULL_RETURN(obj); + EINA_SAFETY_ON_NULL_RETURN(eqd); + e = evas_object_data_get(obj, "e_efx-data"); + EINA_SAFETY_ON_NULL_RETURN(e); + EINA_SAFETY_ON_NULL_RETURN(e->queue); + EINA_SAFETY_ON_TRUE_RETURN(eqd->active); + + if (eina_list_last(e->queue)->data == eqd) return; + + e->queue = eina_list_demote_list(e->queue, eina_list_data_find_list(e->queue, eqd)); +} + +EAPI void +e_efx_queue_delete(Evas_Object *obj, E_Efx_Queue_Data *eqd) +{ + E_EFX *e; + + EINA_SAFETY_ON_NULL_RETURN(obj); + EINA_SAFETY_ON_NULL_RETURN(eqd); + e = evas_object_data_get(obj, "e_efx-data"); + EINA_SAFETY_ON_NULL_RETURN(e); + EINA_SAFETY_ON_NULL_RETURN(e->queue); + EINA_SAFETY_ON_TRUE_RETURN(eqd->active); + + e->queue = eina_list_remove(e->queue, eqd); + eqd_free(eqd); +} + +EAPI void +e_efx_queue_clear(Evas_Object *obj) +{ + E_EFX *e; + E_Efx_Queue_Data *eqd; + Eina_List *l, *ll; + + EINA_SAFETY_ON_NULL_RETURN(obj); + e = evas_object_data_get(obj, "e_efx-data"); + EINA_SAFETY_ON_NULL_RETURN(e); + if (!e->queue) return; + + EINA_LIST_FOREACH_SAFE(e->queue, l, ll, eqd) + { + if (eqd->active) continue; + e->queue = eina_list_remove_list(e->queue, l); + eqd_free(eqd); + } +} + +EAPI Eina_Bool +e_efx_queue_effect_attach(E_Efx_Queue_Data *eqd, E_Efx_Effect_Speed speed, const E_Efx_Queued_Effect *effect, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Queue_Data *sub; + + EINA_SAFETY_ON_NULL_RETURN_VAL(eqd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(effect, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(total_time >= 0.0, EINA_FALSE); + if (effect->type > E_EFX_EFFECT_TYPE_RESIZE) return EINA_FALSE; + e = eqd->e; + + sub = eqd_new(e, speed, effect, total_time, cb, data); + EINA_SAFETY_ON_NULL_RETURN_VAL(sub, EINA_FALSE); + + eqd->subeffects = eina_list_append(eqd->subeffects, sub); + return EINA_TRUE; + (void)e_efx_speed_str; +} diff --git a/src/bin/efx/efx_resize.c b/src/bin/efx/efx_resize.c new file mode 100644 index 000000000..054ba0b3b --- /dev/null +++ b/src/bin/efx/efx_resize.c @@ -0,0 +1,225 @@ +#include "e_efx_private.h" + +typedef enum +{ + NONE, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT +} Anchor; + +typedef struct E_Efx_Resize_Data +{ + E_EFX *e; + E_Efx_Effect_Speed speed; + Ecore_Animator *anim; + int w, h; + int start_w, start_h; + E_Efx_End_Cb cb; + void *data; + Anchor anchor_type; + Evas_Point anchor; + Eina_Bool moving : 1; +} E_Efx_Resize_Data; + +static void +_obj_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Efx_Resize_Data *erd = data; + + if (erd->anim) ecore_animator_del(erd->anim); + erd->e->resize_data = NULL; + if ((!erd->e->owner) && (!erd->e->followers)) e_efx_free(erd->e); + free(erd); +} + +static void +_resize_anchor(E_Efx_Resize_Data *erd) +{ + int x = 0, y = 0; + int cx, cy; + + if (!erd->anchor_type) return; + + _e_efx_resize_adjust(erd->e, &x, &y); + if ((!x) && (!y)) return; + + evas_object_geometry_get(erd->e->obj, &cx, &cy, NULL, NULL); + x += cx, y += cy; + evas_object_move(erd->e->obj, x, y); +} + +static Eina_Bool +_resize_cb(E_Efx_Resize_Data *erd, double pos) +{ + double factor; + + if (pos < 1.0) + { + int w, h; + + factor = ecore_animator_pos_map(pos, erd->speed, 0, 0); + w = lround(factor * (erd->w - erd->start_w)) + erd->start_w; + h = lround(factor * (erd->h - erd->start_h)) + erd->start_h; + evas_object_resize(erd->e->obj, w, h); + _resize_anchor(erd); + return EINA_TRUE; + } + /* lround will usually be off by 1 at the end, so we manually set this here */ + evas_object_resize(erd->e->obj, erd->w, erd->h); + _resize_anchor(erd); + + erd->anim = NULL; + E_EFX_QUEUE_CHECK(erd); + return EINA_TRUE; +} + +static void +_resize_stop(Evas_Object *obj, Eina_Bool reset) +{ + E_EFX *e; + E_Efx_Resize_Data *erd; + + e = evas_object_data_get(obj, "e_efx-data"); + if ((!e) || (!e->resize_data)) return; + erd = e->resize_data; + if (reset) + { + evas_object_resize(obj, erd->start_w, erd->start_h); + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, erd); + if (erd->moving) + { + erd->moving = 0; + e_efx_move_reset(obj); + } + else if (e_efx_queue_complete(erd->e, erd)) + e_efx_queue_process(erd->e); + _obj_del(erd, NULL, NULL, NULL); + INF("reset resized object %p", obj); + } + else + { + INF("stopped resized object %p", obj); + if (erd->anim) ecore_animator_del(erd->anim); + if (erd->moving) + { + erd->moving = 0; + e_efx_move_stop(obj); + } + if (e_efx_queue_complete(erd->e, erd)) + e_efx_queue_process(erd->e); + } +} + +void +_e_efx_resize_adjust(E_EFX *e, int *ax, int *ay) +{ + E_Efx_Resize_Data *erd = e->resize_data; + int x, y, w, h; + + if (!erd) return; + evas_object_geometry_get(e->obj, &x, &y, &w, &h); + switch (erd->anchor_type) + { + case TOP_RIGHT: + *ax = erd->anchor.x - (x + w); + *ay = erd->anchor.y - y; + break; + case BOTTOM_LEFT: + *ax = erd->anchor.x - x; + *ay = erd->anchor.y - (y + h); + break; + case BOTTOM_RIGHT: + *ax = erd->anchor.x - (x + w); + *ay = erd->anchor.y - (y + h); + break; + default: break; + } +} + +EAPI Eina_Bool +e_efx_resize(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *position, int w, int h, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Resize_Data *erd; + int x, y; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(w < 0, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(h < 0, EINA_FALSE); + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + erd = e->resize_data; + if (!erd) + { + e->resize_data = erd = calloc(1, sizeof(E_Efx_Resize_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(erd, EINA_FALSE); + evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->resize_data); + } + + erd->e = e; + erd->anchor_type = NONE; + erd->w = w; + erd->h = h; + erd->cb = cb; + erd->data = (void*)data; + evas_object_geometry_get(obj, &x, &y, &erd->start_w, &erd->start_h); + INF("resize: %p || %dx%d => %dx%d %s over %gs", obj, erd->start_w, erd->start_h, w, h, e_efx_speed_str[speed], total_time); + if (position && ((position->x != x) || (position->y != y))) + { + Evas_Point tr, bl, br; + Evas_Point atr, abl, abr; + + tr = (Evas_Point){x + erd->start_w, y}; + bl = (Evas_Point){x, y + erd->start_h}; + br = (Evas_Point){x + erd->start_w, y + erd->start_h}; + atr = (Evas_Point){position->x + w, position->y}; + abl = (Evas_Point){position->x, position->y + h}; + abr = (Evas_Point){position->x + w, position->y + h}; + if (!memcmp(&tr, &atr, sizeof(Evas_Point))) + { + erd->anchor_type = TOP_RIGHT; + erd->anchor = tr; + } + else if (!memcmp(&bl, &abl, sizeof(Evas_Point))) + { + erd->anchor_type = BOTTOM_LEFT; + erd->anchor = bl; + } + else if (!memcmp(&br, &abr, sizeof(Evas_Point))) + { + erd->anchor_type = BOTTOM_RIGHT; + erd->anchor = br; + } + + if (!e_efx_move(obj, speed, position, total_time, NULL, NULL)) + { + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->resize_data); + free(erd); + e->resize_data = NULL; + e_efx_free(e); + return EINA_FALSE; + } + else + erd->moving = 1; + } + if (total_time) + erd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_resize_cb, erd); + else + _resize_cb(erd, 1.0); + + return EINA_TRUE; +} + +EAPI void +e_efx_resize_reset(Evas_Object *obj) +{ + _resize_stop(obj, EINA_TRUE); +} + +EAPI void +e_efx_resize_stop(Evas_Object *obj) +{ + _resize_stop(obj, EINA_FALSE); +} diff --git a/src/bin/efx/efx_rotate.c b/src/bin/efx/efx_rotate.c new file mode 100644 index 000000000..b6239cf17 --- /dev/null +++ b/src/bin/efx/efx_rotate.c @@ -0,0 +1,145 @@ +#include "e_efx_private.h" + +typedef struct E_Efx_Rotate_Data +{ + E_EFX *e; + Ecore_Animator *anim; + E_Efx_Effect_Speed speed; + double start_degrees; + double degrees; + E_Efx_End_Cb cb; + void *data; +} E_Efx_Rotate_Data; + +static void +_obj_del(E_Efx_Rotate_Data *erd, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if (erd->anim) ecore_animator_del(erd->anim); + erd->e->rotate_data = NULL; + if ((!erd->e->owner) && (!erd->e->followers)) e_efx_free(erd->e); + free(erd); +} + +static Eina_Bool +_rotate_cb(E_Efx_Rotate_Data *erd, double pos) +{ + double degrees; + Eina_List *l; + E_EFX *e; + + degrees = ecore_animator_pos_map(pos, erd->speed, 0, 0); + erd->e->map_data.rotation = degrees * erd->degrees + erd->start_degrees; + //DBG("erd->e->map_data.rotation=%g,erd->degrees=%g,erd->start_degrees=%g", erd->e->map_data.rotation, erd->degrees, erd->start_degrees); + e_efx_maps_apply(erd->e, erd->e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + EINA_LIST_FOREACH(erd->e->followers, l, e) + e_efx_maps_apply(e, e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + + if (pos < 1.0) return EINA_TRUE; + + erd->anim = NULL; + E_EFX_QUEUE_CHECK(erd); + return EINA_TRUE; +} + +static void +_rotate_stop(Evas_Object *obj, Eina_Bool reset) +{ + E_EFX *e; + E_Efx_Rotate_Data *erd; + + e = evas_object_data_get(obj, "e_efx-data"); + if ((!e) || (!e->rotate_data)) return; + erd = e->rotate_data; + if (reset) + { + erd->start_degrees = 0; + _rotate_cb(erd, 0); + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, erd); + erd->e->map_data.rotation = 0; + if (e_efx_queue_complete(erd->e, erd)) + e_efx_queue_process(erd->e); + _obj_del(erd, NULL, NULL, NULL); + INF("reset rotating object %p", obj); + } + else + { + if (erd->anim) ecore_animator_del(erd->anim); + erd->anim = NULL; + INF("stopped rotating object %p", obj); + if (e_efx_queue_complete(erd->e, erd)) + e_efx_queue_process(erd->e); + } +} + +void +_e_efx_rotate_calc(void *data, void *owner, Evas_Object *obj, Evas_Map *map) +{ + E_Efx_Rotate_Data *erd = data; + E_Efx_Rotate_Data *erd2 = owner; + e_efx_rotate_helper(erd2 ? erd2->e : (erd ? erd->e : NULL), obj, map, (erd ? erd->e->map_data.rotation : 0) + (erd2 ? erd2->e->map_data.rotation : 0)); +} + +EAPI Eina_Bool +e_efx_rotate(Evas_Object *obj, E_Efx_Effect_Speed speed, double degrees, const Evas_Point *center, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Rotate_Data *erd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + if (!degrees) return EINA_FALSE; + if (total_time < 0.0) return EINA_FALSE; + if (speed > E_EFX_EFFECT_SPEED_SINUSOIDAL) return EINA_FALSE; + /* can't rotate a spinning object, so we stop it first */ + e = evas_object_data_get(obj, "e_efx-data"); + if (e) + { + if (e->spin_data) e_efx_spin_stop(obj); + if (e->rotate_data) + { + erd = e->rotate_data; + if (erd->anim) e_efx_rotate_stop(obj); + } + } + else + { + e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + } + + if (!e_efx_rotate_center_init(e, center)) return EINA_FALSE; + INF("rotate: %p - %g degrees over %gs: %s", obj, degrees, total_time, e_efx_speed_str[speed]); + if (!e->rotate_data) + { + e->rotate_data = calloc(1, sizeof(E_Efx_Rotate_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->rotate_data, EINA_FALSE); + evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->rotate_data); + } + erd = e->rotate_data; + erd->e = e; + erd->speed = speed; + erd->degrees = degrees; + erd->start_degrees = e->map_data.rotation; + erd->cb = cb; + erd->data = (void*)data; + if (!total_time) + { + e->map_data.rotation += degrees; + _rotate_cb(erd, 1.0); + return EINA_TRUE; + } + if (erd->anim) ecore_animator_del(erd->anim); + erd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_rotate_cb, erd); + return EINA_TRUE; +} + +EAPI void +e_efx_rotate_reset(Evas_Object *obj) +{ + _rotate_stop(obj, EINA_TRUE); +} + +EAPI void +e_efx_rotate_stop(Evas_Object *obj) +{ + _rotate_stop(obj, EINA_FALSE); +} diff --git a/src/bin/efx/efx_spin.c b/src/bin/efx/efx_spin.c new file mode 100644 index 000000000..dc36126f4 --- /dev/null +++ b/src/bin/efx/efx_spin.c @@ -0,0 +1,148 @@ +#include "e_efx_private.h" + +typedef struct E_Efx_Spin_Data +{ + E_EFX *e; + Ecore_Animator *anim; + long dps; + double start; + unsigned int frame; +} E_Efx_Spin_Data; + + +static void +_obj_del(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + E_EFX *e; + E_Efx_Spin_Data *esd; + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return; /* bug? */ + esd = e->spin_data; + if (esd) + { + if (esd->anim) ecore_animator_del(esd->anim); + e->spin_data = NULL; + free(esd); + } + if ((!e->owner) && (!e->followers)) e_efx_free(e); +} + +static Eina_Bool +_spin_cb(E_Efx_Spin_Data *esd) +{ + double fps; + Eina_List *l; + E_EFX *e; + + fps = 1.0 / ecore_animator_frametime_get(); + + esd->e->map_data.rotation = (double)esd->frame * ((double)esd->dps / fps) + esd->start; + e_efx_maps_apply(esd->e, esd->e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + EINA_LIST_FOREACH(esd->e->followers, l, e) + { + e_efx_maps_apply(e, e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + } +/* + if (esd->frame % (int)fps == 0) + DBG("frame: %u || rotate: %g", esd->frame, esd->e->map_data.rotation); +*/ + if (!fmod(esd->e->map_data.rotation, 360.0)) esd->frame = 0; + esd->frame++; /* FIXME: this may overflow */ + + return EINA_TRUE; +} + +static void +_spin_stop(Evas_Object *obj, Eina_Bool reset) +{ + E_EFX *e; + E_Efx_Spin_Data *esd; + + e = evas_object_data_get(obj, "e_efx-data"); + if ((!e) || (!e->spin_data)) return; + esd = e->spin_data; + esd->frame = 0; + if (reset) + { + esd->e->map_data.rotation = esd->start = 0; + e_efx_rotate_center_init(esd->e, NULL); + _spin_cb(esd); + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, esd); + _obj_del(NULL, NULL, e->obj, NULL); + INF("reset spinning object %p", obj); + } + else + { + INF("stopped spinning object %p", obj); + if (esd->anim) ecore_animator_del(esd->anim); + free(esd); + e->spin_data = NULL; + } +} + +void +_e_efx_spin_calc(void *data, void *owner, Evas_Object *obj, Evas_Map *map) +{ + E_Efx_Spin_Data *esd = data; + E_Efx_Spin_Data *esd2 = owner; + e_efx_rotate_helper(esd2 ? esd2->e : (esd ? esd->e : NULL), obj, map, (esd ? esd->e->map_data.rotation : 0) + (esd2 ? esd2->e->map_data.rotation : 0)); +} + +EAPI Eina_Bool +e_efx_spin_start(Evas_Object *obj, long dps, const Evas_Point *center) +{ + E_EFX *e; + E_Efx_Spin_Data *esd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(dps, EINA_FALSE); + /* must stop rotating if object is in motion */ + e_efx_rotate_stop(obj); + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + if (!e_efx_rotate_center_init(e, center)) return EINA_FALSE; + esd = e->spin_data; + if (esd) + { + esd->dps = dps; + esd->start = esd->e->map_data.rotation; + if (!esd->anim) esd->anim = ecore_animator_add((Ecore_Task_Cb)_spin_cb, esd); + if (e->map_data.rotate_center) + INF("spin modified: %p - %s around (%d,%d) || %lddps", obj, (dps > 0) ? "clockwise" : "counter-clockwise", + e->map_data.rotate_center->x, e->map_data.rotate_center->y, dps); + else + INF("spin modified: %p - %s || %lddps", obj, (dps > 0) ? "clockwise" : "counter-clockwise", dps); + return EINA_TRUE; + } + else + { + e->spin_data = esd = calloc(1, sizeof(E_Efx_Spin_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(esd, EINA_FALSE); + evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->spin_data); + } + + esd->e = e; + esd->dps = dps; + esd->start = e->map_data.rotation; + if (e->map_data.rotate_center) + INF("spin: %p - %s around (%d,%d) || %lddps", obj, (dps > 0) ? "clockwise" : "counter-clockwise", + e->map_data.rotate_center->x, e->map_data.rotate_center->y, dps); + else + INF("spin: %p - %s || %lddps", obj, (dps > 0) ? "clockwise" : "counter-clockwise", dps); + esd->anim = ecore_animator_add((Ecore_Task_Cb)_spin_cb, esd); + return EINA_TRUE; + (void)e_efx_speed_str; +} + +EAPI void +e_efx_spin_reset(Evas_Object *obj) +{ + _spin_stop(obj, EINA_TRUE); +} +EAPI void +e_efx_spin_stop(Evas_Object *obj) +{ + _spin_stop(obj, EINA_FALSE); +} diff --git a/src/bin/efx/efx_util.c b/src/bin/efx/efx_util.c new file mode 100644 index 000000000..fc0fc1e28 --- /dev/null +++ b/src/bin/efx/efx_util.c @@ -0,0 +1,137 @@ +#include "e_efx_private.h" + +static void +_obj_del(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + E_EFX *e; + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return; + if (e->owner) + e->owner->followers = eina_list_remove(e->owner->followers, e); + e->owner = NULL; + e_efx_free(e); +} + +EAPI void +e_efx_realize(Evas_Object *obj) +{ + E_EFX *e; + Evas_Coord x, y, ox, oy, w, h; + Evas_Point p1, p2; + double zw, zh; + Evas_Map *map; + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return; + if (!e->map_data.rotate_center) return; + evas_object_geometry_get(obj, &ox, &oy, &w, &h); + map = (Evas_Map*)evas_object_map_get(obj); + if (!map) return; + evas_map_point_coord_get(map, 0, &p1.x, &p1.y, NULL); + evas_map_point_coord_get(map, 2, &p2.x, &p2.y, NULL); + x = lround((double)(p1.x + p2.x) / 2.); + y = lround((double)(p1.y + p2.y) / 2.); + if (e->map_data.zoom) + zw = e->map_data.zoom * w, zh = e->map_data.zoom * h; + else + zw = w, zh = h; + x = lround(x - (zw / 2.)); + y = lround(y - (zh / 2.)); + evas_object_move(obj, x, y); + evas_object_resize(obj, lround(zw), lround(zh)); + e->map_data.zoom = 0; + free(e->map_data.rotate_center); + e->map_data.rotate_center = NULL; + map = e_efx_map_new(obj); + e_efx_maps_apply(e, obj, map, E_EFX_MAPS_APPLY_ALL); + e_efx_map_set(obj, map); + INF("realize: %p - (%d,%d)@%dx%d -> (%d,%d)@%dx%d", obj, ox, oy, w, h, x, y, (int)zw, (int)zh); +} + +EAPI Eina_Bool +e_efx_follow(Evas_Object *obj, Evas_Object *follower) +{ + E_EFX *e, *ef; + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(follower, EINA_FALSE); + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + while (e->owner) e = e->owner; + + ef = evas_object_data_get(follower, "e_efx-data"); + if (ef) + { + if (ef->owner) + { + if (ef->owner == e) return EINA_TRUE; + ef->owner->followers = eina_list_remove(ef->owner->followers, ef); + } + } + else + ef = e_efx_new(follower); + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, EINA_FALSE); + if ((!ef->zoom_data) && (!ef->rotate_data) && (!ef->spin_data) && (!ef->move_data) && (!ef->bumpmap_data) && (!ef->pan_data) && (!ef->fade_data)) + evas_object_event_callback_priority_add(ef->obj, EVAS_CALLBACK_FREE, EVAS_CALLBACK_PRIORITY_BEFORE, (Evas_Object_Event_Cb)_obj_del, ef); + + ef->owner = e; + e->followers = eina_list_append(e->followers, ef); + INF("follow: (owner %p: %u) || (follower %p)", obj, eina_list_count(e->followers), follower); + return EINA_TRUE; + (void)e_efx_speed_str; +} + +EAPI void +e_efx_unfollow(Evas_Object *obj) +{ + E_EFX *e; + + EINA_SAFETY_ON_NULL_RETURN(obj); + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return; + if (!e->owner) return; + INF("unfollow: (owner %p) || (follower %p)", e->owner->obj, obj); + e->owner->followers = eina_list_remove(e->owner->followers, e); + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e); + e_efx_free(e->owner); + e->owner = NULL; + e_efx_free(e); +} + +EAPI Eina_List * +e_efx_followers_get(Evas_Object *obj) +{ + E_EFX *e, *f; + Eina_List *l, *ret = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return NULL; + EINA_LIST_FOREACH(e->followers, l, f) + ret = eina_list_append(ret, f->obj); + return ret; +} + +EAPI Evas_Object * +e_efx_leader_get(Evas_Object *obj) +{ + E_EFX *e; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return NULL; + return e->owner ? e->owner->obj : NULL; +} + +EAPI void +e_efx_reclip(Evas_Object *obj) +{ + E_EFX *e; + + EINA_SAFETY_ON_NULL_RETURN(obj); + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) return; + if (e->fade_data) e_efx_fade_reclip(e->fade_data); +} diff --git a/src/bin/efx/efx_zoom.c b/src/bin/efx/efx_zoom.c new file mode 100644 index 000000000..bb8ba4b33 --- /dev/null +++ b/src/bin/efx/efx_zoom.c @@ -0,0 +1,171 @@ +#include "e_efx_private.h" + +typedef struct E_Efx_Zoom_Data +{ + E_EFX *e; + Ecore_Animator *anim; + E_Efx_Effect_Speed speed; + double ending_zoom; + double starting_zoom; + E_Efx_End_Cb cb; + void *data; +} E_Efx_Zoom_Data; + +static void +_obj_del(E_Efx_Zoom_Data *ezd, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if (ezd->anim) ecore_animator_del(ezd->anim); + ezd->e->zoom_data = NULL; + if ((!ezd->e->owner) && (!ezd->e->followers)) e_efx_free(ezd->e); + free(ezd); +} + +static void +_zoom_center_calc(E_EFX *e, Evas_Object *obj, Evas_Coord *x, Evas_Coord *y) +{ + Evas_Coord w, h; + if (e->map_data.zoom_center) + { + *x = e->map_data.zoom_center->x; + *y = e->map_data.zoom_center->y; + } + else + { + evas_object_geometry_get(obj, x, y, &w, &h); + *x += (w / 2); + *y += (h / 2); + } +} + +static void +_zoom(E_EFX *e, Evas_Object *obj, double zoom) +{ + Evas_Map *map; + Evas_Coord x, y; + + map = e_efx_map_new(obj); + _zoom_center_calc(e, e->obj, &x, &y); + //DBG("ZOOM %p: %g: %d,%d", obj, zoom, x, y); + evas_map_util_zoom(map, zoom, zoom, x, y); + e_efx_maps_apply(e, obj, map, E_EFX_MAPS_APPLY_ROTATE_SPIN); + e_efx_map_set(obj, map); +} + +static Eina_Bool +_zoom_cb(E_Efx_Zoom_Data *ezd, double pos) +{ + double zoom; + Eina_List *l; + E_EFX *e; + + zoom = ecore_animator_pos_map(pos, ezd->speed, 0, 0); + ezd->e->map_data.zoom = (zoom * (ezd->ending_zoom - ezd->starting_zoom)) + ezd->starting_zoom; + //DBG("total: %g || zoom (pos %g): %g || endzoom: %g || startzoom: %g", ezd->e->map_data.zoom, zoom, pos, ezd->ending_zoom, ezd->starting_zoom); + e_efx_maps_apply(ezd->e, ezd->e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + EINA_LIST_FOREACH(ezd->e->followers, l, e) + e_efx_maps_apply(e, e->obj, NULL, E_EFX_MAPS_APPLY_ALL); + + if (pos < 1.0) return EINA_TRUE; + + ezd->anim = NULL; + E_EFX_QUEUE_CHECK(ezd); + return EINA_TRUE; +} + +static void +_zoom_stop(Evas_Object *obj, Eina_Bool reset) +{ + E_EFX *e; + E_Efx_Zoom_Data *ezd; + + e = evas_object_data_get(obj, "e_efx-data"); + if ((!e) || (!e->zoom_data)) return; + ezd = e->zoom_data; + if (reset) + { + ezd->starting_zoom = 0.0; + _zoom(e, obj, 1.0); + evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, ezd); + if (e_efx_queue_complete(ezd->e, ezd)) + e_efx_queue_process(ezd->e); + _obj_del(ezd, NULL, NULL, NULL); + INF("reset zooming object %p", obj); + } + else + { + ecore_animator_del(ezd->anim); + ezd->anim = NULL; + INF("stopped zooming object %p", obj); + if (e_efx_queue_complete(ezd->e, ezd)) + e_efx_queue_process(ezd->e); + } +} + +void +_e_efx_zoom_calc(void *data, void *owner, Evas_Object *obj, Evas_Map *map) +{ + E_Efx_Zoom_Data *ezd = data; + E_Efx_Zoom_Data *ezd2 = owner; + Evas_Coord x, y; + double zoom; + if ((ezd2 && (ezd2->e->map_data.zoom <= 0)) || (ezd && (ezd->e->map_data.zoom <= 0))) return; + _zoom_center_calc(ezd2 ? ezd2->e : ezd->e, ezd2 ? ezd2->e->obj : obj, &x, &y); + zoom = ezd ? ezd->e->map_data.zoom : 0; + if (ezd2) zoom += ezd2->e->map_data.zoom; + //DBG("zoom: %g @ (%d,%d)", zoom, x, y); + evas_map_util_zoom(map, zoom, zoom, x, y); +} + +EAPI Eina_Bool +e_efx_zoom(Evas_Object *obj, E_Efx_Effect_Speed speed, double starting_zoom, double ending_zoom, const Evas_Point *zoom_point, double total_time, E_Efx_End_Cb cb, const void *data) +{ + E_EFX *e; + E_Efx_Zoom_Data *ezd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); + if (ending_zoom <= 0.0) return EINA_FALSE; + if (starting_zoom < 0.0) return EINA_FALSE; + if (total_time < 0.0) return EINA_FALSE; + if (speed > E_EFX_EFFECT_SPEED_SINUSOIDAL) return EINA_FALSE; + + e = evas_object_data_get(obj, "e_efx-data"); + if (!e) e = e_efx_new(obj); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE); + if (!e_efx_zoom_center_init(e, zoom_point)) return EINA_FALSE; + INF("zoom: %p - %g%%->%g%% over %gs: %s", obj, (starting_zoom ?: e->map_data.zoom) * 100.0, ending_zoom * 100.0, total_time, e_efx_speed_str[speed]); + if (!e->zoom_data) + { + e->zoom_data = calloc(1, sizeof(E_Efx_Zoom_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e->zoom_data, EINA_FALSE); + evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->zoom_data); + } + ezd = e->zoom_data; + ezd->e = e; + ezd->speed = speed; + ezd->ending_zoom = ending_zoom; + ezd->starting_zoom = starting_zoom ?: ezd->e->map_data.zoom; + ezd->cb = cb; + ezd->data = (void*)data; + if (!total_time) + { + _zoom_cb(ezd, 1.0); + return EINA_TRUE; + } + if (!ezd->starting_zoom) ezd->starting_zoom = 1.0; + _zoom_cb(ezd, 0); + if (ezd->anim) ecore_animator_del(ezd->anim); + ezd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_zoom_cb, ezd); + return EINA_TRUE; +} + +EAPI void +e_efx_zoom_reset(Evas_Object *obj) +{ + _zoom_stop(obj, EINA_TRUE); +} + +EAPI void +e_efx_zoom_stop(Evas_Object *obj) +{ + _zoom_stop(obj, EINA_FALSE); +} diff --git a/src/modules/Makefile.mk b/src/modules/Makefile.mk index 3ea314881..f4d5f6a55 100644 --- a/src/modules/Makefile.mk +++ b/src/modules/Makefile.mk @@ -3,6 +3,7 @@ MOD_LDFLAGS = -module -avoid-version MOD_CPPFLAGS = -I. \ -I$(top_srcdir) \ -I$(top_srcdir)/src/bin \ +-I$(top_srcdir)/src/bin/efx \ -I$(top_builddir)/src/bin \ -I$(top_srcdir)/src/modules \ @e_cflags@ \