Elementary: Added ui-mirroring support for all the widgets.
[framework/uifw/elementary.git] / src / lib / elm_box.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define SIG_CHILD_ADDED "child,added"
5 #define SIG_CHILD_REMOVED "child,removed"
6
7 /**
8  * @defgroup Box Box
9  *
10  * A box object arranges objects in a single row within a box. Sub objects can
11  * be added at the start, end or before or after any existing object in the
12  * box already. It can have its orientation changed too. How a child object is
13  * sized and otherwise arranged within the box depends on evas hints.
14  * evas_object_size_hint_align_set() will set either the alignment within its
15  * region if the region allocated is bigger than the object size. If you want
16  * the sub object sized up to fill the allocated region, use -1.0 for the
17  * apporpriate horizontal or vertical axes. evas_object_size_hint_weight_set()
18  * will set the packing weight. The weights of all items being packed are added
19  * up and if items are to be sized up to fit, those with the higher weights get
20  * proportionally more space.
21  *
22  * NOTE: Objects should not be added to box objects using _add() calls.
23  */
24 typedef struct _Widget_Data Widget_Data;
25 typedef struct _Transition_Animation_Data Transition_Animation_Data;
26
27 struct _Widget_Data
28 {
29    Evas_Object *box;
30    Eina_Bool horizontal:1;
31    Eina_Bool homogeneous:1;
32 };
33
34 struct _Elm_Box_Transition
35 {
36    double initial_time;
37    double duration;
38    Eina_Bool animation_ended:1;
39    Eina_Bool recalculate:1;
40    Ecore_Animator *animator;
41
42    struct
43    {
44       Evas_Object_Box_Layout layout;
45       void *data;
46       void(*free_data)(void *data);
47    } start, end;
48
49    void(*transition_end_cb)(void *data);
50    void *transition_end_data;
51    void (*transition_end_free_data)(void *data);
52    Eina_List *objs;
53    Evas_Object *box;
54 };
55
56 struct _Transition_Animation_Data
57 {
58    Evas_Object *obj;
59    struct
60    {
61       Evas_Coord x, y, w, h;
62    } start, end;
63 };
64
65 static const char *widtype = NULL;
66 static void _del_hook(Evas_Object *obj);
67 static void _sizing_eval(Evas_Object *obj);
68 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
69 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
70
71 static void
72 _del_pre_hook(Evas_Object *obj)
73 {
74     Widget_Data *wd = elm_widget_data_get(obj);
75    if (!wd) return;
76     evas_object_event_callback_del_full
77         (wd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, obj);
78     evas_object_box_remove_all(wd->box, 0);
79 }
80
81 static void
82 _del_hook(Evas_Object *obj)
83 {
84    Widget_Data *wd = elm_widget_data_get(obj);
85    if (!wd) return;
86    free(wd);
87 }
88
89 static void *
90 _elm_box_list_data_get(const Eina_List *list)
91 {
92    Evas_Object_Box_Option *opt = eina_list_data_get(list);
93    return opt->obj;
94 }
95
96 static Eina_Bool
97 _elm_box_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
98 {
99    Widget_Data *wd = elm_widget_data_get(obj);
100    const Eina_List *items;
101    void *(*list_data_get) (const Eina_List *list);
102
103    if ((!wd) || (!wd->box))
104      return EINA_FALSE;
105
106    /* Focus chain */
107    /* TODO: Change this to use other chain */
108    if ((items = elm_widget_focus_custom_chain_get(obj)))
109      list_data_get = eina_list_data_get;
110    else
111      {
112         Evas_Object_Box_Data *bd = evas_object_smart_data_get(wd->box);
113         items = bd->children;
114         list_data_get = _elm_box_list_data_get;
115
116         if (!items) return EINA_FALSE;
117      }
118
119    return elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next);
120 }
121
122 static void
123 _theme_hook(Evas_Object *obj)
124 {
125    Widget_Data *wd = elm_widget_data_get(obj);
126    if (!wd) return;
127    evas_object_smart_calculate(wd->box);
128 }
129
130 static void
131 _sizing_eval(Evas_Object *obj)
132 {
133    Widget_Data *wd = elm_widget_data_get(obj);
134    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
135    Evas_Coord w, h;
136    if (!wd) return;
137    evas_object_size_hint_min_get(wd->box, &minw, &minh);
138    evas_object_size_hint_max_get(wd->box, &maxw, &maxh);
139    evas_object_size_hint_min_set(obj, minw, minh);
140    evas_object_size_hint_max_set(obj, maxw, maxh);
141    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
142    if (w < minw) w = minw;
143    if (h < minh) h = minh;
144    if ((maxw >= 0) && (w > maxw)) w = maxw;
145    if ((maxh >= 0) && (h > maxh)) h = maxh;
146    evas_object_resize(obj, w, h);
147 }
148
149 static void
150 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
151 {
152    _sizing_eval(data);
153 }
154
155 static void
156 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
157 {
158    _sizing_eval(obj);
159 }
160
161 static void
162 _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data)
163 {
164    Evas_Object *obj = (Evas_Object *) data;
165    Widget_Data *wd = elm_widget_data_get(obj);
166    if (!wd) return;
167    _els_box_layout(o, priv, wd->horizontal, wd->homogeneous,
168          elm_widget_mirrored_get(obj));
169 }
170
171 static Eina_Bool
172 _transition_animation(void *data)
173 {
174    evas_object_smart_changed(data);
175    return ECORE_CALLBACK_RENEW;
176 }
177
178 static void
179 _transition_layout_child_added(void *data, Evas_Object *obj __UNUSED__, void *event_info)
180 {
181    Transition_Animation_Data *tad;
182    Evas_Object_Box_Option *opt = event_info;
183    Elm_Box_Transition *layout_data = data;
184
185    tad = calloc(1, sizeof(Transition_Animation_Data));
186    if (!tad) return;
187    tad->obj = opt->obj;
188    layout_data->objs = eina_list_append(layout_data->objs, tad);
189    layout_data->recalculate = EINA_TRUE;
190 }
191
192 static void
193 _transition_layout_child_removed(void *data, Evas_Object *obj __UNUSED__, void *event_info)
194 {
195    Eina_List *l;
196    Transition_Animation_Data *tad;
197    Elm_Box_Transition *layout_data = data;
198
199    EINA_LIST_FOREACH(layout_data->objs, l, tad)
200      {
201         if (tad->obj == event_info)
202           {
203              free(eina_list_data_get(l));
204              layout_data->objs = eina_list_remove_list(layout_data->objs, l);
205              layout_data->recalculate = EINA_TRUE;
206              break;
207           }
208      }
209 }
210
211 static void
212 _transition_layout_obj_resize_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
213 {
214    Elm_Box_Transition *layout_data = data;
215    layout_data->recalculate = EINA_TRUE;
216 }
217
218 static void
219 _transition_layout_calculate_coords(Evas_Object *obj, Evas_Object_Box_Data *priv,
220                                     Elm_Box_Transition *layout_data)
221 {
222    Eina_List *l;
223    Transition_Animation_Data *tad;
224    Evas_Coord x, y, w, h;
225    const double curtime = ecore_loop_time_get();
226
227    layout_data->duration = 
228      layout_data->duration - (curtime - layout_data->initial_time);
229    layout_data->initial_time = curtime;
230
231    evas_object_geometry_get(obj, &x, &y, &w, &h);
232    EINA_LIST_FOREACH(layout_data->objs, l, tad)
233      {
234         evas_object_geometry_get(tad->obj, &tad->start.x, &tad->start.y,
235                                  &tad->start.w, &tad->start.h);
236         tad->start.x = tad->start.x - x;
237         tad->start.y = tad->start.y - y;
238      }
239    layout_data->end.layout(obj, priv, layout_data->end.data);
240    EINA_LIST_FOREACH(layout_data->objs, l, tad)
241      {
242         evas_object_geometry_get(tad->obj, &tad->end.x, &tad->end.y,
243                                  &tad->end.w, &tad->end.h);
244         tad->end.x = tad->end.x - x;
245         tad->end.y = tad->end.y - y;
246      }
247 }
248
249 static Eina_Bool
250 _transition_layout_load_children_list(Evas_Object_Box_Data *priv,
251                                       Elm_Box_Transition *layout_data)
252 {
253    Eina_List *l;
254    Evas_Object_Box_Option *opt;
255    Transition_Animation_Data *tad;
256
257    EINA_LIST_FREE(layout_data->objs, tad)
258      free(tad);
259
260    EINA_LIST_FOREACH(priv->children, l, opt)
261      {
262         tad = calloc(1, sizeof(Transition_Animation_Data));
263         if (!tad)
264           {
265              EINA_LIST_FREE(layout_data->objs, tad)
266                free(tad);
267              layout_data->objs = NULL;
268              return EINA_FALSE;
269           }
270         tad->obj = opt->obj;
271         layout_data->objs = eina_list_append(layout_data->objs, tad);
272      }
273    return EINA_TRUE;
274 }
275
276 static Eina_Bool
277 _transition_layout_animation_start(Evas_Object *obj, Evas_Object_Box_Data *priv,
278                                    Elm_Box_Transition *layout_data, Eina_Bool(*transition_animation_cb)(void *data))
279 {
280    layout_data->start.layout(obj, priv, layout_data->start.data);
281    layout_data->box = obj;
282    layout_data->initial_time = ecore_loop_time_get();
283
284    if (!_transition_layout_load_children_list(priv, layout_data))
285       return EINA_FALSE;
286    _transition_layout_calculate_coords(obj, priv, layout_data);
287
288    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, 
289                                   _transition_layout_obj_resize_cb, layout_data);
290    evas_object_smart_callback_add(obj, SIG_CHILD_ADDED, 
291                                   _transition_layout_child_added, layout_data);
292    evas_object_smart_callback_add(obj, SIG_CHILD_REMOVED, 
293                                   _transition_layout_child_removed, layout_data);
294    if (!layout_data->animator)
295       layout_data->animator = ecore_animator_add(transition_animation_cb, obj);
296    layout_data->animation_ended = EINA_FALSE;
297    return EINA_TRUE;
298 }
299
300 static void
301 _transition_layout_animation_stop(Elm_Box_Transition *layout_data)
302 {
303    layout_data->animation_ended = EINA_TRUE;
304    if (layout_data->animator)
305      {
306         ecore_animator_del(layout_data->animator);
307         layout_data->animator = NULL;
308      }
309
310    if (layout_data->transition_end_cb)
311       layout_data->transition_end_cb(layout_data->transition_end_data);
312 }
313
314 static void
315 _transition_layout_animation_exec(Evas_Object *obj, Evas_Object_Box_Data *priv __UNUSED__,
316                                   Elm_Box_Transition *layout_data, const double curtime)
317 {
318    Eina_List *l;
319    Transition_Animation_Data *tad;
320    Evas_Coord x, y, w, h;
321    Evas_Coord cur_x, cur_y, cur_w, cur_h;
322    double progress = 0.0;
323
324    progress = (curtime - layout_data->initial_time) / layout_data->duration;
325    evas_object_geometry_get(obj, &x, &y, &w, &h);
326
327    EINA_LIST_FOREACH(layout_data->objs, l, tad)
328      {
329         cur_x = x + tad->start.x + ((tad->end.x - tad->start.x) * progress);
330         cur_y = y + tad->start.y + ((tad->end.y - tad->start.y) * progress);
331         cur_w = tad->start.w + ((tad->end.w - tad->start.w) * progress);
332         cur_h = tad->start.h + ((tad->end.h - tad->start.h) * progress);
333         evas_object_move(tad->obj, cur_x, cur_y);
334         evas_object_resize(tad->obj, cur_w, cur_h);
335      }
336 }
337
338 /**
339  * Add a new box to the parent
340  *
341  * @param parent The parent object
342  * @return The new object or NULL if it cannot be created
343  *
344  * @ingroup Box
345  */
346 EAPI Evas_Object *
347 elm_box_add(Evas_Object *parent)
348 {
349    Evas_Object *obj;
350    Evas *e;
351    Widget_Data *wd;
352
353    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
354
355    wd = ELM_NEW(Widget_Data);
356    e = evas_object_evas_get(parent);
357    if (!e) return NULL;
358    obj = elm_widget_add(e);
359    ELM_SET_WIDTYPE(widtype, "box");
360    elm_widget_type_set(obj, "box");
361    elm_widget_sub_object_add(parent, obj);
362    elm_widget_data_set(obj, wd);
363    elm_widget_del_hook_set(obj, _del_hook);
364    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
365    elm_widget_focus_next_hook_set(obj, _elm_box_focus_next_hook);
366    elm_widget_can_focus_set(obj, EINA_FALSE);
367    elm_widget_highlight_ignore_set(obj, EINA_TRUE);
368    elm_widget_theme_hook_set(obj, _theme_hook);
369
370    wd->box = evas_object_box_add(e);
371    /*evas_object_box_layout_set(wd->box, evas_object_box_layout_vertical,
372                               NULL, NULL);*/
373    evas_object_box_layout_set(wd->box, _layout, obj, NULL);
374
375    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
376                                   _changed_size_hints, obj);
377    elm_widget_resize_object_set(obj, wd->box);
378
379    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
380
381    return obj;
382 }
383
384 /**
385  * Set the horizontal orientation
386  *
387  * By default box object arrange their contents vertically from top to bottom.
388  * By calling this and providing @p horizontal as true, the box will become
389  * horizontal arranging contents left to right.
390  *
391  * @param obj The box object
392  * @param horizontal The horizontal flag (1 = horizontal, 0 = vertical)
393  *
394  * @ingroup Box
395  */
396 EAPI void
397 elm_box_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
398 {
399    ELM_CHECK_WIDTYPE(obj, widtype);
400    Widget_Data *wd = elm_widget_data_get(obj);
401    if (!wd) return;
402    wd->horizontal = !!horizontal;
403    evas_object_smart_calculate(wd->box);
404    /*if (wd->horizontal)
405      {
406         if (wd->homogeneous)
407           evas_object_box_layout_set(wd->box,
408                 evas_object_box_layout_homogeneous_horizontal, NULL, NULL);
409         else
410           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
411                                      NULL, NULL);
412      }
413    else
414      {
415         if (wd->homogeneous)
416           evas_object_box_layout_set(wd->box,
417                 evas_object_box_layout_homogeneous_vertical, NULL, NULL);
418         else
419           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
420                                      NULL, NULL);
421      }*/
422 }
423
424 /**
425  * Get the horizontal orientation
426  *
427  * @param obj The box object
428  * @return If is horizontal
429  *
430  * @ingroup Box
431  */
432 EAPI Eina_Bool
433 elm_box_horizontal_get(const Evas_Object *obj)
434 {
435    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
436    Widget_Data *wd = elm_widget_data_get(obj);
437    if (!wd) return EINA_FALSE;
438    return wd->horizontal;
439 }
440
441 /**
442  * Set homogenous layout
443  *
444  * If enabled, homogenous layout makes all items the same size. This size is
445  * of course governed by the size of the largest item in the box.
446  *
447  * @param obj The box object
448  * @param homogenous The homogenous flag (1 = on, 2 = off)
449  *
450  * @ingroup Box
451  */
452 EAPI void
453 elm_box_homogenous_set(Evas_Object *obj, Eina_Bool homogenous)
454 {
455    ELM_CHECK_WIDTYPE(obj, widtype);
456    Widget_Data *wd = elm_widget_data_get(obj);
457    if (!wd) return;
458    wd->homogeneous = !!homogenous;
459    evas_object_smart_calculate(wd->box);
460    /*if (wd->horizontal)
461      {
462         if (wd->homogeneous)
463           evas_object_box_layout_set(wd->box,
464                 evas_object_box_layout_homogeneous_horizontal, NULL, NULL);
465         else
466           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
467                                      NULL, NULL);
468      }
469    else
470      {
471         if (wd->homogeneous)
472           evas_object_box_layout_set(wd->box,
473                 evas_object_box_layout_homogeneous_vertical, NULL, NULL);
474         else
475           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
476                                      NULL, NULL);
477      }*/
478 }
479
480 /**
481  * Get homogenous layout
482  *
483  * @param obj The box object
484  * @return If is homogenous
485  *
486  * @ingroup Box
487  */
488 EAPI Eina_Bool
489 elm_box_homogenous_get(const Evas_Object *obj)
490 {
491    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
492    Widget_Data *wd = elm_widget_data_get(obj);
493    if (!wd) return EINA_FALSE;
494    return wd->homogeneous;
495 }
496
497 /**
498  * This adds a box at the start of the box (top or left based on orientation)
499  *
500  * This will add the @p subobj to the box object indicated at the beginning
501  * of the box (the left or top end).
502  *
503  * @param obj The box object
504  * @param subobj The object to add to the box
505  *
506  * @ingroup Box
507  */
508 EAPI void
509 elm_box_pack_start(Evas_Object *obj, Evas_Object *subobj)
510 {
511    ELM_CHECK_WIDTYPE(obj, widtype);
512    Widget_Data *wd = elm_widget_data_get(obj);
513    if (!wd) return;
514    elm_widget_sub_object_add(obj, subobj);
515    evas_object_box_prepend(wd->box, subobj);
516 }
517
518 /**
519  * This adds a box at the end of the box (bottom or right based on orientation)
520  *
521  * This will add the @p subobj to the box object indicated at the end
522  * of the box (the right or bottom end).
523  *
524  * @param obj The box object
525  * @param subobj The object to add to the box
526  *
527  * @ingroup Box
528  */
529 EAPI void
530 elm_box_pack_end(Evas_Object *obj, Evas_Object *subobj)
531 {
532    ELM_CHECK_WIDTYPE(obj, widtype);
533    Widget_Data *wd = elm_widget_data_get(obj);
534    if (!wd) return;
535    elm_widget_sub_object_add(obj, subobj);
536    evas_object_box_append(wd->box, subobj);
537 }
538
539 /**
540  * This adds adds an object to the box before the indicated object
541  *
542  * This will add the @p subobj to the box indicated before the object
543  * indicated with @p before. If @p before is not already in the box, results
544  * are undefined. Before means either to the left of the indicated object or
545  * above it depending on orientation.
546  *
547  * @param obj The box object
548  * @param subobj The object to add to the box
549  * @param before The object before which to add it
550  *
551  * @ingroup Box
552  */
553 EAPI void
554 elm_box_pack_before(Evas_Object *obj, Evas_Object *subobj, Evas_Object *before)
555 {
556    ELM_CHECK_WIDTYPE(obj, widtype);
557    Widget_Data *wd = elm_widget_data_get(obj);
558    if (!wd) return;
559    elm_widget_sub_object_add(obj, subobj);
560    evas_object_box_insert_before(wd->box, subobj, before);
561 }
562
563 /**
564  * This adds adds an object to the box after the indicated object
565  *
566  * This will add the @p subobj to the box indicated after the object
567  * indicated with @p after. If @p after is not already in the box, results
568  * are undefined. After means either to the right of the indicated object or
569  * below it depending on orientation.
570  *
571  * @param obj The box object
572  * @param subobj The object to add to the box
573  * @param after The object after which to add it
574  *
575  * @ingroup Box
576  */
577 EAPI void
578 elm_box_pack_after(Evas_Object *obj, Evas_Object *subobj, Evas_Object *after)
579 {
580    ELM_CHECK_WIDTYPE(obj, widtype);
581    Widget_Data *wd = elm_widget_data_get(obj);
582    if (!wd) return;
583    elm_widget_sub_object_add(obj, subobj);
584    evas_object_box_insert_after(wd->box, subobj, after);
585 }
586
587 /**
588  * This clears the box items
589  *
590  * This delete all members of the box object, but not the box itself.
591  *
592  * @param obj The box object
593  *
594  * @ingroup Box
595  */
596 EAPI void
597 elm_box_clear(Evas_Object *obj)
598 {
599    ELM_CHECK_WIDTYPE(obj, widtype);
600    Widget_Data *wd = elm_widget_data_get(obj);
601    if (!wd) return;
602    evas_object_box_remove_all(wd->box, EINA_TRUE);
603 }
604
605 /**
606  * This unpack a box item
607  *
608  * This unpack the selected member from the box object, but does not delete
609  * the box itself or the packed items.
610  *
611  * @param obj The box object
612  *
613  * @ingroup Box
614  */
615 EAPI void
616 elm_box_unpack(Evas_Object *obj, Evas_Object *subobj)
617 {
618    ELM_CHECK_WIDTYPE(obj, widtype);
619    Widget_Data *wd = elm_widget_data_get(obj);
620    if (!wd) return;
621    evas_object_box_remove(wd->box, subobj);
622 }
623
624 /**
625  * This unpack the box items
626  *
627  * This unpack all members from the box object, but does not delete
628  * the box itself or the packed items.
629  *
630  * @param obj The box object
631  *
632  * @ingroup Box
633  */
634 EAPI void
635 elm_box_unpack_all(Evas_Object *obj)
636 {
637    ELM_CHECK_WIDTYPE(obj, widtype);
638    Widget_Data *wd = elm_widget_data_get(obj);
639    if (!wd) return;
640    evas_object_box_remove_all(wd->box, EINA_FALSE);
641 }
642
643 /**
644  * Set the callback layout function (@p cb) to the @p obj elm_box class.
645  *
646  * This function will use evas_object_box_layout_set() to set @p cb as the
647  * layout callback function for this box object.
648  * All layout funtions from evas_object_box can be used as @p cb. Some examples
649  * are evas_object_box_layout_horizontal, evas_object_box_layout_vertical and
650  * evas_object_box_layout_stack. elm_box_layout_transition can also be used.
651  * If @p cb is NULL, the default layout function from elm_box will be used.
652  *
653  * @note Changing the layout function will make horizontal/homogeneous fields
654  * from Widget_Data have NO further usage as they are controlled by default
655  * layout function. So calling elm_box_horizontal_set() or
656  * elm_box_homogenous_set() won't affect layout behavior.
657  *
658  * @param obj The box object
659  * @param cb The callback function used for layout
660  * @param data Data that will be passed to layout function
661  * @param free_data Function called to free @p data
662  *
663  * @ingroup Box
664  */
665 EAPI void
666 elm_box_layout_set(Evas_Object *obj, Evas_Object_Box_Layout cb, const void *data, void (*free_data)(void *data))
667 {
668    ELM_CHECK_WIDTYPE(obj, widtype);
669    Widget_Data *wd = elm_widget_data_get(obj);
670    if (!wd) return;
671
672    if (cb)
673      evas_object_box_layout_set(wd->box, cb, data, free_data);
674    else
675      evas_object_box_layout_set(wd->box, _layout, obj, NULL);
676 }
677
678 /**
679  * Layout function which display a transition animation from start layout to end layout.
680  *
681  * This function should no be called directly. It may be used by elm_box_layout_set() or
682  * evas_object_box_layout_set() as a layout function.
683  * The @p data passed to this function must be a Elm_Box_Transition*, that can be created
684  * using elm_box_transition_new() and freed with elm_box_transition_free().
685  *
686  * Usage Example:
687  * @code
688  * Evas_Object *box = elm_box_add(parent);
689  * Elm_Box_Transition *t = elm_box_transition_new(...add params here...);
690  * elm_box_layout_set(box, elm_box_layout_transition, t, elm_box_transition_free);
691  * @endcode
692  *
693  * @see elm_box_transition_new
694  * @see elm_box_transition_free
695  * @see elm_box_layout_set
696  *
697  * @ingroup Box
698  * @warning Do not call this function directly because the @p obj is not the Widget Box
699  * from elm_box_add(), it is the internal Evas_Object of the Widget Box.
700  */
701 EAPI void
702 elm_box_layout_transition(Evas_Object *obj, Evas_Object_Box_Data *priv, void *data)
703 {
704    Elm_Box_Transition *box_data = data;
705    const double curtime = ecore_loop_time_get();
706
707    if (box_data->animation_ended)
708      {
709           box_data->end.layout(obj, priv, box_data->end.data);
710           return;
711      }
712
713    if (!box_data->animator)
714      {
715         if (!_transition_layout_animation_start(obj, priv, box_data,
716             _transition_animation))
717            return;
718      }
719    else
720      {
721         if (box_data->recalculate)
722           {
723              _transition_layout_calculate_coords(obj, priv, box_data);
724              box_data->recalculate = EINA_FALSE;
725           }
726      }
727
728    if ((curtime >= box_data->duration + box_data->initial_time))
729       _transition_layout_animation_stop(box_data);
730    else
731       _transition_layout_animation_exec(obj, priv, box_data, curtime);
732 }
733
734 /**
735  * Create a new Elm_Box_Transition setted with informed parameters.
736  *
737  * The returned instance may be used as data parameter to elm_box_layout_transition()
738  * and should be freed with elm_box_transition_free().
739  *
740  * @param start_layout The layout function that will be used to start the animation
741  * @param start_layout_data The data to be passed the @p start_layout function
742  * @param start_layout_free_data Function to free @p start_layout_data
743  * @param end_layout The layout function that will be used to end the animation
744  * @param end_layout_free_data The data to be passed the @p end_layout function
745  * @param end_layout_free_data Function to free @p end_layout_data
746  * @param transition_end_cb Callback function called when animation ends
747  * @param transition_end_data Data to be passed to @p transition_end_cb
748  * @return An instance of Elm_Box_Transition setted with informed parameters
749  *
750  * @see elm_box_transition_new
751  * @see elm_box_layout_transition
752  *
753  * @ingroup Box
754  */
755 EAPI Elm_Box_Transition *
756 elm_box_transition_new(const double duration,
757       Evas_Object_Box_Layout start_layout, void *start_layout_data,
758       void(*start_layout_free_data)(void *data),
759       Evas_Object_Box_Layout end_layout, void *end_layout_data,
760       void(*end_layout_free_data)(void *data),
761       void(*transition_end_cb)(void *data),
762       void *transition_end_data)
763 {
764    Elm_Box_Transition *box_data;
765
766    EINA_SAFETY_ON_NULL_RETURN_VAL(start_layout, NULL);
767    EINA_SAFETY_ON_NULL_RETURN_VAL(end_layout, NULL);
768
769    box_data = calloc(1, sizeof(Elm_Box_Transition));
770    if (!box_data)
771       return NULL;
772
773    box_data->start.layout = start_layout;
774    box_data->start.data = start_layout_data;
775    box_data->start.free_data = start_layout_free_data;
776    box_data->end.layout = end_layout;
777    box_data->end.data = end_layout_data;
778    box_data->end.free_data = end_layout_free_data;
779    box_data->duration = duration;
780    box_data->transition_end_cb = transition_end_cb;
781    box_data->transition_end_data = transition_end_data;
782    return box_data;
783 }
784
785 /**
786  * Free a Elm_Box_Transition instance created with elm_box_transition_new().
787  *
788  * @param data The Elm_Box_Transition instance to be freed.
789  *
790  * @see elm_box_transition_new
791  * @see elm_box_layout_transition
792  *
793  * @ingroup Box
794  */
795 EAPI void
796 elm_box_transition_free(void *data)
797 {
798    EINA_SAFETY_ON_NULL_RETURN(data);
799
800    Transition_Animation_Data *tad;
801    Elm_Box_Transition *box_data = data;
802    if ((box_data->start.free_data) && (box_data->start.data))
803       box_data->start.free_data(box_data->start.data);
804    if ((box_data->end.free_data) && (box_data->end.data))
805       box_data->end.free_data(box_data->end.data);
806    EINA_LIST_FREE(box_data->objs, tad)
807       free(tad);
808    evas_object_event_callback_del(box_data->box, EVAS_CALLBACK_RESIZE, _transition_layout_obj_resize_cb);
809    evas_object_smart_callback_del(box_data->box, SIG_CHILD_ADDED, _transition_layout_child_added);
810    evas_object_smart_callback_del(box_data->box, SIG_CHILD_REMOVED, _transition_layout_child_removed);
811    if (box_data->animator)
812      {
813         ecore_animator_del(box_data->animator);
814         box_data->animator = NULL;
815      }
816    free(data);
817 }
818
819 /**
820  * Retrieve the list of children packed into an elm_box
821  *
822  * @param obj The Elm_Box
823  *
824  * @ingroup Box
825  */
826 EAPI const Eina_List *
827 elm_box_children_get(const Evas_Object *obj)
828 {
829    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
830    Widget_Data *wd = elm_widget_data_get(obj);
831    if (!wd) return NULL;
832    return evas_object_box_children_get(wd->box);
833 }
834
835 /**
836  * Set the space (padding) between the box's elements.
837  *
838  * @param obj The Elm_Box
839  * @param horizontal The horizontal space between elements
840  * @param vertical The vertical space between elements
841  * 
842  * @ingroup Box
843  */
844 EAPI void
845 elm_box_padding_set(Evas_Object *obj, Evas_Coord horizontal, Evas_Coord vertical)
846 {
847    ELM_CHECK_WIDTYPE(obj, widtype);
848    Widget_Data *wd = elm_widget_data_get(obj);
849    if (!wd) return;
850    evas_object_box_padding_set(wd->box, horizontal, vertical);
851 }
852
853 /**
854  * Get the space (padding) between the box's elements.
855  *
856  * @param obj The Elm_Box
857  * @param horizontal The horizontal space between elements
858  * @param vertical The vertical space between elements
859  *
860  * @ingroup Box
861  */
862 EAPI void
863 elm_box_padding_get(const Evas_Object *obj, Evas_Coord *horizontal, Evas_Coord *vertical)
864 {
865    ELM_CHECK_WIDTYPE(obj, widtype);
866    Widget_Data *wd = elm_widget_data_get(obj);
867    if (!wd) return;
868    evas_object_box_padding_get(wd->box, horizontal, vertical);
869 }
870
871 /**
872  * Set the alignment of the whole bouding box of contents.
873  *
874  * @param obj The Elm_Box
875  * @param horizontal The horizontal alignment of elements
876  * @param vertical The vertical alignment of elements
877  * 
878  * @ingroup Box
879  */
880 EAPI void
881 elm_box_align_set(Evas_Object *obj, double horizontal, double vertical)
882 {
883    ELM_CHECK_WIDTYPE(obj, widtype);
884    Widget_Data *wd = elm_widget_data_get(obj);
885    if (!wd) return;
886    evas_object_box_align_set(wd->box, horizontal, vertical);
887 }
888
889 /**
890  * Get the alignment of the whole bouding box of contents.
891  *
892  * @param obj The Elm_Box
893  * @param horizontal The horizontal alignment of elements
894  * @param vertical The vertical alignment of elements
895  *
896  * @ingroup Box
897  */
898 EAPI void
899 elm_box_align_get(const Evas_Object *obj, double *horizontal, double *vertical)
900 {
901    ELM_CHECK_WIDTYPE(obj, widtype);
902    Widget_Data *wd = elm_widget_data_get(obj);
903    if (!wd) return;
904    evas_object_box_align_get(wd->box, horizontal, vertical);
905 }