Evas object smart objects

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.

Here is where we add it to the canvas:

d.smt = evas_smart_example_add(d.evas);
evas_object_move(d.smt, WIDTH / 4, HEIGHT / 4);
evas_object_resize(d.smt, WIDTH / 2, HEIGHT / 2);
evas_object_show(d.smt);
evas_object_show
EVAS_API void evas_object_show(Evas_Object *eo_obj)
Makes the given Evas object visible.
Definition evas_object_main.c:1814
evas_object_move
EVAS_API void evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
Move the given Evas object to the given location inside its canvas' viewport.
Definition evas_object_main.c:1171
evas_object_resize
EVAS_API void evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
Changes the size of the given Evas object.
Definition evas_object_main.c:1236

The magic starts to happen in the `evas_smart_example_add()` function, which is one in the example smart object's defined interface. These should be the functions you would export to the users of your smart object. We made three for this one:

- `evas_smart_example_add()`: add a new instance of the example smart object to a canvas
- `evas_smart_example_remove()`: remove a given child of the smart object from it
- `evas_smart_example_set_left()`: set the left child of the smart object
- `evas_smart_example_set_right()`: set the right child of the smart object

The object's creation takes place as:

/* add a new example smart object to a canvas */
Evas_Object *
evas_smart_example_add(Evas *evas)
{
return evas_object_smart_add(evas, _evas_smart_example_smart_class_new());
}
Evas
Eo Evas
An opaque handle to an Evas canvas.
Definition Evas_Common.h:163
Evas_Object
Efl_Canvas_Object Evas_Object
An Evas Object handle.
Definition Evas_Common.h:185
evas_object_smart_add
EVAS_API Evas_Object * evas_object_smart_add(Evas *eo_e, Evas_Smart *s)
Instantiates a new smart object described by s.
Definition evas_object_smart.c:702

Smart objects are defined by smart classes, which are structs defining their interfaces, or smart functions (see Evas_Smart_Class, the base class for any smart object). As you see, one has to use the evas_object_smart_add() function to instantiate smart objects. Its second parameter is what matters – an Evas_Smart struct, which contains all the smart class definitions (smart functions, smart callbacks, and the like). Note, however, that `_evas_smart_example_smart_class_new()` seems not to be defined in our example's code. That's because it came from a very handy helper macro:

EVAS_SMART_SUBCLASS_NEW(_evas_smart_example_type, _evas_smart_example,
Evas_Smart_Class, Evas_Smart_Class,
evas_object_smart_clipped_class_get, _smart_callbacks);
EVAS_SMART_SUBCLASS_NEW
#define EVAS_SMART_SUBCLASS_NEW(smart_name, prefix, api_type, parent_type, parent_func, cb_desc)
Convenience macro to subclass a given Evas smart class.
Definition Evas_Common.h:2175
Evas_Smart_Class
struct _Evas_Smart_Class Evas_Smart_Class
A smart object's base class definition.
Definition Evas_Common.h:126
evas_object_smart_clipped_class_get
EVAS_API const Evas_Smart_Class * evas_object_smart_clipped_class_get(void)
Get a pointer to the clipped smart object's class, to use for proper inheritance.
Definition evas_object_smart_clipped.c:121

What it does is to subclass a given existing smart class, thus specializing it. This is very common and useful in Evas. There is a built-in smart object, the "clipped smart object", which implements a behavior mostly desired by many other smart object implementors: it will clip its children to its area and move them along with it, on evas_object_move() calls. Then, our example smart object will get that behavior for free.

The first argument to the macro,

#define _evas_smart_example_type "Evas_Smart_Example"

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:

/* setting our smart interface */
static void
_evas_smart_example_smart_set_user(Evas_Smart_Class *sc)
{
/* specializing these two */
sc->add = _evas_smart_example_smart_add;
sc->del = _evas_smart_example_smart_del;
/* clipped smart object has no hook on resizes or calculations */
sc->resize = _evas_smart_example_smart_resize;
sc->calculate = _evas_smart_example_smart_calculate;
}
_Evas_Smart_Class::add
void(* add)(Evas_Object *o)
code to be run when adding object to a canvas
Definition Evas_Common.h:1951
_Evas_Smart_Class::del
void(* del)(Evas_Object *o)
code to be run when removing object from a canvas
Definition Evas_Common.h:1952
_Evas_Smart_Class::calculate
void(* calculate)(Evas_Object *o)
code to be run when object has rendering updates on a canvas
Definition Evas_Common.h:1960
_Evas_Smart_Class::resize
void(* resize)(Evas_Object *o, Evas_Coord w, Evas_Coord h)
code to be run when resizing object on a canvas.
Definition Evas_Common.h:1954

The first function pointer's code will take place at an example smart object's creation time:

/* create and setup a new example smart object's internals */
static void
_evas_smart_example_smart_add(Evas_Object *o)
{
EVAS_SMART_DATA_ALLOC(o, Evas_Smart_Example_Data);
/* call parent_sc->add() before member_adding the children, otherwise the
* smart object's clipper won't be created yet, and the children won't be
* clipped to it */
_evas_smart_example_parent_sc->add(o);
/* this is a border around the smart object's area, delimiting it */
priv->border = evas_object_image_filled_add(evas_object_evas_get(o));
evas_object_image_file_set(priv->border, border_img_path, NULL);
evas_object_image_border_set(priv->border, 3, 3, 3, 3);
evas_object_image_border_center_fill_set(
priv->border, EVAS_BORDER_FILL_NONE);
evas_object_show(priv->border);
evas_object_smart_member_add(priv->border, o);
}
evas_object_evas_get
EVAS_API Evas * evas_object_evas_get(const Eo *eo_obj)
Get the Evas to which this object belongs to.
Definition evas_object_main.c:2662
evas_object_image_border_set
EVAS_API void evas_object_image_border_set(Evas_Object *obj, int l, int r, int t, int b)
Dimensions of this image's border, a region that does not scale with the center area.
Definition evas_image_legacy.c:117
evas_object_image_border_center_fill_set
EVAS_API void evas_object_image_border_center_fill_set(Evas_Object *obj, Evas_Border_Fill_Mode fill)
Specifies how the center part of the object (not the borders) should be drawn when EFL is rendering i...
Definition evas_image_legacy.c:145
evas_object_image_file_set
EVAS_API void evas_object_image_file_set(Evas_Object *obj, const char *file, const char *key)
Set the source file from where an image object must fetch the real image data (it may be an Eet file,...
Definition evas_image_legacy.c:194
evas_object_image_filled_add
EVAS_API Evas_Object * evas_object_image_filled_add(Evas *eo_e)
Creates a new image object that automatically scales its bound image to the object's area,...
Definition evas_image_legacy.c:35
EVAS_BORDER_FILL_NONE
@ EVAS_BORDER_FILL_NONE
Image's center region is not to be rendered.
Definition Evas_Legacy.h:5721
EVAS_SMART_DATA_ALLOC
#define EVAS_SMART_DATA_ALLOC(o, priv_type)
Convenience macro to allocate smart data only if needed.
Definition Evas_Common.h:2314
evas_object_smart_member_add
EVAS_API void evas_object_smart_member_add(Evas_Object *eo_obj, Evas_Object *smart_obj)
Set an Evas object as a member of a given smart object.
Definition evas_object_smart.c:210

The EVAS_SMART_DATA_ALLOC macro will take care of allocating our smart object data, which will be available on other contexts for us (mainly in our interface functions):

typedef struct _Evas_Smart_Example_Data Evas_Smart_Example_Data;
/*
* This structure augments clipped smart object's instance data,
* providing extra members required by our example smart object's
* implementation.
*/
struct _Evas_Smart_Example_Data
{
Evas_Object_Smart_Clipped_Data base;
Evas_Object *children[2], *border;
int child_count;
};
Evas_Object_Smart_Clipped_Data
struct _Evas_Object_Smart_Clipped_Data Evas_Object_Smart_Clipped_Data
Every subclass should provide this at the beginning of their own data set with evas_object_smart_data...
Definition Evas_Common.h:2578

See that, as we're inheriting from the clipped smart object's class, we must have their data struct as our first member. Other data of interest for us is a child members array and the border object's handle. The latter is what is created in the last mentioned function. Note how to tell Evas the border will be managed by our smart object from that time on: `evas_object_smart_member_add(priv->border, o);`. The counterpart of this function is exemplified on the smart object's interface function to remove children:

/* remove a child element, return its pointer (or NULL on errors) */
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);
evas_object_smart_callback_call(
o, EVT_CHILDREN_NUMBER_CHANGED, (void *)(uintptr_t)priv->child_count);
evas_object_smart_changed(o);
return child;
}
/* set to return any previous object set to the left position of the
evas_object_smart_changed
EVAS_API void evas_object_smart_changed(Efl_Canvas_Group *obj)
Marks the object as dirty.
Definition efl_canvas_group_eo.legacy.c:15
evas_object_smart_callback_call
EVAS_API void evas_object_smart_callback_call(Evas_Object *eo_obj, const char *event, void *event_info)
Call a given smart callback on the smart object obj.
Definition evas_object_smart.c:1151

At the end of that function we make use of an constant defined by the EVAS_SMART_SUBCLASS_NEW: `_evas_smart_example_parent_sc`. It has the same prefix we passed to the macro, as you can see, and it holds a pointer to our parent smart class. Then, we can call the specialized method, itself, after our code. The `del`, `hide`, `show` and `resize` specializations are straightforward, we let the reader take a look at them below to check their behavior. What's interesting is the `calculate` one:

/* act on child objects' properties, before rendering */
static void
_evas_smart_example_smart_calculate(Evas_Object *o)
{
Evas_Coord x, y, w, h;
EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN(o, priv);
evas_object_geometry_get(o, &x, &y, &w, &h);
evas_object_resize(priv->border, w, h);
evas_object_move(priv->border, x, y);
if (priv->children[0])
{
evas_object_move(priv->children[0], x + 3, y + 3);
evas_object_resize(priv->children[0], (w / 2) - 3, (h / 2) - 3);
}
if (priv->children[1])
{
evas_object_move(priv->children[1], x + (w / 2), y + (h / 2));
evas_object_resize(priv->children[1], (w / 2) - 3, (h / 2) - 3);
}
}
/* setting our smart interface */
Evas_Coord
int Evas_Coord
Type used for coordinates (in pixels, int).
Definition Evas_Common.h:116
evas_object_geometry_get
EVAS_API void evas_object_geometry_get(const Evas_Object *eo_obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
Retrieves the position and (rectangular) size of the given Evas object.
Definition evas_object_main.c:1335

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:

ret = evas_object_smart_type_check(d.smt, _evas_smart_example_type);
printf("Adding smart object of type \"%s\" to the canvas: %s.\n",
_evas_smart_example_type, ret ? "success" : "failure");
d.clipper = evas_object_smart_clipped_clipper_get(d.smt);
printf("Checking if clipped smart object's clipper is a "
"\"static\" one: %s\n",
evas_object_static_clip_get(d.clipper) ? "yes" : "no");
evas_object_static_clip_get
EVAS_API Eina_Bool evas_object_static_clip_get(const Evas_Object *eo_obj)
Get the "static clipper" hint flag for a given Evas object.
Definition evas_object_main.c:2574
evas_object_smart_clipped_clipper_get
EVAS_API Evas_Object * evas_object_smart_clipped_clipper_get(const Evas_Object *eo_obj)
Get the clipper object for the given clipped smart object.
Definition evas_object_smart_clipped.c:14
evas_object_smart_type_check
EVAS_API Eina_Bool evas_object_smart_type_check(const Evas_Object *eo_obj, const char *type)
Checks whether a given smart object or any of its smart object parents is of a given smart class.
Definition evas_object_smart.c:430

The evas_object_smart_type_check() one will assure we have the string naming our smart class really set to the live object. The evas_object_smart_clipped_clipper_get() exemplifies usage of "static clippers" – clipped smart objects have their global clippers flagged static.

Other important things we also exemplify here are smart callbacks and smart callback introspection:

#define EVT_CHILDREN_NUMBER_CHANGED "children,changed"
static const Evas_Smart_Cb_Description _smart_callbacks[] =
{
{EVT_CHILDREN_NUMBER_CHANGED, "i"},
{NULL, NULL}
};
Evas_Smart_Cb_Description
struct _Evas_Smart_Cb_Description Evas_Smart_Cb_Description
A smart object callback description, used to provide introspection.
Definition Evas_Common.h:151

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:

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;
/* we know we don't have other types of smart callbacks
* here, just playing with it */
/* for now, we know the only one callback is the one
* reporting number of member objects changed on the
* example smart object */
evas_object_smart_callback_add(
d.smt, (*descriptions)->name,
_on_example_smart_object_child_num_change, NULL);
}
evas_object_focus_set(d.bg, EINA_TRUE);
EINA_TRUE
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition eina_types.h:539
evas_object_focus_set
EVAS_API void evas_object_focus_set(Efl_Canvas_Object *obj, Eina_Bool focus)
Indicates that this object is the keyboard event receiver on its canvas.
Definition efl_canvas_object_eo.legacy.c:39
evas_object_smart_callback_add
EVAS_API void evas_object_smart_callback_add(Evas_Object *eo_obj, const char *event, Evas_Smart_Cb func, const void *data)
Add (register) a callback function to the smart event specified by event on the smart object obj.
Definition evas_object_smart.c:1040

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:

/* callback on number of member objects changed */
_on_example_smart_object_child_num_change(void *data EINA_UNUSED,
Evas_Object *obj 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);
}
EINA_UNUSED
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition eina_types.h:339

One of the points at which we issue that callback is inside the `evas_smart_example_remove()`, code that was already shown.

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:

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"
;

Use 'l' and 'r' keys, to create new rectangles and place them on the left (`evas_smart_example_set_left()`) or right (`evas_smart_example_set_right()`) spots of our smart object, respectively. The 'w' command will remove all member objects from the smart object and delete them. The keyboard arrows will move the smart object along the canvas. See how it takes any child objects with it during its movement. The 'd' and 'i' keys will increase or decrease the smart object's size – see how it affects the children's sizes, too. Finally, 'c' will change the color of the smart object's clipper (which is the exact internal clipper coming from a clipped smart object):

d.clipper = evas_object_smart_clipped_clipper_get(d.smt);
printf("Checking if clipped smart object's clipper is a "
"\"static\" one: %s\n",
evas_object_static_clip_get(d.clipper) ? "yes" : "no");
evas_object_color_set(
d.clipper, clipper_colors[cur_color].r, clipper_colors[cur_color].g,
clipper_colors[cur_color].b, clipper_colors[cur_color].a);
evas_object_color_set
EVAS_API void evas_object_color_set(Evas_Object *obj, int r, int g, int b, int a)
Sets the general/main color of the given Evas object to the given one.
Definition evas_object_main.c:2024

"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 <Ecore_Evas.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"
static const Evas_Smart_Cb_Description _smart_callbacks[] =
{
{EVT_CHILDREN_NUMBER_CHANGED, "i"},
{NULL, NULL}
};
typedef struct _Evas_Smart_Example_Data Evas_Smart_Example_Data;
/*
* This structure augments clipped smart object's instance data,
* providing extra members required by our example smart object's
* implementation.
*/
struct _Evas_Smart_Example_Data
{
Evas_Object_Smart_Clipped_Data base;
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; \
}
EVAS_SMART_SUBCLASS_NEW(_evas_smart_example_type, _evas_smart_example,
Evas_Smart_Class, Evas_Smart_Class,
evas_object_smart_clipped_class_get, _smart_callbacks);
static void
_on_destroy(Ecore_Evas *ee EINA_UNUSED)
{
ecore_main_loop_quit();
}
/* Keep the example's window size in sync with the background image's size */
static void
_canvas_resize_cb(Ecore_Evas *ee)
{
int w, h;
ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
evas_object_resize(d.bg, w, h);
}
static void
_on_child_del(void *data,
Evas *evas EINA_UNUSED,
Evas_Object *o,
void *einfo EINA_UNUSED)
{
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;
evas_object_smart_member_del(o);
evas_object_smart_changed(example_smart);
}
static void
_evas_smart_example_child_callbacks_unregister(Evas_Object *obj)
{
evas_object_data_set(obj, "index", NULL);
evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE, _on_child_del);
}
static void
_evas_smart_example_child_callbacks_register(Evas_Object *o,
Evas_Object *child,
long idx)
{
evas_object_event_callback_add(child, EVAS_CALLBACK_FREE, _on_child_del, o);
evas_object_data_set(child, "index", (void *)(uintptr_t)(++idx));
}
/* create and setup a new example smart object's internals */
static void
_evas_smart_example_smart_add(Evas_Object *o)
{
EVAS_SMART_DATA_ALLOC(o, Evas_Smart_Example_Data);
/* call parent_sc->add() before member_adding the children, otherwise the
* smart object's clipper won't be created yet, and the children won't be
* clipped to it */
_evas_smart_example_parent_sc->add(o);
/* this is a border around the smart object's area, delimiting it */
priv->border = evas_object_image_filled_add(evas_object_evas_get(o));
evas_object_image_file_set(priv->border, border_img_path, NULL);
evas_object_image_border_set(priv->border, 3, 3, 3, 3);
evas_object_image_border_center_fill_set(
priv->border, EVAS_BORDER_FILL_NONE);
evas_object_show(priv->border);
evas_object_smart_member_add(priv->border, 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,
Evas_Coord w,
Evas_Coord h)
{
Evas_Coord ow, oh;
evas_object_geometry_get(o, NULL, NULL, &ow, &oh);
if ((ow == w) && (oh == h)) return;
/* this will trigger recalculation */
evas_object_smart_changed(o);
}
/* act on child objects' properties, before rendering */
static void
_evas_smart_example_smart_calculate(Evas_Object *o)
{
Evas_Coord x, y, w, h;
EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN(o, priv);
evas_object_geometry_get(o, &x, &y, &w, &h);
evas_object_resize(priv->border, w, h);
evas_object_move(priv->border, x, y);
if (priv->children[0])
{
evas_object_move(priv->children[0], x + 3, y + 3);
evas_object_resize(priv->children[0], (w / 2) - 3, (h / 2) - 3);
}
if (priv->children[1])
{
evas_object_move(priv->children[1], x + (w / 2), y + (h / 2));
evas_object_resize(priv->children[1], (w / 2) - 3, (h / 2) - 3);
}
}
/* setting our smart interface */
static void
_evas_smart_example_smart_set_user(Evas_Smart_Class *sc)
{
/* specializing these two */
sc->add = _evas_smart_example_smart_add;
sc->del = _evas_smart_example_smart_del;
/* clipped smart object has no hook on resizes or calculations */
sc->resize = _evas_smart_example_smart_resize;
sc->calculate = _evas_smart_example_smart_calculate;
}
/* BEGINS example smart object's own interface */
/* add a new example smart object to a canvas */
Evas_Object *
evas_smart_example_add(Evas *evas)
{
return evas_object_smart_add(evas, _evas_smart_example_smart_class_new());
}
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_smart_member_del(child);
}
/* remove a child element, return its pointer (or NULL on errors) */
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);
evas_object_smart_callback_call(
o, EVT_CHILDREN_NUMBER_CHANGED, (void *)(uintptr_t)priv->child_count);
evas_object_smart_changed(o);
return child;
}
/* set to return any previous object set to the left position of the
* smart object or NULL, if any (or on errors) */
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);
evas_object_smart_member_add(child, o);
evas_object_smart_changed(o);
priv->child_count++;
if (!ret)
{
evas_object_smart_callback_call(
o, EVT_CHILDREN_NUMBER_CHANGED, (void *)(uintptr_t)priv->child_count);
}
return ret;
}
/* set to return any previous object set to the right position of the
* smart object or NULL, if any (or on errors) */
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);
evas_object_smart_member_add(child, o);
evas_object_smart_changed(o);
priv->child_count++;
if (!ret)
{
evas_object_smart_callback_call(
o, EVT_CHILDREN_NUMBER_CHANGED, (void *)(uintptr_t)priv->child_count);
}
return ret;
}
/* END OF example smart object's own interface */
static void
_map_update(void)
{
Evas_Map *m;
Evas_Coord x, y, w, h;
evas_object_geometry_get(d.smt, &x, &y, &w, &h);
m = evas_map_new(4);
evas_map_util_points_populate_from_object(m, d.smt);
evas_map_util_rotate(m, cur_angle, x + (w / 2), y + (h / 2));
evas_object_map_set(d.smt, m);
evas_object_map_enable_set(d.smt, EINA_TRUE);
evas_map_free(m);
}
static void
_on_keydown(void *data EINA_UNUSED,
Evas *evas EINA_UNUSED,
Evas_Object *o EINA_UNUSED,
void *einfo)
{
Evas_Event_Key_Down *ev = einfo;
if (strcmp(ev->key, "q") == 0) /* print help */
{
_on_destroy(NULL);
return;
}
if (strcmp(ev->key, "h") == 0) /* print help */
{
puts(commands);
return;
}
if (strcmp(ev->key, "w") == 0) /* clear out smart object (WRT
* members) */
{
if (d.rects[0])
{
evas_smart_example_remove(d.smt, d.rects[0]);
evas_object_del(d.rects[0]);
}
if (d.rects[1])
{
evas_smart_example_remove(d.smt, d.rects[1]);
evas_object_del(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) /* insert random colored
* rectangle on the left */
{
Evas_Object *rect = evas_object_rectangle_add(d.evas), *prev;
evas_object_color_set(
rect, rand() % 255, rand() % 255, rand() % 255, 255);
evas_object_show(rect);
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",
evas_object_smart_parent_get(rect) == d.smt ? "OK!" :
"Failure!");
if (prev)
{
int r, g, b;
evas_object_color_get(prev, &r, &g, &b, NULL);
printf("Deleting previous left child,"
" which had colors (%d, %d, %d)\n", r, g, b);
evas_object_del(prev);
}
return;
}
if (strcmp(ev->key, "r") == 0) /* insert random colored
* rectangle on the right */
{
Evas_Object *rect = evas_object_rectangle_add(d.evas), *prev;
evas_object_color_set(
rect, rand() % 255, rand() % 255, rand() % 255, 255);
evas_object_show(rect);
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",
evas_object_smart_parent_get(rect) == d.smt ? "OK!" :
"Failure!");
if (prev)
{
int r, g, b;
evas_object_color_get(prev, &r, &g, &b, NULL);
printf("Deleting previous right child,"
" which had colors (%d, %d, %d)\n", r, g, b);
evas_object_del(prev);
}
return;
}
/* move smart object along the canvas */
if (strcmp(ev->key, "Right") == 0 || strcmp(ev->key, "Left") == 0 ||
strcmp(ev->key, "Up") == 0 || strcmp(ev->key, "Down") == 0)
{
Evas_Coord x, y;
evas_object_geometry_get(d.smt, &x, &y, NULL, NULL);
switch (ev->key[0])
{
case 'R':
x += 20;
break;
case 'L':
x -= 20;
break;
case 'U':
y -= 20;
break;
case 'D':
y += 20;
break;
}
evas_object_move(d.smt, x, y);
_map_update();
return;
}
/* increase smart object's size */
if (strcmp(ev->key, "i") == 0)
{
Evas_Coord w, h;
evas_object_geometry_get(d.smt, NULL, NULL, &w, &h);
w *= 1.1;
h *= 1.1;
evas_object_resize(d.smt, w, h);
_map_update();
return;
}
/* decrease smart object's size */
if (strcmp(ev->key, "d") == 0)
{
Evas_Coord w, h;
evas_object_geometry_get(d.smt, NULL, NULL, &w, &h);
w *= 0.9;
h *= 0.9;
evas_object_resize(d.smt, w, h);
_map_update();
return;
}
/* change smart object's clipper color */
if (strcmp(ev->key, "c") == 0)
{
cur_color = (cur_color + 1) % 4;
evas_object_color_set(
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;
}
/* rotate object to the right */
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
/* callback on number of member objects changed */
_on_example_smart_object_child_num_change(void *data EINA_UNUSED,
Evas_Object *obj 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)
{
const Evas_Smart_Cb_Description **descriptions;
unsigned int count;
Eina_Bool ret;
if (!ecore_evas_init())
return EXIT_FAILURE;
/* this will give you a window with an Evas canvas under the first
* engine available */
d.ee = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL);
if (!d.ee)
goto error;
ecore_evas_callback_destroy_set(d.ee, _on_destroy);
ecore_evas_callback_resize_set(d.ee, _canvas_resize_cb);
ecore_evas_show(d.ee);
/* the canvas pointer, de facto */
d.evas = ecore_evas_get(d.ee);
d.bg = evas_object_rectangle_add(d.evas);
evas_object_color_set(d.bg, 255, 255, 255, 255);
evas_object_move(d.bg, 0, 0);
evas_object_resize(d.bg, WIDTH, HEIGHT);
evas_object_show(d.bg);
d.smt = evas_smart_example_add(d.evas);
evas_object_move(d.smt, WIDTH / 4, HEIGHT / 4);
evas_object_resize(d.smt, WIDTH / 2, HEIGHT / 2);
evas_object_show(d.smt);
ret = evas_object_smart_type_check(d.smt, _evas_smart_example_type);
printf("Adding smart object of type \"%s\" to the canvas: %s.\n",
_evas_smart_example_type, ret ? "success" : "failure");
d.clipper = evas_object_smart_clipped_clipper_get(d.smt);
printf("Checking if clipped smart object's clipper is a "
"\"static\" one: %s\n",
evas_object_static_clip_get(d.clipper) ? "yes" : "no");
evas_object_color_set(
d.clipper, clipper_colors[cur_color].r, clipper_colors[cur_color].g,
clipper_colors[cur_color].b, clipper_colors[cur_color].a);
evas_object_smart_callbacks_descriptions_get(
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;
/* we know we don't have other types of smart callbacks
* here, just playing with it */
/* for now, we know the only one callback is the one
* reporting number of member objects changed on the
* example smart object */
evas_object_smart_callback_add(
d.smt, (*descriptions)->name,
_on_example_smart_object_child_num_change, NULL);
}
evas_object_focus_set(d.bg, EINA_TRUE);
evas_object_event_callback_add(
d.bg, EVAS_CALLBACK_KEY_DOWN, _on_keydown, NULL);
puts(commands);
ecore_main_loop_begin();
ecore_evas_free(d.ee);
ecore_evas_shutdown();
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");
ecore_evas_shutdown();
return -1;
}
Ecore_Evas.h
Evas wrapper functions.
EVAS_CALLBACK_KEY_DOWN
@ EVAS_CALLBACK_KEY_DOWN
Key Press Event.
Definition Evas_Common.h:430
EVAS_CALLBACK_FREE
@ EVAS_CALLBACK_FREE
Object Being Freed (Called after Del).
Definition Evas_Common.h:429
ecore_evas_init
EAPI int ecore_evas_init(void)
Inits the Ecore_Evas system.
Definition ecore_evas.c:608
ecore_evas_callback_destroy_set
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
ecore_evas_show
EAPI void ecore_evas_show(Ecore_Evas *ee)
Shows an Ecore_Evas' window.
Definition ecore_evas.c:1494
ecore_evas_get
EAPI Evas * ecore_evas_get(const Ecore_Evas *ee)
Gets an Ecore_Evas's Evas.
Definition ecore_evas.c:1314
ecore_evas_geometry_get
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
ecore_evas_new
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
ecore_evas_callback_resize_set
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
ecore_evas_shutdown
EAPI int ecore_evas_shutdown(void)
Shuts down the Ecore_Evas system.
Definition ecore_evas.c:672
ecore_evas_free
EAPI void ecore_evas_free(Ecore_Evas *ee)
Frees an Ecore_Evas.
Definition ecore_evas.c:1097
ecore_main_loop_quit
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
ecore_main_loop_begin
void ecore_main_loop_begin(void)
Runs the application main loop.
Definition ecore_main.c:1311
Eina_Bool
unsigned char Eina_Bool
Type to mimic a boolean.
Definition eina_types.h:527
Evas_Event_Key_Down
struct _Evas_Event_Key_Down Evas_Event_Key_Down
Event structure for EVAS_CALLBACK_KEY_DOWN event callbacks.
Definition Evas_Legacy.h:154
evas_object_del
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_object_color_get
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_object_event_callback_add
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_object_data_set
EVAS_API void evas_object_data_set(Evas_Object *eo_obj, const char *key, const void *data)
Set an attached data pointer to an object with a given string key.
Definition evas_data.c:5
evas_map_util_rotate
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_map_free
EVAS_API void evas_map_free(Evas_Map *m)
Free a previously allocated map.
Definition evas_map.c:745
evas_map_util_points_populate_from_object
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_map_new
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_object_smart_parent_get
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_object_map_set
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_object_map_enable_set
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_object_rectangle_add
EVAS_API Evas_Object * evas_object_rectangle_add(Evas *e)
Adds a rectangle to the given evas.
Definition evas_object_rectangle.c:78
evas_object_smart_callbacks_descriptions_get
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_object_smart_member_del
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
_Evas_Event_Key_Down::key
const char * key
The logical key : (eg shift+1 == exclamation).
Definition Evas_Legacy.h:320