enlightenment/src/bin/efx/efx_fade.c

190 lines
5.9 KiB
C

#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, (Ecore_Pos_Map)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);
efd->anim = NULL;
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;
int r, g, b, a;
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, &r, &g, &b, &a);
efd->start.r = r;
efd->start.g = g;
efd->start.b = b;
efd->alpha[0] = a;
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 (!eina_dbl_exact(total_time, 0))
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);
}