efl/legacy/evas/src/lib/canvas/evas_smart.c

427 lines
12 KiB
C

#include "evas_common.h"
#include "evas_private.h"
static void _evas_smart_class_callbacks_create(Evas_Smart *s);
/* all public */
/**
* @addtogroup Evas_Smart_Group
* @{
*/
/**
* Create an Evas_Smart, which can be used to instantiate new smart objects.
*
* This function internally creates an Evas_Smart_Class and sets the
* provided callbacks. Callbacks that are unneeded (or marked DEPRECATED
* below) should be set to NULL.
*
* Alternatively you can create an Evas_Smart_Class yourself and use
* evas_smart_class_new().
*
* @param name a unique name for the smart
* @param func_add callback called when smart object is added
* @param func_del callback called when smart object is deleted
* @param func_layer_set DEPRECATED
* @param func_raise DEPRECATED
* @param func_lower DEPRECATED
* @param func_stack_above DEPRECATED
* @param func_stack_below DEPRECATED
* @param func_move callback called when smart object is moved
* @param func_resize callback called when smart object is resized
* @param func_show callback called when smart object is shown
* @param func_hide callback called when smart object is hidden
* @param func_color_set callback called when smart object has its color set
* @param func_clip_set callback called when smart object has its clip set
* @param func_clip_unset callback called when smart object has its clip unset
* @param data a pointer to user data for the smart
* @return an Evas_Smart
*
*/
EAPI Evas_Smart *
evas_smart_new(const char *name,
void (*func_add) (Evas_Object *o),
void (*func_del) (Evas_Object *o),
void (*func_layer_set) (Evas_Object *o, int l) __UNUSED__,
void (*func_raise) (Evas_Object *o) __UNUSED__,
void (*func_lower) (Evas_Object *o) __UNUSED__,
void (*func_stack_above) (Evas_Object *o, Evas_Object *above) __UNUSED__,
void (*func_stack_below) (Evas_Object *o, Evas_Object *below) __UNUSED__,
void (*func_move) (Evas_Object *o, Evas_Coord x, Evas_Coord y),
void (*func_resize) (Evas_Object *o, Evas_Coord w, Evas_Coord h),
void (*func_show) (Evas_Object *o),
void (*func_hide) (Evas_Object *o),
void (*func_color_set) (Evas_Object *o, int r, int g, int b, int a),
void (*func_clip_set) (Evas_Object *o, Evas_Object *clip),
void (*func_clip_unset) (Evas_Object *o),
const void *data)
{
Evas_Smart *s;
Evas_Smart_Class *sc;
WRN("----- WARNING. evas_smart_new() will be deprecated and removed soon"
"----- Please use evas_smart_class_new() instead");
if (!name) return NULL;
s = evas_mem_calloc(sizeof(Evas_Smart));
if (!s) return NULL;
s->magic = MAGIC_SMART;
s->class_allocated = 1;
sc = evas_mem_calloc(sizeof(Evas_Smart_Class));
if (!sc)
{
free(s);
return NULL;
}
sc->name = name;
sc->add = func_add;
sc->del = func_del;
sc->move = func_move;
sc->resize = func_resize;
sc->show = func_show;
sc->hide = func_hide;
sc->color_set = func_color_set;
sc->clip_set = func_clip_set;
sc->clip_unset = func_clip_unset;
sc->data = (void *)data;
s->smart_class = sc;
return s;
}
/**
* Free an Evas_Smart
*
* If this smart was created using evas_smart_class_new(), the associated
* Evas_Smart_Class will not be freed.
*
* @param s the Evas_Smart to free
*
*/
EAPI void
evas_smart_free(Evas_Smart *s)
{
MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
return;
MAGIC_CHECK_END();
s->delete_me = 1;
if (s->usage > 0) return;
if (s->class_allocated) free((void *)s->smart_class);
free(s);
}
/**
* Creates an Evas_Smart from an Evas_Smart_Class.
*
* @param sc the smart class definition
* @return an Evas_Smart
*/
EAPI Evas_Smart *
evas_smart_class_new(const Evas_Smart_Class *sc)
{
Evas_Smart *s;
if (!sc) return NULL;
/* api does not match abi! for now refuse as we only have 1 version */
if (sc->version != EVAS_SMART_CLASS_VERSION) return NULL;
s = evas_mem_calloc(sizeof(Evas_Smart));
if (!s) return NULL;
s->magic = MAGIC_SMART;
s->smart_class = sc;
_evas_smart_class_callbacks_create(s);
return s;
}
/**
* Get the Evas_Smart_Class of an Evas_Smart
*
* @param s the Evas_Smart
* @return the Evas_Smart_Class
*/
EAPI const Evas_Smart_Class *
evas_smart_class_get(const Evas_Smart *s)
{
MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
return NULL;
MAGIC_CHECK_END();
return s->smart_class;
}
/**
* @brief Get the data pointer set on an Evas_Smart.
*
* @param s Evas_Smart
*
* This data pointer is set either as the final parameter to
* evas_smart_new or as the data field in the Evas_Smart_Class passed
* in to evas_smart_class_new
*/
EAPI void *
evas_smart_data_get(const Evas_Smart *s)
{
MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
return NULL;
MAGIC_CHECK_END();
return (void *)s->smart_class->data;
}
/**
* Get the callbacks known by this Evas_Smart.
*
* This is likely different from Evas_Smart_Class::callbacks as it
* will contain the callbacks of all class hierarchy sorted, while the
* direct smart class member refers only to that specific class and
* should not include parent's.
*
* If no callbacks are known, this function returns @c NULL.
*
* The array elements and thus their contents will be reference to
* original values given to evas_smart_new() as
* Evas_Smart_Class::callbacks.
*
* The array is sorted by name. The last array element is the @c NULL
* pointer and is not counted in @a count. Loop iterations can check
* any of these cases.
*
* @param s the Evas_Smart.
* @param count returns the number of elements in returned array.
* @return the array with callback descriptions known by this class,
* its size is returned in @a count parameter. It should not
* be modified anyhow. If no callbacks are known, @c NULL is
* returned. The array is sorted by name and elements refer to
* the original value given to evas_smart_new().
*
* @note objects may provide per-instance callbacks, use
* evas_object_smart_callbacks_descriptions_get() to get those
* as well.
* @see evas_object_smart_callbacks_descriptions_get()
*/
EAPI const Evas_Smart_Cb_Description **
evas_smart_callbacks_descriptions_get(const Evas_Smart *s, unsigned int *count)
{
MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
if (count) *count = 0;
return NULL;
MAGIC_CHECK_END();
if (count) *count = s->callbacks.size;
return s->callbacks.array;
}
/**
* Find callback description for callback called @a name.
*
* @param s the Evas_Smart.
* @param name name of desired callback, must @b not be @c NULL. The
* search have a special case for @a name being the same
* pointer as registered with Evas_Smart_Cb_Description, one
* can use it to avoid excessive use of strcmp().
* @return reference to description if found, @c NULL if not found.
*/
EAPI const Evas_Smart_Cb_Description *
evas_smart_callback_description_find(const Evas_Smart *s, const char *name)
{
if (!name) return NULL;
MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
return NULL;
MAGIC_CHECK_END();
return evas_smart_cb_description_find(&s->callbacks, name);
}
/**
* Sets one class to inherit from the other.
*
* Copy all function pointers, set @c parent to @a parent_sc and copy
* everything after sizeof(Evas_Smart_Class) present in @a parent_sc,
* using @a parent_sc_size as reference.
*
* This is recommended instead of a single memcpy() since it will take
* care to not modify @a sc name, version, callbacks and possible
* other members.
*
* @param sc child class.
* @param parent_sc parent class, will provide attributes.
* @param parent_sc_size size of parent_sc structure, child should be at least
* this size. Everything after @c Evas_Smart_Class size is copied
* using regular memcpy().
*/
EAPI Eina_Bool
evas_smart_class_inherit_full(Evas_Smart_Class *sc, const Evas_Smart_Class *parent_sc, unsigned int parent_sc_size)
{
unsigned int off;
/* api does not match abi! for now refuse as we only have 1 version */
if (parent_sc->version != EVAS_SMART_CLASS_VERSION) return 0;
#define _CP(m) sc->m = parent_sc->m
_CP(add);
_CP(del);
_CP(move);
_CP(resize);
_CP(show);
_CP(hide);
_CP(color_set);
_CP(clip_set);
_CP(clip_unset);
_CP(calculate);
_CP(member_add);
_CP(member_del);
#undef _CP
sc->parent = parent_sc;
off = sizeof(Evas_Smart_Class);
if (parent_sc_size == off) return 1;
memcpy(((char *)sc) + off, ((char *)parent_sc) + off, parent_sc_size - off);
return 1;
}
/**
* @}
*/
/* internal funcs */
void
evas_object_smart_use(Evas_Smart *s)
{
s->usage++;
}
void
evas_object_smart_unuse(Evas_Smart *s)
{
s->usage--;
if ((s->usage <= 0) && (s->delete_me)) evas_smart_free(s);
}
Eina_Bool
evas_smart_cb_descriptions_resize(Evas_Smart_Cb_Description_Array *a, unsigned int size)
{
void *tmp;
if (size == a->size)
return 1;
if (size == 0)
{
free(a->array);
a->array = NULL;
a->size = 0;
return 1;
}
tmp = realloc(a->array, (size + 1) * sizeof(Evas_Smart_Cb_Description *));
if (tmp)
{
a->array = tmp;
a->size = size;
a->array[size] = NULL;
return 1;
}
else
{
fprintf(stderr, "ERROR: realloc failed!\n");
return 0;
}
}
static int
_evas_smart_cb_description_cmp_sort(const void *p1, const void *p2)
{
const Evas_Smart_Cb_Description * const*a = p1, * const*b = p2;
return strcmp((*a)->name, (*b)->name);
}
void
evas_smart_cb_descriptions_fix(Evas_Smart_Cb_Description_Array *a)
{
unsigned int i, j;
qsort(a->array, a->size, sizeof(Evas_Smart_Cb_Description *),
_evas_smart_cb_description_cmp_sort);
fprintf(stderr, "\nDEBUG: %u callbacks\n", a->size);
if (a->size)
fprintf(stderr, "DEBUG: %20.20s [%s]\n", a->array[0]->name, a->array[1]->type);
for (i = 0, j = 1; j < a->size; j++)
{
const Evas_Smart_Cb_Description *cur, *prev;
cur = a->array[j];
prev = a->array[i];
fprintf(stderr, "DEBUG: %20.20s [%s]\n", cur->name, cur->type);
if (strcmp(cur->name, prev->name) != 0)
{
i++;
if (i != j)
a->array[i] = a->array[j];
}
else
{
if (strcmp(cur->type, prev->type) == 0)
fprintf(stderr, "WARNING: duplicated smart callback description name '%s', type '%s'\n", cur->name, cur->type);
else
fprintf(stderr, "ERROR: callback description named '%s' differ, keep '%s', ignore '%s'\n", cur->name, prev->type, cur->type);
}
}
evas_smart_cb_descriptions_resize(a, a->size - (j - i));
}
static void
_evas_smart_class_callbacks_create(Evas_Smart *s)
{
const Evas_Smart_Class *sc;
unsigned int n = 0;
for (sc = s->smart_class; sc != NULL; sc = sc->parent)
{
const Evas_Smart_Cb_Description *d;
for (d = sc->callbacks; d && d->name != NULL; d++)
n++;
}
if (n == 0) return;
if (!evas_smart_cb_descriptions_resize(&s->callbacks, n)) return;
for (n = 0, sc = s->smart_class; sc != NULL; sc = sc->parent)
{
const Evas_Smart_Cb_Description *d;
for (d = sc->callbacks; d->name != NULL; d++)
s->callbacks.array[n++] = d;
}
evas_smart_cb_descriptions_fix(&s->callbacks);
}
static int
_evas_smart_cb_description_cmp_search(const void *p1, const void *p2)
{
const char *name = p1;
const Evas_Smart_Cb_Description * const*v = p2;
/* speed up string shares searches (same pointers) */
if (name == (*v)->name) return 0;
return strcmp(name, (*v)->name);
}
const Evas_Smart_Cb_Description *
evas_smart_cb_description_find(const Evas_Smart_Cb_Description_Array *a, const char *name)
{
if (!a->array) return NULL;
return bsearch(name, a->array, a->size, sizeof(Evas_Smart_Cb_Description *),
_evas_smart_cb_description_cmp_search);
}