Evas object stacking functions (and some event handling)

In this example, we illustrate how to stack objects in a custom manner and how to deal with layers.

We have three objects of interest in it – white background, red rectangle, green rectangle and blue rectangle.

d.bg = evas_object_rectangle_add(d.canvas);
evas_object_name_set(d.bg, "background"); /* white bg */
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_API void evas_object_name_set(Evas_Object *eo_obj, const char *name)
Sets the name of the given Evas object to the given name.
Definition: evas_name.c:5
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
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_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
EVAS_API Evas_Object * evas_object_rectangle_add(Evas *e)
Adds a rectangle to the given evas.
Definition: evas_object_rectangle.c:78
d.rects[2] = evas_object_rectangle_add(d.canvas);
evas_object_name_set(d.rects[2], "blue");
evas_object_color_set(d.rects[2], 0, 0, 255, 255);
evas_object_resize(d.rects[2], WIDTH / 2.2, WIDTH / 2.2);
evas_object_move(d.rects[2], WIDTH / 6, WIDTH / 4.5);
evas_object_show(d.rects[2]);
d.rects[2], EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down, NULL);
d.rects[1] = evas_object_rectangle_add(d.canvas);
evas_object_name_set(d.rects[1], "green");
evas_object_color_set(d.rects[1], 0, 255, 0, 255);
evas_object_resize(d.rects[1], WIDTH / 2.2, WIDTH / 2.2);
evas_object_move(d.rects[1], WIDTH / 2.5, WIDTH / 7);
evas_object_show(d.rects[1]);
d.rects[1], EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down, NULL);
d.rects[0] = evas_object_rectangle_add(d.canvas);
evas_object_name_set(d.rects[0], "red");
evas_object_color_set(d.rects[0], 255, 0, 0, 255);
evas_object_resize(d.rects[0], WIDTH / 2.2, WIDTH / 2.2);
evas_object_move(d.rects[0], WIDTH / 3, WIDTH / 2.5);
evas_object_show(d.rects[0]);
@ EVAS_CALLBACK_MOUSE_DOWN
Mouse Button Down Event.
Definition: Evas_Common.h:422
EVAS_API void evas_object_show(Evas_Object *eo_obj)
Makes the given Evas object visible.
Definition: evas_object_main.c:1814
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

Like in other Evas examples, one interacts with it by means of key commands:

static const char *commands = \
"commands are:\n"
"\tc - change the target rectangle to operate on\n"
"\ta - stack target rectangle one level above\n"
"\tb - stack target rectangle one level below\n"
"\tt - stack target rectangle up to the top of its layer\n"
"\tm - stack target rectangle down to the bottom of its layer\n"
"\tp - toggle target rectangle's 'pass events' property\n"
"\tr - toggle target rectangle's 'repeat events' property\n"
"\ts - print current stacking information\n"
"\tl - change background rectangle's layer\n"
"\th - print help\n";

At any given point, like seem above, you'll be operating one rectangle only. You may stacking it below an adjacent object with "b":

evas_object_stack_below(d.rects[d.cur_rect], neighbour);
EVAS_API void evas_object_stack_below(Evas_Object *obj, Evas_Object *below)
Stack obj immediately below below.
Definition: evas_stack.x:231

"a" will do the opposite:

evas_object_stack_above(d.rects[d.cur_rect], neighbour);
EVAS_API void evas_object_stack_above(Evas_Object *obj, Evas_Object *above)
Stack obj immediately above above.
Definition: evas_stack.x:137

To bring it directly to the top/bottom, use "t"/"m", respectively:

evas_object_raise(d.rects[d.cur_rect]);
EVAS_API void evas_object_raise(Evas_Object *obj)
Raise obj to the top of its layer.
Definition: evas_stack.x:38
evas_object_lower(d.rects[d.cur_rect]);
EVAS_API void evas_object_lower(Evas_Object *obj)
Lower obj to the bottom of its layer.
Definition: evas_stack.x:87

At any time, use the "s" command to see the status of the ordering. It will show the background's ordering too. Note that it also shows the layer for this object. It starts at a different layer than the others. Use "l" to change its layer (higher layer numbers mean higher layers). If the background is on the same layer as the others (0), you'll see it interact with them on the ordering. If it's in the layer above, no matter what you do, you'll see nothing but the white rectangle: it covers the other layers. For the initial layer (-1), it will never mess nor occlude the others.

Let's make some tests with those commands. The rectangle which starts selected and which will receive our commands is the red one. It starts stacked above all the others, like seem above:

Stack it one level below, with 'b', and you'll get:

Note how the rectangle which laid above it, the green one, is now on top of it. Now change the rectangle to operate on to the blue one, with two consecutive 'c' commands. Note that it's the lowest one on the stack of rectangles. Issue the 'a' command for it, thus re-stacking it one level above:

You can send it to the top of its layer directly with the 't' command:

Now put it back to the bottom of that layer with 'm':

Like said above, we have two layers used at the beginning of the example: the default one (0) and the one immediately below it (-1), for the white background. Let's change this setup by issuing the 'l' command, which will change the background's layer to 1, i.e., a layer above the one holding the other rectangles:

See how it now covers everything else. Press 'l' again, taking it now to layer 0. It's still covering everything because it lands the layer as the highest one on the objects stack. As we have the blue rectangle as the one receiving stacking commands, hit 't' and you'll see it again:

By bringing the background back to layer -1 ('l'), you'll get:

The last two commands available are "p" and "r", which will make the target rectangle to pass (ignore) and repeat the mouse events occurring on it (the commands will cycle through on and off states). This is demonstrated with the following EVAS_CALLBACK_MOUSE_DOWN callback, registered on each of the colored rectangles:

static void
_on_mouse_down(void *data EINA_UNUSED,
void *einfo EINA_UNUSED)
{
printf("Mouse down on rectangle %s!\n", _name_get(o));
}
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339
Eo Evas
An opaque handle to an Evas canvas.
Definition: Evas_Common.h:163
Efl_Canvas_Object Evas_Object
An Evas Object handle.
Definition: Evas_Common.h:185

Try to change these properties on the three rectangles while experimenting with mouse clicks on their intersection region.

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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#define WIDTH 320
#define HEIGHT 320
struct test_data
{
Ecore_Evas *ee;
Evas *canvas;
Evas_Object *rects[3]; /* red, green, blue */
int layers[3]; /* default, below it, above it */
int cur_rect, cur_layer;
};
static struct test_data d = {0};
static const char *commands = \
"commands are:\n"
"\tc - change the target rectangle to operate on\n"
"\ta - stack target rectangle one level above\n"
"\tb - stack target rectangle one level below\n"
"\tt - stack target rectangle up to the top of its layer\n"
"\tm - stack target rectangle down to the bottom of its layer\n"
"\tp - toggle target rectangle's 'pass events' property\n"
"\tr - toggle target rectangle's 'repeat events' property\n"
"\ts - print current stacking information\n"
"\tl - change background rectangle's layer\n"
"\th - print help\n";
static const char *
_name_get(Evas_Object *o)
{
const char *s = evas_object_name_get(o);
if (!s) s = "(null)";
return s;
}
static void
_on_mouse_down(void *data EINA_UNUSED,
void *einfo EINA_UNUSED)
{
printf("Mouse down on rectangle %s!\n", _name_get(o));
}
/* 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);
}
/* use the following commands to interact with this example - 'h' is
* the key for help */
static void
_on_keydown(void *data EINA_UNUSED,
void *einfo)
{
Evas_Event_Key_Down *ev = einfo;
const char *name = _name_get(d.rects[d.cur_rect]);
if (strcmp(ev->key, "h") == 0) /* print help */
{
printf("%s\n", commands);
return;
}
if (strcmp(ev->key, "s") == 0) /* get status of the
* rectangles WRT size
* hints */
{
Evas_Object *rect;
printf("Order of stacking, from top to bottom, is: ");
rect = evas_object_top_get(evas);
printf("%s", _name_get(rect));
rect = evas_object_below_get(rect);
while (rect)
{
printf(", %s", _name_get(rect));
rect = evas_object_below_get(rect);
}
printf(".\n");
printf("Current target rectangle is %s\n",
_name_get(d.rects[d.cur_rect]));
printf("Background rectangle's layer is %d\n",
return;
}
if (strcmp(ev->key, "l") == 0) /* change background rectangle's layer */
{
d.cur_layer = (d.cur_layer + 1) % 3;
evas_object_layer_set(d.bg, d.layers[d.cur_layer]);
printf("Changing background rectangle's layer to %d\n",
d.layers[d.cur_layer]);
return;
}
if (strcmp(ev->key, "c") == 0) /* change rectangle to operate on */
{
d.cur_rect = (d.cur_rect + 1) % 3;
printf("Changing target rectangle to the %s one\n",
_name_get(d.rects[d.cur_rect]));
return;
}
if (strcmp(ev->key, "t") == 0) /* bring target to top */
{
Evas_Object *neighbour;
evas_object_raise(d.rects[d.cur_rect]);
printf("%s rectangle was re-stacked to the top if its layer\n",
name);
neighbour = evas_object_below_get(d.rects[d.cur_rect]);
printf("Below of %s rect is %s\n", name,
neighbour ? _name_get(neighbour) : "no object");
return;
}
if (strcmp(ev->key, "m") == 0) /* bring target to bottom */
{
Evas_Object *neighbour;
evas_object_lower(d.rects[d.cur_rect]);
printf("%s rectangle was re-stacked to the bottom if its layer\n",
name);
neighbour = evas_object_below_get(d.rects[d.cur_rect]);
printf("Below of %s rect is %s\n", name,
neighbour ? _name_get(neighbour) : "no object");
return;
}
if (strcmp(ev->key, "p") == 0) /* toggle pass events */
{
Eina_Bool pass = evas_object_pass_events_get(d.rects[d.cur_rect]);
evas_object_pass_events_set(d.rects[d.cur_rect], !pass);
printf("%s rectangle is now set to%s pass (ignore) events\n",
name, pass ? " NOT" : "");
return;
}
if (strcmp(ev->key, "r") == 0) /* toggle repeat events */
{
Eina_Bool repeat = evas_object_repeat_events_get(d.rects[d.cur_rect]);
evas_object_repeat_events_set(d.rects[d.cur_rect], !repeat);
printf("%s rectangle is now set to%s repeat events\n",
name, repeat ? " NOT" : "");
return;
}
if (strcmp(ev->key, "a") == 0) /* stack target above */
{
Evas_Object *neighbour = evas_object_above_get(d.rects[d.cur_rect]);
if (!neighbour || (evas_object_layer_get(d.rects[d.cur_rect]) !=
evas_object_layer_get(neighbour)))
return;
evas_object_stack_above(d.rects[d.cur_rect], neighbour);
printf("%s rectangle was re-stacked one level above\n", name);
neighbour = evas_object_above_get(d.rects[d.cur_rect]);
printf("Above of %s rect is %s\n", name,
neighbour ? _name_get(neighbour) : "no object");
neighbour = evas_object_below_get(d.rects[d.cur_rect]);
printf("Below of %s rect is %s\n", name,
neighbour ? _name_get(neighbour) : "no object");
return;
}
if (strcmp(ev->key, "b") == 0) /* stack target below */
{
Evas_Object *neighbour = evas_object_below_get(d.rects[d.cur_rect]);
if (!neighbour || (evas_object_layer_get(d.rects[d.cur_rect]) !=
evas_object_layer_get(neighbour)))
return;
evas_object_stack_below(d.rects[d.cur_rect], neighbour);
printf("%s rectangle was re-stacked one level below\n", name);
neighbour = evas_object_above_get(d.rects[d.cur_rect]);
printf("Above of %s rect is %s\n", name,
neighbour ? _name_get(neighbour) : "no object");
neighbour = evas_object_below_get(d.rects[d.cur_rect]);
printf("Below of %s rect is %s\n", name,
neighbour ? _name_get(neighbour) : "no object");
return;
}
}
static void
_on_destroy(Ecore_Evas *ee EINA_UNUSED)
{
}
int
main(void)
{
return EXIT_FAILURE;
/* this will give you a window with an Evas canvas under the first
* engine available */
d.ee = ecore_evas_new(NULL, 0, 0, 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);
/* the canvas pointer, de facto */
d.canvas = ecore_evas_get(d.ee);
d.bg = evas_object_rectangle_add(d.canvas);
evas_object_name_set(d.bg, "background"); /* white bg */
evas_object_color_set(d.bg, 255, 255, 255, 255);
evas_object_move(d.bg, 0, 0);
evas_object_resize(d.bg, WIDTH, HEIGHT);
d.layers[0] = evas_object_layer_get(d.bg);
d.layers[1] = d.layers[0] - 1;
d.layers[2] = d.layers[0] + 1;
d.cur_layer = 1;
evas_object_layer_set(d.bg, d.layers[d.cur_layer]); /* let's start with it
* below the default
* layer */
d.bg, EVAS_CALLBACK_KEY_DOWN, _on_keydown, NULL);
d.rects[2] = evas_object_rectangle_add(d.canvas);
evas_object_name_set(d.rects[2], "blue");
evas_object_color_set(d.rects[2], 0, 0, 255, 255);
evas_object_resize(d.rects[2], WIDTH / 2.2, WIDTH / 2.2);
evas_object_move(d.rects[2], WIDTH / 6, WIDTH / 4.5);
evas_object_show(d.rects[2]);
d.rects[2], EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down, NULL);
d.rects[1] = evas_object_rectangle_add(d.canvas);
evas_object_name_set(d.rects[1], "green");
evas_object_color_set(d.rects[1], 0, 255, 0, 255);
evas_object_resize(d.rects[1], WIDTH / 2.2, WIDTH / 2.2);
evas_object_move(d.rects[1], WIDTH / 2.5, WIDTH / 7);
evas_object_show(d.rects[1]);
d.rects[1], EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down, NULL);
d.rects[0] = evas_object_rectangle_add(d.canvas);
evas_object_name_set(d.rects[0], "red");
evas_object_color_set(d.rects[0], 255, 0, 0, 255);
evas_object_resize(d.rects[0], WIDTH / 2.2, WIDTH / 2.2);
evas_object_move(d.rects[0], WIDTH / 3, WIDTH / 2.5);
evas_object_show(d.rects[0]);
d.rects[0], EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down, NULL);
printf("%s\n", 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 wrapper functions.
@ EVAS_CALLBACK_KEY_DOWN
Key Press Event.
Definition: Evas_Common.h:430
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
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
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
EVAS_API Efl_Canvas_Object * evas_object_top_get(const Evas_Canvas *obj)
Get the highest (stacked) Evas object on the canvas e.
Definition: evas_canvas_eo.legacy.c:63
EVAS_API const char * evas_object_name_get(const Evas_Object *eo_obj)
Retrieves the name of the given Evas object.
Definition: evas_name.c:26
EVAS_API Eina_Bool evas_object_pass_events_get(const Efl_Canvas_Object *obj)
Determine whether an object is set to pass (ignore) events.
Definition: efl_canvas_object_eo.legacy.c:82
EVAS_API Evas_Object * evas_object_below_get(const Evas_Object *obj)
Get the Evas object stacked right below obj.
Definition: evas_stack.x:352
EVAS_API void evas_object_layer_set(Evas_Object *obj, short l)
Sets the layer of its canvas that the given object will be part of.
Definition: evas_layer.c:212
EVAS_API Evas_Object * evas_object_above_get(const Evas_Object *obj)
Get the Evas object stacked right above obj.
Definition: evas_stack.x:323
EVAS_API void evas_object_pass_events_set(Efl_Canvas_Object *obj, Eina_Bool pass)
Set whether an Evas object is to pass (ignore) events.
Definition: efl_canvas_object_eo.legacy.c:76
EVAS_API short evas_object_layer_get(const Evas_Object *obj)
Retrieves the layer of its canvas that the given object is part of.
Definition: evas_layer.c:269
EVAS_API Eina_Bool evas_object_repeat_events_get(const Efl_Canvas_Object *obj)
Determine whether an object is set to repeat events.
Definition: efl_canvas_object_eo.legacy.c:33
EVAS_API void evas_object_repeat_events_set(Efl_Canvas_Object *obj, Eina_Bool repeat)
Set whether an Evas object is to repeat events.
Definition: efl_canvas_object_eo.legacy.c:27
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
Key press event.
Definition: Evas_Legacy.h:314
const char * key
The logical key : (eg shift+1 == exclamation)
Definition: Evas_Legacy.h:320