enlightenment/src/bin/efx/efx_resize.c

247 lines
6.7 KiB
C

#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;
if (erd->e->move_data)
cx = erd->e->x, cy = erd->e->y;
else
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, (Ecore_Pos_Map)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;
//DBG("%p to (%dx%d)", erd->e->obj, w, h);
erd->e->w = w, erd->e->h = 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 */
erd->e->w = erd->w, erd->e->h = erd->h;
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)
{
erd->e->w = erd->start_w, erd->e->h = erd->start_h;
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);
erd->anim = NULL;
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) || (!erd->anim)) return;
if (e->move_data)
x = e->x, y = e->y;
else
evas_object_geometry_get(e->obj, &x, &y, NULL, NULL);
w = e->w, h = e->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);
e->w = erd->start_w;
e->h = erd->start_h;
if (e->move_data)
x = e->x, y = e->y;
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)
{
if ((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;
}
else
evas_object_move(obj, position->x, position->y);
}
if (!eina_dbl_exact(total_time, 0))
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);
}