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