Box - Layout transitions

Setting a customized layout for a box is simple once you have the layout function, which is just like the layout function for Evas_Box. The new and fancier thing we can do with Elementary is animate the transition from one layout to the next. We'll see now how to do that through a simple example, while also taking a look at some of the API that was left untouched in our previous example.

#include <Elementary.h>

Our application data consists of a list of layout functions, given by transitions. We'll be animating through them throughout the entire run. The box with the stuff to move around and the last layout that was set to make things easier in the code.

typedef struct
{
Eina_List *transitions;
} Transitions_Data;
void(* Evas_Object_Box_Layout)(Evas_Object *o, Evas_Object_Box_Data *priv, void *user_data)
Function signature for an Evas box object layouting routine.
Definition: Evas_Common.h:2726
Efl_Canvas_Object Evas_Object
An Evas Object handle.
Definition: Evas_Common.h:185
Type for a generic double linked list.
Definition: eina_list.h:318

The box starts with three buttons, clicking on any of them will take it out of the box without deleting the object. There are also two more buttons outside, one to add an object to the box and the other to clear it. This is all to show how you can interact with the items in the box, add things and even remove them, while the transitions occur.

One of the callback we'll be using creates a new button, asks the box for the list of its children and if it's not empty, we add the new object after the first one, otherwise just place at the end as it will not make any difference.

static void
_add_cb(void *data, Evas_Object *obj EINA_UNUSED, void *ev EINA_UNUSED)
{
Eina_List *children;
Transitions_Data *tdata = data;
btn = elm_button_add(tdata->box);
elm_object_text_set(btn, "I do nothing");
children = (Eina_List *)elm_box_children_get(tdata->box);
if (children)
{
elm_box_pack_after(tdata->box, btn, (Evas_Object *)children->data);
eina_list_free(children);
}
EINA_API Eina_List * eina_list_free(Eina_List *list)
Frees an entire list and all the nodes, ignoring the data contained.
Definition: eina_list.c:823
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339
Eina_List * elm_box_children_get(const Elm_Box *obj)
Get a list of the objects packed into the box.
Definition: elm_box_eo.legacy.c:51
void elm_box_pack_after(Elm_Box *obj, Efl_Canvas_Object *subobj, Efl_Canvas_Object *after)
Adds an object to the box after the indicated object.
Definition: elm_box_eo.legacy.c:75
Evas_Object * elm_button_add(Evas_Object *parent)
Add a new button to the parent's canvas.
Definition: efl_ui_button.c:459
void * data
Pointer to list element payload.
Definition: eina_list.h:319
else
elm_box_pack_end(tdata->box, btn);
}
void elm_box_pack_end(Elm_Box *obj, Efl_Canvas_Object *subobj)
Add an object at the end of the pack list.
Definition: elm_box_eo.legacy.c:57
EVAS_API void evas_object_show(Evas_Object *eo_obj)
Makes the given Evas object visible.
Definition: evas_object_main.c:1814

The clear button is even simpler. Everything in the box will be deleted, leaving it empty and ready to fill it up with more stuff.

static void
_clear_cb(void *data, Evas_Object *obj EINA_UNUSED, void *ev EINA_UNUSED)
{
Transitions_Data *tdata = data;
elm_box_clear(tdata->box);
}
void elm_box_clear(Elm_Box *obj)
Clear the box of all children.
Definition: elm_box_eo.legacy.c:99

And a little function to remove buttons from the box without deleting them. This one is set for the clicked callback of the original buttons, unpacking them when clicked and placing it somewhere in the screen where they will not disturb. Once we do this, the box no longer has any control of it, so it will be left untouched until the program ends.

static void
_unpack_cb(void *data, Evas_Object *obj, void *ev EINA_UNUSED)
{
Transitions_Data *tdata = data;
elm_box_unpack(tdata->box, obj);
evas_object_move(obj, 0, 50);
evas_object_color_set(obj, 128, 64, 0, 128);
}
void elm_box_unpack(Elm_Box *obj, Efl_Canvas_Object *subobj)
Unpack a box item.
Definition: elm_box_eo.legacy.c:69
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

If we wanted, we could just call evas_object_del() on the object to destroy it. In this case, no unpack is really necessary, as the box would be notified of a child being deleted and adjust its calculations accordingly.

The core of the program is the following function. It takes whatever function is first on our list of layouts and together with the last_layout, it creates an Elm_Box_Transition to use with elm_box_layout_transition(). In here, we tell it to start from whatever layout we last set, end with the one that was at the top of the list and when everything is finished, call us back so we can create another transition. Finally, move the new layout to the end of the list so we can continue running through them until the program ends.

static void
_test_box_transition_change(void *data)
{
Transitions_Data *tdata = data;
Elm_Box_Transition *layout_data;
if (!data) return;
next_layout = eina_list_data_get(tdata->transitions);
layout_data = elm_box_transition_new(2.0, tdata->last_layout,
NULL, NULL, next_layout, NULL, NULL,
_test_box_transition_change, tdata);
tdata->last_layout = next_layout;
tdata->transitions = eina_list_demote_list(tdata->transitions,
tdata->transitions);
}
EINA_API Eina_List * eina_list_demote_list(Eina_List *list, Eina_List *move_list)
Moves the specified data to the tail of the list.
Definition: eina_list.c:889
static void * eina_list_data_get(const Eina_List *list)
Gets the list node data member.
void elm_box_layout_transition(Evas_Object *obj, Evas_Object_Box_Data *priv, void *data)
Special layout function that animates the transition from one layout to another.
Definition: elm_box.c:514
Elm_Box_Transition * elm_box_transition_new(const double duration, Evas_Object_Box_Layout start_layout, void *start_layout_data, Ecore_Cb start_layout_free_data, Evas_Object_Box_Layout end_layout, void *end_layout_data, Ecore_Cb end_layout_free_data, Ecore_Cb transition_end_cb, void *transition_end_data)
Create a new Elm_Box_Transition to animate the switch of layouts.
Definition: elm_box.c:549
void elm_box_layout_set(Eo *obj, Evas_Object_Box_Layout cb, const void *data, Ecore_Cb free_data)
Set the layout defining function to be used by the box.
Definition: elm_box.c:502
void elm_box_transition_free(void *data)
Free a Elm_Box_Transition instance created with elm_box_transition_new().
Definition: elm_box.c:581
Definition: elm_widget_box.h:36

The main function doesn't have anything special. Creation of box, initial buttons and some callback setting. The only part worth mentioning is the initialization of our application data.

tdata.box = bx;
tdata.last_layout = evas_object_box_layout_horizontal;
tdata.transitions = eina_list_append(tdata.transitions,
tdata.transitions = eina_list_append(tdata.transitions,
tdata.transitions = eina_list_append(tdata.transitions,
EINA_API Eina_List * eina_list_append(Eina_List *list, const void *data)
Appends the given data to the given linked list.
Definition: eina_list.c:584
EVAS_API void evas_object_box_layout_vertical(Evas_Box *obj, Evas_Object_Box_Data *priv, void *data)
Layout function which sets the box o to a (basic) vertical box.
Definition: evas_box_eo.legacy.c:39
EVAS_API void evas_object_box_layout_horizontal(Evas_Box *obj, Evas_Object_Box_Data *priv, void *data)
Layout function which sets the box o to a (basic) horizontal box.
Definition: evas_box_eo.legacy.c:33
EVAS_API void evas_object_box_layout_stack(Evas_Box *obj, Evas_Object_Box_Data *priv, void *data)
Layout function which sets the box o to a stacking box.
Definition: evas_box_eo.legacy.c:147

We have a simple static variable, set the box, the first layout we are using as last and create the list with the different functions to go through.

And in the end, we set the first layout and call the same function we went through before to start the run of transitions.

tdata.transitions = eina_list_append(tdata.transitions,
tdata.transitions = eina_list_append(tdata.transitions,
tdata.transitions = eina_list_append(tdata.transitions,
tdata.transitions = eina_list_append(tdata.transitions,
tdata.transitions = eina_list_append(tdata.transitions,
_test_box_transition_change(&tdata);
EVAS_API void evas_object_box_layout_homogeneous_vertical(Evas_Box *obj, Evas_Object_Box_Data *priv, void *data)
Layout function which sets the box o to a homogeneous vertical box.
Definition: evas_box_eo.legacy.c:153
EVAS_API void evas_object_box_layout_flow_vertical(Evas_Box *obj, Evas_Object_Box_Data *priv, void *data)
Layout function which sets the box o to a flow vertical box.
Definition: evas_box_eo.legacy.c:51
EVAS_API void evas_object_box_layout_homogeneous_horizontal(Evas_Box *obj, Evas_Object_Box_Data *priv, void *data)
Layout function which sets the box o to a homogeneous horizontal box.
Definition: evas_box_eo.legacy.c:123
EVAS_API void evas_object_box_layout_flow_horizontal(Evas_Box *obj, Evas_Object_Box_Data *priv, void *data)
Layout function which sets the box o to a flow horizontal box.
Definition: evas_box_eo.legacy.c:159

For the full code, follow here.