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;
Evas *evas;
Evas_Object *smt, *bg, *clipper, *rects[2];
};
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
{
Evas_Object *children[2], *border;
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,
Evas_Object *o,
{
Evas_Object *example_smart = data;
long idx;
EVAS_SMART_EXAMPLE_DATA_GET(example_smart, priv);
idx = (long)(uintptr_t)evas_object_data_get(o, "index");
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,
Evas_Object *child,
long idx)
{
}
static void
_evas_smart_example_smart_add(Evas_Object *o)
{
_evas_smart_example_parent_sc->add(o);
}
static void
_evas_smart_example_smart_del(Evas_Object *o)
{
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
_evas_smart_example_smart_resize(Evas_Object *o,
{
if ((ow == w) && (oh == h)) return;
}
static void
_evas_smart_example_smart_calculate(Evas_Object *o)
{
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_Object *
evas_smart_example_add(Evas *evas)
{
}
static void
_evas_smart_example_remove_do(Evas_Smart_Example_Data *priv,
Evas_Object *child,
int idx)
{
priv->children[idx] = NULL;
priv->child_count--;
_evas_smart_example_child_callbacks_unregister(child);
}
Evas_Object *
evas_smart_example_remove(Evas_Object *o,
Evas_Object *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 = (long)(uintptr_t)evas_object_data_get(child, "index");
idx--;
_evas_smart_example_remove_do(priv, child, idx);
o, EVT_CHILDREN_NUMBER_CHANGED, (void *)(uintptr_t)priv->child_count);
return child;
}
Evas_Object *
evas_smart_example_set_left(Evas_Object *o,
Evas_Object *child)
{
Evas_Object *ret = NULL;
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_Object *
evas_smart_example_set_right(Evas_Object *o,
Evas_Object *child)
{
Evas_Object *ret = NULL;
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:608
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:1199
EAPI void ecore_evas_show(Ecore_Evas *ee)
Shows an Ecore_Evas' window.
Definition ecore_evas.c:1494
EAPI Evas * ecore_evas_get(const Ecore_Evas *ee)
Gets an Ecore_Evas's Evas.
Definition ecore_evas.c:1314
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:1376
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:1053
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:1154
EAPI int ecore_evas_shutdown(void)
Shuts down the Ecore_Evas system.
Definition ecore_evas.c:672
EAPI void ecore_evas_free(Ecore_Evas *ee)
Frees an Ecore_Evas.
Definition ecore_evas.c:1097
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_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