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