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