1 #include <Elementary.h>
4 #include "elm_widget_box.h"
6 EAPI const char ELM_BOX_SMART_NAME[] = "elm_box";
8 EVAS_SMART_SUBCLASS_NEW
9 (ELM_BOX_SMART_NAME, _elm_box, Elm_Box_Smart_Class,
10 Elm_Widget_Smart_Class, elm_widget_smart_class_get, NULL);
12 static const char SIG_CHILD_ADDED[] = "child,added";
13 static const char SIG_CHILD_REMOVED[] = "child,removed";
14 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
15 {SIG_CHILD_ADDED, ""},
16 {SIG_CHILD_REMOVED, ""},
21 _elm_box_list_data_get(const Eina_List *list)
23 Evas_Object_Box_Option *opt = eina_list_data_get(list);
28 _child_added_cb_proxy(void *data,
29 Evas_Object *o __UNUSED__,
32 Evas_Object *box = data;
33 Evas_Object_Box_Option *opt = event_info;
34 evas_object_smart_callback_call(box, SIG_CHILD_ADDED, opt->obj);
38 _child_removed_cb_proxy(void *data,
39 Evas_Object *o __UNUSED__,
42 Evas_Object *box = data;
43 Evas_Object *child = event_info;
44 evas_object_smart_callback_call(box, SIG_CHILD_REMOVED, child);
48 _elm_box_smart_focus_next(const Evas_Object *obj,
49 Elm_Focus_Direction dir,
52 const Eina_List *items;
53 void *(*list_data_get)(const Eina_List *list);
55 ELM_BOX_DATA_GET(obj, sd);
58 /* TODO: Change this to use other chain */
59 if ((items = elm_widget_focus_custom_chain_get(obj)))
60 list_data_get = eina_list_data_get;
63 Evas_Object_Box_Data *bd =
64 evas_object_smart_data_get(ELM_WIDGET_DATA(sd)->resize_obj);
67 list_data_get = _elm_box_list_data_get;
69 if (!items) return EINA_FALSE;
72 return elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next);
76 _elm_box_smart_focus_direction(const Evas_Object *obj,
77 const Evas_Object *base,
79 Evas_Object **direction,
82 const Eina_List *items;
83 void *(*list_data_get)(const Eina_List *list);
85 ELM_BOX_DATA_GET(obj, sd);
87 if ((items = elm_widget_focus_custom_chain_get(obj)))
88 list_data_get = eina_list_data_get;
91 Evas_Object_Box_Data *bd =
92 evas_object_smart_data_get(ELM_WIDGET_DATA(sd)->resize_obj);
95 list_data_get = _elm_box_list_data_get;
97 if (!items) return EINA_FALSE;
99 return elm_widget_focus_list_direction_get
100 (obj, base, items, list_data_get, degree, direction, weight);
104 _elm_box_smart_theme(Evas_Object *obj)
106 ELM_BOX_DATA_GET(obj, sd);
108 if (!_elm_box_parent_sc->theme(obj)) return EINA_FALSE;
110 evas_object_smart_calculate(ELM_WIDGET_DATA(sd)->resize_obj);
116 _sizing_eval(Evas_Object *obj)
118 Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
121 ELM_BOX_DATA_GET(obj, sd);
126 evas_object_size_hint_min_get
127 (ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh);
128 evas_object_size_hint_max_get
129 (ELM_WIDGET_DATA(sd)->resize_obj, &maxw, &maxh);
130 evas_object_size_hint_min_set(obj, minw, minh);
131 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);
142 _on_size_hints_changed(void *data,
144 Evas_Object *obj __UNUSED__,
145 void *event_info __UNUSED__)
151 _elm_box_smart_sub_object_del(Evas_Object *obj,
154 if (!_elm_box_parent_sc->sub_object_del(obj, child)) return EINA_FALSE;
162 _elm_box_custom_layout(Evas_Object *o,
163 Evas_Object_Box_Data *priv,
166 ELM_BOX_DATA_GET(data, sd);
168 _els_box_layout(o, priv, sd->horizontal, sd->homogeneous,
169 elm_widget_mirrored_get(data));
173 _transition_animation(void *data)
175 evas_object_smart_changed(data);
177 return ECORE_CALLBACK_RENEW;
181 _transition_layout_child_added(void *data,
182 Evas_Object *obj __UNUSED__,
185 Transition_Animation_Data *tad;
186 Evas_Object_Box_Option *opt = event_info;
187 Elm_Box_Transition *layout_data = data;
189 tad = calloc(1, sizeof(Transition_Animation_Data));
193 layout_data->objs = eina_list_append(layout_data->objs, tad);
194 layout_data->recalculate = EINA_TRUE;
198 _transition_layout_child_removed(void *data,
199 Evas_Object *obj __UNUSED__,
203 Transition_Animation_Data *tad;
204 Elm_Box_Transition *layout_data = data;
206 EINA_LIST_FOREACH(layout_data->objs, l, tad)
208 if (tad->obj == event_info)
210 free(eina_list_data_get(l));
211 layout_data->objs = eina_list_remove_list(layout_data->objs, l);
212 layout_data->recalculate = EINA_TRUE;
219 _transition_layout_obj_resize_cb(void *data,
221 Evas_Object *obj __UNUSED__,
222 void *event_info __UNUSED__)
224 Elm_Box_Transition *layout_data = data;
226 layout_data->recalculate = EINA_TRUE;
230 _transition_layout_calculate_coords(Evas_Object *obj,
231 Evas_Object_Box_Data *priv,
232 Elm_Box_Transition *layout_data)
235 Evas_Coord x, y, w, h;
236 Transition_Animation_Data *tad;
237 const double curtime = ecore_loop_time_get();
239 layout_data->duration =
240 layout_data->duration - (curtime - layout_data->initial_time);
241 layout_data->initial_time = curtime;
243 evas_object_geometry_get(obj, &x, &y, &w, &h);
244 EINA_LIST_FOREACH(layout_data->objs, l, tad)
246 evas_object_geometry_get(tad->obj, &tad->start.x, &tad->start.y,
247 &tad->start.w, &tad->start.h);
248 tad->start.x = tad->start.x - x;
249 tad->start.y = tad->start.y - y;
251 layout_data->end.layout(obj, priv, layout_data->end.data);
252 EINA_LIST_FOREACH(layout_data->objs, l, tad)
254 evas_object_geometry_get(tad->obj, &tad->end.x, &tad->end.y,
255 &tad->end.w, &tad->end.h);
256 tad->end.x = tad->end.x - x;
257 tad->end.y = tad->end.y - y;
262 _transition_layout_load_children_list(Evas_Object_Box_Data *priv,
263 Elm_Box_Transition *layout_data)
266 Evas_Object_Box_Option *opt;
267 Transition_Animation_Data *tad;
269 EINA_LIST_FREE (layout_data->objs, tad)
272 EINA_LIST_FOREACH(priv->children, l, opt)
274 tad = calloc(1, sizeof(Transition_Animation_Data));
277 EINA_LIST_FREE (layout_data->objs, tad)
279 layout_data->objs = NULL;
283 layout_data->objs = eina_list_append(layout_data->objs, tad);
289 _transition_layout_animation_start(Evas_Object *obj,
290 Evas_Object_Box_Data *priv,
291 Elm_Box_Transition *layout_data,
292 Eina_Bool (*transition_animation_cb)
295 layout_data->start.layout(obj, priv, layout_data->start.data);
296 layout_data->box = obj;
297 layout_data->initial_time = ecore_loop_time_get();
299 if (!_transition_layout_load_children_list(priv, layout_data))
302 _transition_layout_calculate_coords(obj, priv, layout_data);
304 evas_object_event_callback_add
305 (obj, EVAS_CALLBACK_RESIZE, _transition_layout_obj_resize_cb,
307 evas_object_smart_callback_add
308 (obj, SIG_CHILD_ADDED, _transition_layout_child_added, layout_data);
309 evas_object_smart_callback_add
310 (obj, SIG_CHILD_REMOVED, _transition_layout_child_removed, layout_data);
312 if (!layout_data->animator)
313 layout_data->animator = ecore_animator_add(transition_animation_cb, obj);
315 layout_data->animation_ended = EINA_FALSE;
321 _transition_layout_animation_stop(Elm_Box_Transition *layout_data)
323 layout_data->animation_ended = EINA_TRUE;
325 if (layout_data->animator)
327 ecore_animator_del(layout_data->animator);
328 layout_data->animator = NULL;
331 if (layout_data->transition_end_cb)
332 layout_data->transition_end_cb(layout_data->transition_end_data);
336 _transition_layout_animation_exec(Evas_Object *obj,
337 Evas_Object_Box_Data *priv __UNUSED__,
338 Elm_Box_Transition *layout_data,
339 const double curtime)
342 double progress = 0.0;
343 Evas_Coord x, y, w, h;
344 Transition_Animation_Data *tad;
345 Evas_Coord cur_x, cur_y, cur_w, cur_h;
347 progress = (curtime - layout_data->initial_time) / layout_data->duration;
348 evas_object_geometry_get(obj, &x, &y, &w, &h);
350 EINA_LIST_FOREACH(layout_data->objs, l, tad)
352 cur_x = x + tad->start.x + ((tad->end.x - tad->start.x) * progress);
353 cur_y = y + tad->start.y + ((tad->end.y - tad->start.y) * progress);
354 cur_w = tad->start.w + ((tad->end.w - tad->start.w) * progress);
355 cur_h = tad->start.h + ((tad->end.h - tad->start.h) * progress);
356 evas_object_move(tad->obj, cur_x, cur_y);
357 evas_object_resize(tad->obj, cur_w, cur_h);
362 _elm_box_smart_add(Evas_Object *obj)
364 EVAS_SMART_DATA_ALLOC(obj, Elm_Box_Smart_Data);
366 ELM_WIDGET_DATA(priv)->resize_obj =
367 evas_object_box_add(evas_object_evas_get(obj));
368 evas_object_box_layout_set
369 (ELM_WIDGET_DATA(priv)->resize_obj, _elm_box_custom_layout, obj, NULL);
371 evas_object_event_callback_add
372 (ELM_WIDGET_DATA(priv)->resize_obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
373 _on_size_hints_changed, obj);
375 _elm_box_parent_sc->base.add(obj);
377 evas_object_smart_callback_add
378 (ELM_WIDGET_DATA(priv)->resize_obj, SIG_CHILD_ADDED,
379 _child_added_cb_proxy, obj);
380 evas_object_smart_callback_add
381 (ELM_WIDGET_DATA(priv)->resize_obj, SIG_CHILD_REMOVED,
382 _child_removed_cb_proxy, obj);
384 elm_widget_can_focus_set(obj, EINA_FALSE);
385 elm_widget_highlight_ignore_set(obj, EINA_TRUE);
389 _elm_box_smart_del(Evas_Object *obj)
394 ELM_BOX_DATA_GET(obj, sd);
396 sd->on_deletion = EINA_TRUE;
398 evas_object_event_callback_del_full
399 (ELM_WIDGET_DATA(sd)->resize_obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
400 _on_size_hints_changed, obj);
402 /* let's make our box object the *last* to be processed, since it
403 * may (smart) parent other sub objects here */
404 EINA_LIST_FOREACH(ELM_WIDGET_DATA(sd)->subobjs, l, child)
406 if (child == ELM_WIDGET_DATA(sd)->resize_obj)
408 ELM_WIDGET_DATA(sd)->subobjs =
409 eina_list_demote_list(ELM_WIDGET_DATA(sd)->subobjs, l);
414 _elm_box_parent_sc->base.del(obj);
418 _elm_box_smart_set_user(Elm_Box_Smart_Class *sc)
420 ELM_WIDGET_CLASS(sc)->base.add = _elm_box_smart_add;
421 ELM_WIDGET_CLASS(sc)->base.del = _elm_box_smart_del;
423 ELM_WIDGET_CLASS(sc)->sub_object_del = _elm_box_smart_sub_object_del;
424 ELM_WIDGET_CLASS(sc)->theme = _elm_box_smart_theme;
425 ELM_WIDGET_CLASS(sc)->focus_next = _elm_box_smart_focus_next;
426 ELM_WIDGET_CLASS(sc)->focus_direction = _elm_box_smart_focus_direction;
429 EAPI const Elm_Box_Smart_Class *
430 elm_box_smart_class_get(void)
432 static Elm_Box_Smart_Class _sc =
433 ELM_BOX_SMART_CLASS_INIT_NAME_VERSION(ELM_BOX_SMART_NAME);
434 static const Elm_Box_Smart_Class *class = NULL;
435 Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
437 if (class) return class;
439 _elm_box_smart_set(&_sc);
440 esc->callbacks = _smart_callbacks;
447 elm_box_add(Evas_Object *parent)
451 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
453 obj = elm_widget_add(_elm_box_smart_class_new(), parent);
454 if (!obj) return NULL;
456 if (!elm_widget_sub_object_add(parent, obj))
457 ERR("could not add %p as sub object of %p", obj, parent);
463 elm_box_horizontal_set(Evas_Object *obj,
464 Eina_Bool horizontal)
467 ELM_BOX_DATA_GET(obj, sd);
469 sd->horizontal = !!horizontal;
470 evas_object_smart_calculate(ELM_WIDGET_DATA(sd)->resize_obj);
474 elm_box_horizontal_get(const Evas_Object *obj)
476 ELM_BOX_CHECK(obj) EINA_FALSE;
477 ELM_BOX_DATA_GET(obj, sd);
479 return sd->horizontal;
483 elm_box_homogeneous_set(Evas_Object *obj,
484 Eina_Bool homogeneous)
487 ELM_BOX_DATA_GET(obj, sd);
489 sd->homogeneous = !!homogeneous;
490 evas_object_smart_calculate(ELM_WIDGET_DATA(sd)->resize_obj);
494 elm_box_homogeneous_get(const Evas_Object *obj)
496 ELM_BOX_CHECK(obj) EINA_FALSE;
497 ELM_BOX_DATA_GET(obj, sd);
499 return sd->homogeneous;
503 elm_box_pack_start(Evas_Object *obj,
507 ELM_BOX_DATA_GET(obj, sd);
509 elm_widget_sub_object_add(obj, subobj);
510 evas_object_box_prepend(ELM_WIDGET_DATA(sd)->resize_obj, subobj);
514 elm_box_pack_end(Evas_Object *obj,
518 ELM_BOX_DATA_GET(obj, sd);
520 elm_widget_sub_object_add(obj, subobj);
521 evas_object_box_append(ELM_WIDGET_DATA(sd)->resize_obj, subobj);
525 elm_box_pack_before(Evas_Object *obj,
530 ELM_BOX_DATA_GET(obj, sd);
532 elm_widget_sub_object_add(obj, subobj);
533 evas_object_box_insert_before
534 (ELM_WIDGET_DATA(sd)->resize_obj, subobj, before);
538 elm_box_pack_after(Evas_Object *obj,
543 ELM_BOX_DATA_GET(obj, sd);
545 elm_widget_sub_object_add(obj, subobj);
546 evas_object_box_insert_after
547 (ELM_WIDGET_DATA(sd)->resize_obj, subobj, after);
551 elm_box_clear(Evas_Object *obj)
554 ELM_BOX_DATA_GET(obj, sd);
556 /* EINA_TRUE means to delete objects as well */
557 evas_object_box_remove_all(ELM_WIDGET_DATA(sd)->resize_obj, EINA_TRUE);
561 elm_box_unpack(Evas_Object *obj,
565 ELM_BOX_DATA_GET(obj, sd);
567 if (evas_object_box_remove(ELM_WIDGET_DATA(sd)->resize_obj, subobj))
568 elm_widget_sub_object_del(obj, subobj);
572 elm_box_unpack_all(Evas_Object *obj)
574 Evas_Object_Box_Data *bd;
575 Evas_Object_Box_Option *opt;
579 ELM_BOX_DATA_GET(obj, sd);
581 bd = evas_object_smart_data_get(ELM_WIDGET_DATA(sd)->resize_obj);
582 EINA_LIST_FOREACH(bd->children, l, opt)
583 elm_widget_sub_object_del(obj, opt->obj);
585 /* EINA_FALSE means to delete objects as well */
586 evas_object_box_remove_all(ELM_WIDGET_DATA(sd)->resize_obj, EINA_FALSE);
590 elm_box_layout_set(Evas_Object *obj,
591 Evas_Object_Box_Layout cb,
596 ELM_BOX_DATA_GET(obj, sd);
599 evas_object_box_layout_set
600 (ELM_WIDGET_DATA(sd)->resize_obj, cb, data, free_data);
602 evas_object_box_layout_set
603 (ELM_WIDGET_DATA(sd)->resize_obj, _elm_box_custom_layout, obj, NULL);
607 elm_box_layout_transition(Evas_Object *obj,
608 Evas_Object_Box_Data *priv,
611 Elm_Box_Transition *box_data = data;
612 const double curtime = ecore_loop_time_get();
614 if (box_data->animation_ended)
616 box_data->end.layout(obj, priv, box_data->end.data);
620 if (!box_data->animator)
622 if (!_transition_layout_animation_start(obj, priv, box_data,
623 _transition_animation))
628 if (box_data->recalculate)
630 _transition_layout_calculate_coords(obj, priv, box_data);
631 box_data->recalculate = EINA_FALSE;
635 if ((curtime >= box_data->duration + box_data->initial_time))
636 _transition_layout_animation_stop(box_data);
638 _transition_layout_animation_exec(obj, priv, box_data, curtime);
641 EAPI Elm_Box_Transition *
642 elm_box_transition_new(const double duration,
643 Evas_Object_Box_Layout start_layout,
644 void *start_layout_data,
645 Ecore_Cb start_layout_free_data,
646 Evas_Object_Box_Layout end_layout,
647 void *end_layout_data,
648 Ecore_Cb end_layout_free_data,
649 Ecore_Cb transition_end_cb,
650 void *transition_end_data)
652 Elm_Box_Transition *box_data;
654 EINA_SAFETY_ON_NULL_RETURN_VAL(start_layout, NULL);
655 EINA_SAFETY_ON_NULL_RETURN_VAL(end_layout, NULL);
657 box_data = calloc(1, sizeof(Elm_Box_Transition));
658 if (!box_data) return NULL;
660 box_data->start.layout = start_layout;
661 box_data->start.data = start_layout_data;
662 box_data->start.free_data = start_layout_free_data;
663 box_data->end.layout = end_layout;
664 box_data->end.data = end_layout_data;
665 box_data->end.free_data = end_layout_free_data;
666 box_data->duration = duration;
667 box_data->transition_end_cb = transition_end_cb;
668 box_data->transition_end_data = transition_end_data;
674 elm_box_transition_free(void *data)
676 EINA_SAFETY_ON_NULL_RETURN(data);
678 Transition_Animation_Data *tad;
679 Elm_Box_Transition *box_data = data;
680 if ((box_data->start.free_data) && (box_data->start.data))
681 box_data->start.free_data(box_data->start.data);
682 if ((box_data->end.free_data) && (box_data->end.data))
683 box_data->end.free_data(box_data->end.data);
684 EINA_LIST_FREE (box_data->objs, tad)
687 evas_object_event_callback_del
688 (box_data->box, EVAS_CALLBACK_RESIZE, _transition_layout_obj_resize_cb);
689 evas_object_smart_callback_del
690 (box_data->box, SIG_CHILD_ADDED, _transition_layout_child_added);
691 evas_object_smart_callback_del
692 (box_data->box, SIG_CHILD_REMOVED, _transition_layout_child_removed);
693 if (box_data->animator)
695 ecore_animator_del(box_data->animator);
696 box_data->animator = NULL;
703 elm_box_children_get(const Evas_Object *obj)
705 ELM_BOX_CHECK(obj) NULL;
706 ELM_BOX_DATA_GET(obj, sd);
708 return evas_object_box_children_get(ELM_WIDGET_DATA(sd)->resize_obj);
712 elm_box_padding_set(Evas_Object *obj,
713 Evas_Coord horizontal,
717 ELM_BOX_DATA_GET(obj, sd);
719 evas_object_box_padding_set
720 (ELM_WIDGET_DATA(sd)->resize_obj, horizontal, vertical);
724 elm_box_padding_get(const Evas_Object *obj,
725 Evas_Coord *horizontal,
726 Evas_Coord *vertical)
729 ELM_BOX_DATA_GET(obj, sd);
731 evas_object_box_padding_get
732 (ELM_WIDGET_DATA(sd)->resize_obj, horizontal, vertical);
736 elm_box_align_set(Evas_Object *obj,
741 ELM_BOX_DATA_GET(obj, sd);
743 evas_object_size_hint_align_set
744 (ELM_WIDGET_DATA(sd)->resize_obj, horizontal, vertical);
748 elm_box_align_get(const Evas_Object *obj,
753 ELM_BOX_DATA_GET(obj, sd);
755 evas_object_size_hint_align_get
756 (ELM_WIDGET_DATA(sd)->resize_obj, horizontal, vertical);
760 elm_box_recalculate(Evas_Object *obj)
763 ELM_BOX_DATA_GET(obj, sd);
765 if (sd->recalc) return;
767 evas_object_smart_need_recalculate_set
768 (ELM_WIDGET_DATA(sd)->resize_obj, EINA_TRUE);
770 evas_object_smart_calculate(ELM_WIDGET_DATA(sd)->resize_obj);