In this example, we illustrate how to create and handle Evas smart objects.
A smart object is one that provides custom functions to handle clipping, hiding, moving, resizing, color setting and more on child elements, automatically, for the smart object's user. They could be as simple as a group of objects that move together (see Clipped Smart Object) or implementations of whole complex UI widgets, providing some intelligence (thus the name) and extension to simple Evas objects.
Here, we create one as an example. What it does is to control (at maximum) 2 child objects, with regard to their geometries and colors. There can be a "left" child and a "right" one. The former will always occupy the top left quadrant of the smart object's area, while the latter will occupy the bottom right. The smart object will also contain an internal decorative border object, which will also be controlled by it, naturally.
will define the new smart class' name. The second tells the macro what is the prefix of the function it will be declaring with a _smart_set_user()
suffix. On this function, we may override/extend any desired method from our parent smart class:
This code will take place whenever the smart object itself is flagged "dirty", i.e., must be recalculated for rendering (that could come from changes on its clipper, resizing, moving, etc). There, we make sure the decorative border lies on the edges of the smart object and the children, if any, lie on their respective quadrants.
After instantiating our smart object, we do some checks to exemplify some of the API on smart objects:
Here we declare our array of smart callback descriptions, which has one element only, in this case. That callback will take place, as the name indicates, whenever the number of member objects in our smart object example instance changes. That global array variable must be the last argument to EVAS_SMART_SUBCLASS_NEW, so that it's registered as the smart class's callbacks description.
After we instantiate the smart object, we take a look on those descriptions and register a callback on that unique smart event:
The code of the callback will just print how many member objects we have, which is an integer argument of the callback itself, as flagged by its description:
As in other examples, to interact with this one there's a command line interface. A help string can be asked for with the 'h' key:
"Real life" examples of smart objects are Edje and Emotion objects: they both have independent libraries implementing their behavior. The full example follows.
#ifdef HAVE_CONFIG_H
#include "config.h"
#else
#define PACKAGE_EXAMPLES_DIR "."
#endif
#include <Ecore.h>
#include <stdio.h>
#include <errno.h>
#include "evas-common.h"
#define WIDTH (320)
#define HEIGHT (240)
static const char *commands = \
"commands are:\n"
"\tl - insert child rectangle on the left\n"
"\tr - insert child rectangle on the right\n"
"\tw - remove and delete all members from the smart object\n"
"\tright arrow - move smart object to the right\n"
"\tleft arrow - move smart object to the left\n"
"\tup arrow - move smart object up\n"
"\tdown arrow - move smart object down\n"
"\td - decrease smart object's size\n"
"\ti - increase smart object's size\n"
"\tc - change smart object's clipper color\n"
"\t. - rotate object to the right\n"
"\t, - rotate object to the left\n"
"\th - print help\n"
"\tq - quit\n"
;
#define WHITE {255, 255, 255, 255}
#define RED {255, 0, 0, 255}
#define GREEN {0, 255, 0, 255}
#define BLUE {0, 0, 255, 255}
struct test_data
{
Ecore_Evas *ee;
};
struct color_tuple
{
int r, g, b, a;
} clipper_colors[4] = {WHITE, RED, GREEN, BLUE};
int cur_color = 0;
int cur_angle = 0;
static const char *
_index_to_color(int i)
{
switch (i)
{
case 0:
return "WHITE (default)";
case 1:
return "RED";
case 2:
return "GREEN";
case 3:
return "BLUE";
default:
return "other";
}
}
static struct test_data d = {0};
static const char *border_img_path = PACKAGE_EXAMPLES_DIR EVAS_IMAGE_FOLDER "/red.png";
#define _evas_smart_example_type "Evas_Smart_Example"
#define EVT_CHILDREN_NUMBER_CHANGED "children,changed"
{
{EVT_CHILDREN_NUMBER_CHANGED, "i"},
{NULL, NULL}
};
typedef struct _Evas_Smart_Example_Data Evas_Smart_Example_Data;
struct _Evas_Smart_Example_Data
{
int child_count;
};
#define EVAS_SMART_EXAMPLE_DATA_GET(o, ptr) \
Evas_Smart_Example_Data * ptr = evas_object_smart_data_get(o)
#define EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN(o, ptr) \
EVAS_SMART_EXAMPLE_DATA_GET(o, ptr); \
if (!ptr) \
{ \
fprintf(stderr, "No widget data for object %p (%s)!", \
o, evas_object_type_get(o)); \
fflush(stderr); \
abort(); \
return; \
}
#define EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
EVAS_SMART_EXAMPLE_DATA_GET(o, ptr); \
if (!ptr) \
{ \
fprintf(stderr, "No widget data for object %p (%s)!", \
o, evas_object_type_get(o)); \
fflush(stderr); \
abort(); \
return val; \
}
static void
{
}
static void
_canvas_resize_cb(Ecore_Evas *ee)
{
int w, h;
}
static void
_on_child_del(void *data,
{
long idx;
EVAS_SMART_EXAMPLE_DATA_GET(example_smart, priv);
idx--;
priv->children[idx] = NULL;
}
static void
_evas_smart_example_child_callbacks_unregister(
Evas_Object *obj)
{
}
static void
_evas_smart_example_child_callbacks_register(
Evas_Object *o,
long idx)
{
}
static void
{
_evas_smart_example_parent_sc->add(o);
}
static void
{
EVAS_SMART_EXAMPLE_DATA_GET(o, priv);
if (priv->children[0])
{
_evas_smart_example_child_callbacks_unregister(priv->children[0]);
priv->children[0] = NULL;
}
if (priv->children[1])
{
_evas_smart_example_child_callbacks_unregister(priv->children[1]);
priv->children[1] = NULL;
}
_evas_smart_example_parent_sc->del(o);
}
static void
{
if ((ow == w) && (oh == h)) return;
}
static void
{
EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN(o, priv);
if (priv->children[0])
{
}
if (priv->children[1])
{
}
}
static void
{
sc->
add = _evas_smart_example_smart_add;
sc->
del = _evas_smart_example_smart_del;
sc->
resize = _evas_smart_example_smart_resize;
sc->
calculate = _evas_smart_example_smart_calculate;
}
evas_smart_example_add(
Evas *evas)
{
}
static void
_evas_smart_example_remove_do(Evas_Smart_Example_Data *priv,
int idx)
{
priv->children[idx] = NULL;
priv->child_count--;
_evas_smart_example_child_callbacks_unregister(child);
}
{
long idx;
EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
if (priv->children[0] != child && priv->children[1] != child)
{
fprintf(stderr, "You are trying to remove something not belonging to"
" the example smart object!\n");
return NULL;
}
idx--;
_evas_smart_example_remove_do(priv, child, idx);
o, EVT_CHILDREN_NUMBER_CHANGED, (void *)(uintptr_t)priv->child_count);
return child;
}
{
EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
if (!child)
return NULL;
if (priv->children[1] == child)
{
fprintf(stderr, "You mustn't place a child on both slots of"
" the example smart object!\n");
return NULL;
}
if (priv->children[0])
{
if (priv->children[0] != child)
{
ret = priv->children[0];
_evas_smart_example_remove_do(priv, priv->children[0], 0);
}
else return child;
}
priv->children[0] = child;
_evas_smart_example_child_callbacks_register(o, child, 0);
priv->child_count++;
if (!ret)
{
o, EVT_CHILDREN_NUMBER_CHANGED, (void *)(uintptr_t)priv->child_count);
}
return ret;
}
{
EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
if (!child)
return NULL;
if (priv->children[0] == child)
{
fprintf(stderr, "You mustn't place a child on both slots of"
" the example smart object!\n");
return NULL;
}
if (priv->children[1])
{
if (priv->children[1] != child)
{
ret = priv->children[1];
_evas_smart_example_remove_do(priv, priv->children[1], 1);
}
else return child;
}
priv->children[1] = child;
_evas_smart_example_child_callbacks_register(o, child, 1);
priv->child_count++;
if (!ret)
{
o, EVT_CHILDREN_NUMBER_CHANGED, (void *)(uintptr_t)priv->child_count);
}
return ret;
}
static void
_map_update(void)
{
Evas_Map *m;
}
static void
void *einfo)
{
if (strcmp(ev->
key,
"q") == 0)
{
_on_destroy(NULL);
return;
}
if (strcmp(ev->
key,
"h") == 0)
{
puts(commands);
return;
}
if (strcmp(ev->
key,
"w") == 0)
{
if (d.rects[0])
{
evas_smart_example_remove(d.smt, d.rects[0]);
}
if (d.rects[1])
{
evas_smart_example_remove(d.smt, d.rects[1]);
}
memset(d.rects, 0, sizeof(d.rects));
printf("Deleting all members of the smart object.\n");
return;
}
if (strcmp(ev->
key,
"l") == 0)
{
rect, rand() % 255, rand() % 255, rand() % 255, 255);
prev = evas_smart_example_set_left(d.smt, rect);
d.rects[0] = rect;
printf("Setting smart object's left spot with a new rectangle.\n");
printf("Checking its new smart object parent: %s\n",
"Failure!");
if (prev)
{
int r, g, b;
printf("Deleting previous left child,"
" which had colors (%d, %d, %d)\n", r, g, b);
}
return;
}
if (strcmp(ev->
key,
"r") == 0)
{
rect, rand() % 255, rand() % 255, rand() % 255, 255);
prev = evas_smart_example_set_right(d.smt, rect);
d.rects[1] = rect;
printf("Setting smart object's right spot with a new rectangle.\n");
printf("Checking its new smart object parent: %s\n",
"Failure!");
if (prev)
{
int r, g, b;
printf("Deleting previous right child,"
" which had colors (%d, %d, %d)\n", r, g, b);
}
return;
}
if (strcmp(ev->
key,
"Right") == 0 || strcmp(ev->
key,
"Left") == 0 ||
strcmp(ev->
key,
"Up") == 0 || strcmp(ev->
key,
"Down") == 0)
{
{
case 'R':
x += 20;
break;
case 'L':
x -= 20;
break;
case 'U':
y -= 20;
break;
case 'D':
y += 20;
break;
}
_map_update();
return;
}
if (strcmp(ev->
key,
"i") == 0)
{
w *= 1.1;
h *= 1.1;
_map_update();
return;
}
if (strcmp(ev->
key,
"d") == 0)
{
w *= 0.9;
h *= 0.9;
_map_update();
return;
}
if (strcmp(ev->
key,
"c") == 0)
{
cur_color = (cur_color + 1) % 4;
d.clipper, clipper_colors[cur_color].r, clipper_colors[cur_color].g,
clipper_colors[cur_color].b, clipper_colors[cur_color].a);
fprintf(stderr, "Changing clipper's color to %s\n",
_index_to_color(cur_color));
return;
}
if (strcmp(ev->
key,
"period") == 0)
{
cur_angle = (cur_angle + 30) % 360;
_map_update();
return;
}
if (strcmp(ev->
key,
"comma") == 0)
{
cur_angle = (cur_angle - 30) % 360;
_map_update();
return;
}
fprintf(stderr,
"Invalid key: '%s'\n", ev->
key);
}
static void
_on_example_smart_object_child_num_change(
void *data
EINA_UNUSED,
void *event_info)
{
printf("Number of child members on our example smart"
" object changed to %llu\n", (unsigned long long)(uintptr_t)event_info);
}
int
main(void)
{
unsigned int count;
return EXIT_FAILURE;
if (!d.ee)
goto error;
d.smt = evas_smart_example_add(d.evas);
printf("Adding smart object of type \"%s\" to the canvas: %s.\n",
_evas_smart_example_type, ret ? "success" : "failure");
printf("Checking if clipped smart object's clipper is a "
"\"static\" one: %s\n",
d.clipper, clipper_colors[cur_color].r, clipper_colors[cur_color].g,
clipper_colors[cur_color].b, clipper_colors[cur_color].a);
d.smt, &descriptions, &count, NULL, NULL);
for (; *descriptions; descriptions++)
{
printf("We've found a smart callback on the smart object!"
"\n\tname: %s\n\ttype: %s\n", (*descriptions)->name,
(*descriptions)->type);
if (strcmp((*descriptions)->type, "i")) continue;
d.smt, (*descriptions)->name,
_on_example_smart_object_child_num_change, NULL);
}
puts(commands);
return 0;
error:
fprintf(stderr, "error: Requires at least one Evas engine built and linked"
" to ecore-evas for this example to run properly.\n");
return -1;
}
@ EVAS_CALLBACK_KEY_DOWN
Key Press Event.
Definition: Evas_Common.h:430
@ EVAS_CALLBACK_FREE
Object Being Freed (Called after Del)
Definition: Evas_Common.h:429
EAPI int ecore_evas_init(void)
Inits the Ecore_Evas system.
Definition: ecore_evas.c:602
EAPI void ecore_evas_callback_destroy_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
Sets a callback for Ecore_Evas destroy events.
Definition: ecore_evas.c:1185
EAPI void ecore_evas_show(Ecore_Evas *ee)
Shows an Ecore_Evas' window.
Definition: ecore_evas.c:1480
EAPI Evas * ecore_evas_get(const Ecore_Evas *ee)
Gets an Ecore_Evas's Evas.
Definition: ecore_evas.c:1300
EAPI void ecore_evas_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h)
Gets the geometry of an Ecore_Evas.
Definition: ecore_evas.c:1362
EAPI Ecore_Evas * ecore_evas_new(const char *engine_name, int x, int y, int w, int h, const char *extra_options)
Creates a new Ecore_Evas based on engine name and common parameters.
Definition: ecore_evas.c:1039
EAPI void ecore_evas_callback_resize_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
Sets a callback for Ecore_Evas resize events.
Definition: ecore_evas.c:1140
EAPI int ecore_evas_shutdown(void)
Shuts down the Ecore_Evas system.
Definition: ecore_evas.c:666
EAPI void ecore_evas_free(Ecore_Evas *ee)
Frees an Ecore_Evas.
Definition: ecore_evas.c:1083
void ecore_main_loop_quit(void)
Quits the main loop once all the events currently on the queue have been processed.
Definition: ecore_main.c:1321
void ecore_main_loop_begin(void)
Runs the application main loop.
Definition: ecore_main.c:1311
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
EVAS_API void evas_object_del(Evas_Object *obj)
Marks the given Evas object for deletion (when Evas will free its memory).
Definition: evas_object_main.c:928
EVAS_API void evas_object_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
Retrieves the general/main color of the given Evas object.
Definition: evas_object_main.c:2071
EVAS_API void * evas_object_event_callback_del(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func)
Delete a callback function from an object.
Definition: evas_callbacks.c:513
EVAS_API void evas_object_event_callback_add(Evas_Object *eo_obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data)
Add (register) a callback function to a given Evas object event.
Definition: evas_callbacks.c:478
EVAS_API void evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy)
Change the map to apply the given rotation.
Definition: evas_map.c:968
EVAS_API void evas_map_free(Evas_Map *m)
Free a previously allocated map.
Definition: evas_map.c:745
EVAS_API void evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *eo_obj)
Populate source and destination map points to match exactly object.
Definition: evas_map.c:885
EVAS_API Evas_Map * evas_map_new(int count)
Create map of transformation points to be later used with an Evas object.
Definition: evas_map.c:658
EVAS_API Efl_Canvas_Object * evas_object_smart_parent_get(const Efl_Canvas_Object *obj)
Gets the parent smart object of a given Evas object, if it has one.
Definition: efl_canvas_object_eo.legacy.c:100
EVAS_API void evas_object_map_set(Evas_Object *eo_obj, const Evas_Map *map)
Set current object transformation map.
Definition: evas_map.c:532
EVAS_API void evas_object_map_enable_set(Eo *eo_obj, Eina_Bool enabled)
Enable or disable the map that is set.
Definition: evas_map.c:516
EVAS_API Evas_Object * evas_object_rectangle_add(Evas *e)
Adds a rectangle to the given evas.
Definition: evas_object_rectangle.c:78
EVAS_API void evas_object_smart_callbacks_descriptions_get(const Eo *eo_obj, const Evas_Smart_Cb_Description ***class_descriptions, unsigned int *class_count, const Evas_Smart_Cb_Description ***instance_descriptions, unsigned int *instance_count)
Retrieve an smart object's know smart callback descriptions (both instance and class ones).
Definition: evas_object_smart.c:1217
EVAS_API void evas_object_smart_member_del(Evas_Object *eo_obj)
Removes a member object from a given smart object.
Definition: evas_object_smart.c:344
Key press event.
Definition: Evas_Legacy.h:314
const char * key
The logical key : (eg shift+1 == exclamation)
Definition: Evas_Legacy.h:320