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