move elementary to trunk base. out of TMP/st.
[framework/uifw/elementary.git] / src / lib / elm_layout.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Layout Layout
6  *
7  * This takes a standard Edje design file and wraps it very thinly
8  * in a widget and handles swallowing widgets into swallow regions
9  * in the Edje object, allowing Edje to be used as a design and
10  * layout tool
11  */
12
13 typedef struct _Widget_Data Widget_Data;
14 typedef struct _Subinfo Subinfo;
15 typedef struct _Part_Cursor Part_Cursor;
16
17 struct _Widget_Data
18 {
19    Evas_Object *obj;
20    Evas_Object *lay;
21    Eina_List *subs;
22    Eina_List *parts_cursors;
23    Eina_Bool needs_size_calc:1;
24 };
25
26 struct _Subinfo
27 {
28    const char *part;
29    Evas_Object *obj;
30    enum {
31      SWALLOW,
32      BOX_APPEND,
33      BOX_PREPEND,
34      BOX_INSERT_BEFORE,
35      BOX_INSERT_AT,
36      TABLE_PACK,
37      TEXT
38    } type;
39    union {
40       union {
41          const Evas_Object *reference;
42          unsigned int pos;
43       } box;
44       struct {
45          unsigned short col, row, colspan, rowspan;
46       } table;
47       struct {
48          const char *text;
49       } text;
50    } p;
51 };
52
53 struct _Part_Cursor
54 {
55    Evas_Object *obj;
56    const char *part;
57    const char *cursor;
58    const char *style;
59    Eina_Bool engine_only:1;
60 };
61
62 static const char *widtype = NULL;
63 static void _del_hook(Evas_Object *obj);
64 static void _theme_hook(Evas_Object *obj);
65 static void _sizing_eval(Widget_Data *wd);
66 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
67 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
68 static void _part_cursor_free(Part_Cursor *pc);
69
70 static void
71 _del_hook(Evas_Object *obj)
72 {
73    Widget_Data *wd = elm_widget_data_get(obj);
74    Subinfo *si;
75    Part_Cursor *pc;
76
77    if (!wd) return;
78    EINA_LIST_FREE(wd->subs, si)
79      {
80         eina_stringshare_del(si->part);
81         if (si->type == TEXT)
82           eina_stringshare_del(si->p.text.text);
83         free(si);
84      }
85    EINA_LIST_FREE(wd->parts_cursors, pc) _part_cursor_free(pc);
86    free(wd);
87 }
88
89 static void
90 _theme_hook(Evas_Object *obj)
91 {
92    Widget_Data *wd = elm_widget_data_get(obj);
93    if (!wd) return;
94    edje_object_scale_set(wd->lay, elm_widget_scale_get(obj) *
95                          _elm_config->scale);
96    _sizing_eval(wd);
97 }
98
99 static void
100 _changed_hook(Evas_Object *obj)
101 {
102    Widget_Data *wd = elm_widget_data_get(obj);
103    if (!wd) return;
104    if (wd->needs_size_calc)
105      {
106         _sizing_eval(wd);
107         wd->needs_size_calc = 0;
108      }
109 }
110
111 static void
112 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
113 {
114    Widget_Data *wd = elm_widget_data_get(obj);
115    edje_object_signal_emit(wd->lay, emission, source);
116 }
117
118 static void
119 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
120 {
121    Widget_Data *wd = elm_widget_data_get(obj);
122    edje_object_signal_callback_add(wd->lay, emission, source, func_cb, data);
123 }
124
125 static void
126 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
127 {
128    Widget_Data *wd = elm_widget_data_get(obj);
129    edje_object_signal_callback_del_full(wd->lay, emission, source, func_cb,
130                                         data);
131 }
132
133
134 static void *
135 _elm_layout_list_data_get(const Eina_List *list)
136 {
137    Subinfo *si = eina_list_data_get(list);
138    return si->obj;
139 }
140
141 static Eina_Bool
142 _elm_layout_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
143 {
144    Widget_Data *wd = elm_widget_data_get(obj);
145    const Eina_List *items;
146    void *(*list_data_get) (const Eina_List *list);
147
148    if ((!wd) || (!wd->subs))
149      return EINA_FALSE;
150
151    /* Focus chain (This block is diferent of elm_win cycle)*/
152    if ((items = elm_widget_focus_custom_chain_get(obj)))
153      list_data_get = eina_list_data_get;
154    else
155      {
156         items = wd->subs;
157         list_data_get = _elm_layout_list_data_get;
158
159         if (!items) return EINA_FALSE;
160      }
161
162    return elm_widget_focus_list_next_get(obj, items, list_data_get, dir,
163                                           next);
164 }
165
166 static void
167 _sizing_eval(Widget_Data *wd)
168 {
169    Evas_Coord minw = -1, minh = -1;
170    edje_object_size_min_calc(wd->lay, &minw, &minh);
171    evas_object_size_hint_min_set(wd->obj, minw, minh);
172    evas_object_size_hint_max_set(wd->obj, -1, -1);
173 }
174
175 static void
176 _request_sizing_eval(Widget_Data *wd)
177 {
178    if (wd->needs_size_calc) return;
179    wd->needs_size_calc = 1;
180    evas_object_smart_changed(wd->obj);
181 }
182
183 static void
184 _part_cursor_free(Part_Cursor *pc)
185 {
186    eina_stringshare_del(pc->part);
187    eina_stringshare_del(pc->style);
188    eina_stringshare_del(pc->cursor);
189    free(pc);
190 }
191
192 static void
193 _part_cursor_part_apply(const Part_Cursor *pc)
194 {
195    elm_object_cursor_set(pc->obj, pc->cursor);
196    elm_object_cursor_style_set(pc->obj, pc->style);
197    elm_object_cursor_engine_only_set(pc->obj, pc->engine_only);
198 }
199
200 static Part_Cursor *
201 _parts_cursors_find(Widget_Data *wd, const char *part)
202 {
203    const Eina_List *l;
204    Part_Cursor *pc;
205    EINA_LIST_FOREACH(wd->parts_cursors, l, pc)
206      {
207         if (!strcmp(pc->part, part))
208           return pc;
209      }
210    return NULL;
211 }
212
213 static void
214 _parts_cursors_apply(Widget_Data *wd)
215 {
216    const char *file, *group;
217    const Eina_List *l;
218    Part_Cursor *pc;
219
220    edje_object_file_get(wd->lay, &file, &group);
221
222    EINA_LIST_FOREACH(wd->parts_cursors, l, pc)
223      {
224         Evas_Object *obj = (Evas_Object *)edje_object_part_object_get
225           (wd->lay, pc->part);
226
227         if (!obj)
228           {
229              pc->obj = NULL;
230              WRN("no part '%s' in group '%s' of file '%s'. "
231                  "Cannot set cursor '%s'",
232                  pc->part, group, file, pc->cursor);
233              continue;
234           }
235         else if (evas_object_pass_events_get(obj))
236           {
237              pc->obj = NULL;
238              WRN("part '%s' in group '%s' of file '%s' has mouse_events: 0. "
239                  "Cannot set cursor '%s'",
240                  pc->part, group, file, pc->cursor);
241              continue;
242           }
243
244         pc->obj = obj;
245         _part_cursor_part_apply(pc);
246      }
247 }
248
249 static void
250 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
251 {
252    _request_sizing_eval(data);
253 }
254
255 static void
256 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
257 {
258    Widget_Data *wd = elm_widget_data_get(obj);
259    Evas_Object *sub = event_info;
260    Eina_List *l;
261    Subinfo *si;
262    if (!wd) return;
263    EINA_LIST_FOREACH(wd->subs, l, si)
264      {
265         if (si->obj == sub)
266           {
267              evas_object_event_callback_del_full(sub,
268                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
269                                             _changed_size_hints,
270                                             wd);
271              wd->subs = eina_list_remove_list(wd->subs, l);
272              eina_stringshare_del(si->part);
273              free(si);
274              break;
275           }
276      }
277 }
278
279 static void
280 _signal_size_eval(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
281 {
282    _request_sizing_eval(data);
283 }
284
285 static void
286 _parts_text_fix(Widget_Data *wd)
287 {
288    const Eina_List *l;
289    Subinfo *si;
290
291    EINA_LIST_FOREACH(wd->subs, l, si)
292      {
293         if (si->type == TEXT)
294           edje_object_part_text_set(wd->lay, si->part, si->p.text.text);
295      }
296 }
297
298 /**
299  * Add a new layout to the parent
300  *
301  * @param parent The parent object
302  * @return The new object or NULL if it cannot be created
303  *
304  * @ingroup Layout
305  */
306 EAPI Evas_Object *
307 elm_layout_add(Evas_Object *parent)
308 {
309    Evas_Object *obj;
310    Evas *e;
311    Widget_Data *wd;
312
313    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
314
315    wd = ELM_NEW(Widget_Data);
316    e = evas_object_evas_get(parent);
317    if (!e) return NULL;
318    wd->obj = obj = elm_widget_add(e);
319    ELM_SET_WIDTYPE(widtype, "layout");
320    elm_widget_type_set(obj, "layout");
321    elm_widget_sub_object_add(parent, obj);
322    elm_widget_data_set(obj, wd);
323    elm_widget_del_hook_set(obj, _del_hook);
324    elm_widget_theme_hook_set(obj, _theme_hook);
325    elm_widget_changed_hook_set(obj, _changed_hook);
326    elm_widget_can_focus_set(obj, EINA_FALSE);
327    elm_widget_focus_next_hook_set(obj, _elm_layout_focus_next_hook);
328    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
329    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
330    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
331
332    wd->lay = edje_object_add(e);
333    elm_widget_resize_object_set(obj, wd->lay);
334    edje_object_signal_callback_add(wd->lay, "size,eval", "elm",
335                                    _signal_size_eval, wd);
336    
337    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
338
339    _request_sizing_eval(wd);
340    return obj;
341 }
342
343 /**
344  * Set the file that will be used as layout
345  *
346  * @param obj The layout object
347  * @param file The path to file (edj) that will be used as layout
348  * @param group The group that the layout belongs in edje file
349  *
350  * @return (1 = success, 0 = error)
351  *
352  * @ingroup Layout
353  */
354 EAPI Eina_Bool
355 elm_layout_file_set(Evas_Object *obj, const char *file, const char *group)
356 {
357    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
358    Widget_Data *wd = elm_widget_data_get(obj);
359    if (!wd) return EINA_FALSE;
360    Eina_Bool ret = edje_object_file_set(wd->lay, file, group);
361    if (ret)
362      {
363         _parts_text_fix(wd);
364         _request_sizing_eval(wd);
365         _parts_cursors_apply(wd);
366      }
367    else DBG("failed to set edje file '%s', group '%s': %s",
368             file, group,
369             edje_load_error_str(edje_object_load_error_get(wd->lay)));
370    return ret;
371 }
372
373 /**
374  * Set the edje group from the elementary theme that will be used as layout
375  *
376  * @param obj The layout object
377  * @param clas the clas of the group
378  * @param group the group
379  * @param style the style to used
380  *
381  * @return (1 = success, 0 = error)
382  *
383  * @ingroup Layout
384  */
385 EAPI Eina_Bool
386 elm_layout_theme_set(Evas_Object *obj, const char *clas, const char *group, const char *style)
387 {
388    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
389    Widget_Data *wd = elm_widget_data_get(obj);
390    if (!wd) return EINA_FALSE;
391    Eina_Bool ret = _elm_theme_object_set(obj, wd->lay, clas, group, style);
392    if (ret)
393      {
394         _parts_text_fix(wd);
395         _request_sizing_eval(wd);
396         _parts_cursors_apply(wd);
397      }
398    return ret;
399 }
400
401 /**
402  * Set the layout content
403  *
404  * Once the content object is set, a previously set one will be deleted.
405  * If you want to keep that old content object, use the
406  * elm_layout_content_unset() function.
407  *
408  * @param obj The layout object
409  * @param swallow The swallow group name in the edje file
410  * @param content The content will be filled in this layout object
411  *
412  * @ingroup Layout
413  */
414 EAPI void
415 elm_layout_content_set(Evas_Object *obj, const char *swallow, Evas_Object *content)
416 {
417    ELM_CHECK_WIDTYPE(obj, widtype);
418    Widget_Data *wd = elm_widget_data_get(obj);
419    Subinfo *si;
420    const Eina_List *l;
421    if (!wd) return;
422    EINA_LIST_FOREACH(wd->subs, l, si)
423      {
424         if ((si->type == SWALLOW) && (!strcmp(swallow, si->part)))
425           {
426              if (content == si->obj) return;
427              evas_object_del(si->obj);
428              break;
429           }
430      }
431    if (content)
432      {
433         elm_widget_sub_object_add(obj, content);
434         evas_object_event_callback_add(content,
435                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
436                                        _changed_size_hints, wd);
437         if (!edje_object_part_swallow(wd->lay, swallow, content))
438           WRN("could not swallow %p into part '%s'", content, swallow);
439         si = ELM_NEW(Subinfo);
440         si->type = SWALLOW;
441         si->part = eina_stringshare_add(swallow);
442         si->obj = content;
443         wd->subs = eina_list_append(wd->subs, si);
444      }
445    _request_sizing_eval(wd);
446 }
447
448 /**
449  * Get the swallowed object in the given part
450  *
451  * @param obj The layout object
452  * @param swallow The SWALLOW part to get its content
453  *
454  * @return The swallowed object or NULL if none or an error occurred
455  *
456  * @ingroup Layout
457  */
458 EAPI const Evas_Object *
459 elm_layout_content_get(const Evas_Object *obj, const char *swallow)
460 {
461    Widget_Data *wd = elm_widget_data_get(obj);
462    const Eina_List *l;
463    Subinfo *si;
464    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
465
466    EINA_LIST_FOREACH(wd->subs, l, si)
467      {
468         if ((si->type == SWALLOW) && !strcmp(swallow, si->part))
469           return si->obj;
470      }
471    return NULL;
472 }
473
474 /**
475  * Unset the layout content
476  *
477  * Unparent and return the content object which was set for this widget
478  *
479  * @param obj The layout object
480  * @param swallow The swallow group name in the edje file
481  * @return The content that was being used
482  *
483  * @ingroup Layout
484  */
485 EAPI Evas_Object *
486 elm_layout_content_unset(Evas_Object *obj, const char *swallow)
487 {
488    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
489    Widget_Data *wd = elm_widget_data_get(obj);
490    Subinfo *si;
491    const Eina_List *l;
492    if (!wd) return NULL;
493    EINA_LIST_FOREACH(wd->subs, l, si)
494      {
495         if ((si->type == SWALLOW) && (!strcmp(swallow, si->part)))
496           {
497              Evas_Object *content;
498              if (!si->obj) return NULL;
499              content = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
500              elm_widget_sub_object_del(obj, content);
501              edje_object_part_unswallow(wd->lay, content);
502              return content;
503           }
504      }
505    return NULL;
506 }
507
508 /**
509  * Set the text of the given part
510  *
511  * @param obj The layout object
512  * @param part The TEXT part where to set the text
513  * @param text The text to set
514  *
515  * @ingroup Layout
516  */
517 EAPI void
518 elm_layout_text_set(Evas_Object *obj, const char *part, const char *text)
519 {
520    Widget_Data *wd = elm_widget_data_get(obj);
521    Subinfo *si = NULL;
522    Eina_List *l;
523    ELM_CHECK_WIDTYPE(obj, widtype);
524
525    EINA_LIST_FOREACH(wd->subs, l, si)
526      {
527         if ((si->type == TEXT) && (!strcmp(part, si->part)))
528           {
529              if (!text)
530                {
531                   eina_stringshare_del(si->part);
532                   eina_stringshare_del(si->p.text.text);
533                   free(si);
534                   edje_object_part_text_set(wd->lay, part, NULL);
535                   wd->subs = eina_list_remove_list(wd->subs, l);
536                   return;
537                }
538              else
539                break;
540           }
541         si = NULL;
542      }
543
544    if (!si)
545      {
546         si = ELM_NEW(Subinfo);
547         if (!si) return;
548         si->type = TEXT;
549         si->part = eina_stringshare_add(part);
550         wd->subs = eina_list_append(wd->subs, si);
551      }
552
553    eina_stringshare_replace(&si->p.text.text, text);
554    edje_object_part_text_set(wd->lay, part, text);
555    _request_sizing_eval(wd);
556 }
557
558 /**
559  * Get the text set in the given part
560  *
561  * @param obj The layout object
562  * @param part The TEXT part to retrieve the text off
563  *
564  * @return The text set in @p part
565  *
566  * @ingroup Layout
567  */
568 EAPI const char *
569 elm_layout_text_get(const Evas_Object *obj, const char *part)
570 {
571    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
572    Widget_Data *wd = elm_widget_data_get(obj);
573    return edje_object_part_text_get(wd->lay, part);
574 }
575
576 /**
577  * Append child to layout box part.
578  *
579  * Once the object is appended, its lifetime will be bound to the
580  * layout, whenever the layout dies the child will be deleted
581  * automatically. One should use elm_layout_box_remove() to make this
582  * layout forget about the object.
583  *
584  * @param obj the layout object
585  * @param part the box part to append.
586  * @param child the child object to append to box.
587  *
588  * @ingroup Layout
589  */
590 EAPI void
591 elm_layout_box_append(Evas_Object *obj, const char *part, Evas_Object *child)
592 {
593    ELM_CHECK_WIDTYPE(obj, widtype);
594    Widget_Data *wd = elm_widget_data_get(obj);
595    Subinfo *si;
596    if (!wd) return;
597
598    if (!edje_object_part_box_append(wd->lay, part, child))
599      WRN("child %p could not be appended to box part '%s'", child, part);
600    elm_widget_sub_object_add(obj, child);
601    evas_object_event_callback_add
602      (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
603
604    si = ELM_NEW(Subinfo);
605    si->type = BOX_APPEND;
606    si->part = eina_stringshare_add(part);
607    si->obj = child;
608    wd->subs = eina_list_append(wd->subs, si);
609    _request_sizing_eval(wd);
610 }
611
612 /**
613  * Prepend child to layout box part.
614  *
615  * Once the object is prepended, its lifetime will be bound to the
616  * layout, whenever the layout dies the child will be deleted
617  * automatically. One should use elm_layout_box_remove() to make this
618  * layout forget about the object.
619  *
620  * @param obj the layout object
621  * @param part the box part to prepend.
622  * @param child the child object to prepend to box.
623  *
624  * @ingroup Layout
625  */
626 EAPI void
627 elm_layout_box_prepend(Evas_Object *obj, const char *part, Evas_Object *child)
628 {
629    ELM_CHECK_WIDTYPE(obj, widtype);
630    Widget_Data *wd = elm_widget_data_get(obj);
631    Subinfo *si;
632    if (!wd) return;
633
634    if (!edje_object_part_box_prepend(wd->lay, part, child))
635      WRN("child %p could not be prepended to box part '%s'", child, part);
636    elm_widget_sub_object_add(obj, child);
637    evas_object_event_callback_add
638      (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
639
640    si = ELM_NEW(Subinfo);
641    si->type = BOX_PREPEND;
642    si->part = eina_stringshare_add(part);
643    si->obj = child;
644    wd->subs = eina_list_prepend(wd->subs, si);
645    _request_sizing_eval(wd);
646 }
647
648 static void
649 _box_reference_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
650 {
651    Subinfo *si = data;
652    si->p.box.reference = NULL;
653 }
654
655 /**
656  * Insert child to layout box part before a reference object.
657  *
658  * Once the object is inserted, its lifetime will be bound to the
659  * layout, whenever the layout dies the child will be deleted
660  * automatically. One should use elm_layout_box_remove() to make this
661  * layout forget about the object.
662  *
663  * @param obj the layout object
664  * @param part the box part to insert.
665  * @param child the child object to insert into box.
666  * @param reference another reference object to insert before in box.
667  *
668  * @ingroup Layout
669  */
670 EAPI void
671 elm_layout_box_insert_before(Evas_Object *obj, const char *part, Evas_Object *child, const Evas_Object *reference)
672 {
673    ELM_CHECK_WIDTYPE(obj, widtype);
674    Widget_Data *wd = elm_widget_data_get(obj);
675    Subinfo *si;
676    if (!wd) return;
677
678    if (!edje_object_part_box_insert_before(wd->lay, part, child, reference))
679      WRN("child %p could not be inserted before %p inf box part '%s'",
680          child, reference, part);
681
682    si = ELM_NEW(Subinfo);
683    si->type = BOX_INSERT_BEFORE;
684    si->part = eina_stringshare_add(part);
685    si->obj = child;
686    si->p.box.reference = reference;
687
688    elm_widget_sub_object_add(obj, child);
689    evas_object_event_callback_add
690      (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
691    evas_object_event_callback_add
692      ((Evas_Object *)reference, EVAS_CALLBACK_DEL, _box_reference_del, si);
693
694    wd->subs = eina_list_append(wd->subs, si);
695    _request_sizing_eval(wd);
696 }
697
698 /**
699  * Insert child to layout box part at a given position.
700  *
701  * Once the object is inserted, its lifetime will be bound to the
702  * layout, whenever the layout dies the child will be deleted
703  * automatically. One should use elm_layout_box_remove() to make this
704  * layout forget about the object.
705  *
706  * @param obj the layout object
707  * @param part the box part to insert.
708  * @param child the child object to insert into box.
709  * @param pos the numeric position >=0 to insert the child.
710  *
711  * @ingroup Layout
712  */
713 EAPI void
714 elm_layout_box_insert_at(Evas_Object *obj, const char *part, Evas_Object *child, unsigned int pos)
715 {
716    ELM_CHECK_WIDTYPE(obj, widtype);
717    Widget_Data *wd = elm_widget_data_get(obj);
718    Subinfo *si;
719    if (!wd) return;
720
721    if (!edje_object_part_box_insert_at(wd->lay, part, child, pos))
722      WRN("child %p could not be inserted at %u to box part '%s'",
723          child, pos, part);
724
725    elm_widget_sub_object_add(obj, child);
726    evas_object_event_callback_add
727      (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
728
729    si = ELM_NEW(Subinfo);
730    si->type = BOX_INSERT_AT;
731    si->part = eina_stringshare_add(part);
732    si->obj = child;
733    si->p.box.pos = pos;
734    wd->subs = eina_list_append(wd->subs, si);
735    _request_sizing_eval(wd);
736 }
737
738 static Evas_Object *
739 _sub_box_remove(Widget_Data *wd, Subinfo *si)
740 {
741    Evas_Object *child;
742
743    if (si->type == BOX_INSERT_BEFORE)
744      evas_object_event_callback_del_full
745        ((Evas_Object *)si->p.box.reference,
746         EVAS_CALLBACK_DEL, _box_reference_del, si);
747
748    child = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
749    edje_object_part_box_remove(wd->lay, si->part, child);
750    elm_widget_sub_object_del(wd->obj, child);
751    return child;
752 }
753
754 static Evas_Object *
755 _sub_table_remove(Widget_Data *wd, Subinfo *si)
756 {
757    Evas_Object *child;
758
759    child = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
760    edje_object_part_table_unpack(wd->lay, si->part, child);
761    elm_widget_sub_object_del(wd->obj, child);
762    return child;
763 }
764
765 static Eina_Bool
766 _sub_box_is(const Subinfo *si)
767 {
768    switch (si->type)
769      {
770       case BOX_APPEND:
771       case BOX_PREPEND:
772       case BOX_INSERT_BEFORE:
773       case BOX_INSERT_AT:
774          return EINA_TRUE;
775       default:
776          return EINA_FALSE;
777      }
778 }
779
780 /**
781  * Remove a child of the given part box.
782  *
783  * The object will be removed from the box part and its lifetime will
784  * not be handled by the layout anymore. This is equivalent to
785  * elm_layout_content_unset() for box.
786  *
787  * @param obj The layout object
788  * @param part The box part name to remove child.
789  * @param child The object to remove from box.
790  * @return The object that was being used, or NULL if not found.
791  *
792  * @ingroup Layout
793  */
794 EAPI Evas_Object *
795 elm_layout_box_remove(Evas_Object *obj, const char *part, Evas_Object *child)
796 {
797    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
798    Widget_Data *wd = elm_widget_data_get(obj);
799    const Eina_List *l;
800    Subinfo *si;
801
802    if (!wd) return NULL;
803
804    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
805    EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
806    EINA_LIST_FOREACH(wd->subs, l, si)
807      {
808         if (!_sub_box_is(si)) continue;
809         if ((si->obj == child) && (!strcmp(si->part, part)))
810           return _sub_box_remove(wd, si);
811      }
812    return NULL;
813 }
814
815 /**
816  * Remove all child of the given part box.
817  *
818  * The objects will be removed from the box part and their lifetime will
819  * not be handled by the layout anymore. This is equivalent to
820  * elm_layout_content_unset() for all box children.
821  *
822  * @param obj The layout object
823  * @param part The box part name to remove child.
824  * @param clear If EINA_TRUE, then all objects will be deleted as
825  *        well, otherwise they will just be removed and will be
826  *        dangling on the canvas.
827  *
828  * @ingroup Layout
829  */
830 EAPI void
831 elm_layout_box_remove_all(Evas_Object *obj, const char *part, Eina_Bool clear)
832 {
833    ELM_CHECK_WIDTYPE(obj, widtype);
834    Widget_Data *wd = elm_widget_data_get(obj);
835    Subinfo *si;
836    Eina_List *lst;
837
838    if (!wd) return;
839    EINA_SAFETY_ON_NULL_RETURN(part);
840
841    lst = eina_list_clone(wd->subs);
842    EINA_LIST_FREE(lst, si)
843      {
844         if (!_sub_box_is(si)) continue;
845         if (!strcmp(si->part, part))
846           {
847              Evas_Object *child = _sub_box_remove(wd, si);
848              if ((clear) && (child)) evas_object_del(child);
849           }
850      }
851    /* eventually something may not be added with layout, del them as well */
852    edje_object_part_box_remove_all(wd->lay, part, clear);
853 }
854
855 /**
856  * Insert child to layout table part.
857  *
858  * Once the object is inserted, its lifetime will be bound to the
859  * layout, whenever the layout dies the child will be deleted
860  * automatically. One should use elm_layout_box_remove() to make this
861  * layout forget about the object.
862  *
863  * @param obj the layout object
864  * @param part the box part to pack child.
865  * @param child the child object to pack into table.
866  * @param reference another reference object to insert before in box.
867  *
868  * @ingroup Layout
869  */
870 EAPI void
871 elm_layout_table_pack(Evas_Object *obj, const char *part, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
872 {
873    ELM_CHECK_WIDTYPE(obj, widtype);
874    Widget_Data *wd = elm_widget_data_get(obj);
875    Subinfo *si;
876    if (!wd) return;
877
878    if (!edje_object_part_table_pack
879        (wd->lay, part, child, col, row, colspan, rowspan))
880      WRN("child %p could not be packed into box part '%s' col=%uh, row=%hu, "
881          "colspan=%hu, rowspan=%hu", child, part, col, row, colspan, rowspan);
882
883    elm_widget_sub_object_add(obj, child);
884    evas_object_event_callback_add
885      (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
886
887    si = ELM_NEW(Subinfo);
888    si->type = TABLE_PACK;
889    si->part = eina_stringshare_add(part);
890    si->obj = child;
891    si->p.table.col = col;
892    si->p.table.row = row;
893    si->p.table.colspan = colspan;
894    si->p.table.rowspan = rowspan;
895    wd->subs = eina_list_append(wd->subs, si);
896    _request_sizing_eval(wd);
897 }
898
899 /**
900  * Unpack (remove) a child of the given part table.
901  *
902  * The object will be unpacked from the table part and its lifetime
903  * will not be handled by the layout anymore. This is equivalent to
904  * elm_layout_content_unset() for table.
905  *
906  * @param obj The layout object
907  * @param part The table part name to remove child.
908  * @param child The object to remove from table.
909  * @return The object that was being used, or NULL if not found.
910  *
911  * @ingroup Layout
912  */
913 EAPI Evas_Object *
914 elm_layout_table_unpack(Evas_Object *obj, const char *part, Evas_Object *child)
915 {
916    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
917    Widget_Data *wd = elm_widget_data_get(obj);
918    const Eina_List *l;
919    Subinfo *si;
920
921    if (!wd) return NULL;
922
923    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
924    EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
925    EINA_LIST_FOREACH(wd->subs, l, si)
926      {
927         if (si->type != TABLE_PACK) continue;
928         if ((si->obj == child) && (!strcmp(si->part, part)))
929           return _sub_table_remove(wd, si);
930      }
931    return NULL;
932 }
933
934 /**
935  * Remove all child of the given part table.
936  *
937  * The objects will be removed from the table part and their lifetime will
938  * not be handled by the layout anymore. This is equivalent to
939  * elm_layout_content_unset() for all table children.
940  *
941  * @param obj The layout object
942  * @param part The table part name to remove child.
943  * @param clear If EINA_TRUE, then all objects will be deleted as
944  *        well, otherwise they will just be removed and will be
945  *        dangling on the canvas.
946  *
947  * @ingroup Layout
948  */
949 EAPI void
950 elm_layout_table_clear(Evas_Object *obj, const char *part, Eina_Bool clear)
951 {
952    ELM_CHECK_WIDTYPE(obj, widtype);
953    Widget_Data *wd = elm_widget_data_get(obj);
954    Subinfo *si;
955    Eina_List *lst;
956
957    if (!wd) return;
958    EINA_SAFETY_ON_NULL_RETURN(part);
959
960    lst = eina_list_clone(wd->subs);
961    EINA_LIST_FREE(lst, si)
962      {
963         if (si->type != TABLE_PACK) continue;
964         if (!strcmp(si->part, part))
965           {
966              Evas_Object *child = _sub_table_remove(wd, si);
967              if ((clear) && (child)) evas_object_del(child);
968           }
969      }
970    /* eventually something may not be added with layout, del them as well */
971    edje_object_part_table_clear(wd->lay, part, clear);
972 }
973
974 /**
975  * Get the edje layout
976  *
977  * @param obj The layout object
978  * 
979  * This returns the edje object. It is not expected to be used to then swallow
980  * objects via edje_object_part_swallow() for example. Use 
981  * elm_layout_content_set() instead so child object handling and sizing is
982  * done properly. This is more intended for setting text, emitting signals,
983  * hooking to signal callbacks etc.
984  *
985  * @return A Evas_Object with the edje layout settings loaded
986  * with function elm_layout_file_set
987  *
988  * @ingroup Layout
989  */
990 EAPI Evas_Object *
991 elm_layout_edje_get(const Evas_Object *obj)
992 {
993    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
994    Widget_Data *wd = elm_widget_data_get(obj);
995    if (!wd) return NULL;
996    return wd->lay;
997 }
998
999 /**
1000  * Get the edje data of the given layout
1001  *
1002  * @param obj The layout object
1003  * @param key The data key
1004  *
1005  * @return The edje data string
1006  *
1007  * This function fetches data specified at the object level.
1008  * This function return NULL if data is not found.
1009  *
1010  * In EDC this comes from a data block within the group block that @a
1011  * obj was loaded from. E.g.
1012  *
1013  * @code
1014  * collections {
1015  *   group {
1016  *     name: "a_group";
1017  *     data {
1018  *       item: "key1" "value1";
1019  *       item: "key2" "value2";
1020  *     }
1021  *   }
1022  * }
1023  * @endcode
1024  *
1025  * @ingroup Layout
1026  */
1027 EAPI const char *
1028 elm_layout_data_get(const Evas_Object *obj, const char *key)
1029 {
1030    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1031    Widget_Data *wd = elm_widget_data_get(obj);
1032    return edje_object_data_get(wd->lay, key);
1033 }
1034
1035 /**
1036  * Eval sizing
1037  *
1038  * Manually forms a sizing re-evaluation when contents changed state so that
1039  * minimum size might have changed and needs re-evaluation. Also note that
1040  * a standard signal of "size,eval" "elm" emitted by the edje object will
1041  * cause this to happen too
1042  *
1043  * @param obj The layout object
1044  *
1045  * @ingroup Layout
1046  */
1047 EAPI void
1048 elm_layout_sizing_eval(Evas_Object *obj)
1049 {
1050    ELM_CHECK_WIDTYPE(obj, widtype);
1051    Widget_Data *wd = elm_widget_data_get(obj);
1052    EINA_SAFETY_ON_NULL_RETURN(wd);
1053    _request_sizing_eval(wd);
1054 }
1055
1056 /**
1057  * Sets a specific cursor for an edje part.
1058  *
1059  * @param obj The layout object.
1060  * @param part_name a part from loaded edje group.
1061  * @param cursor cursor name to use, see Elementary_Cursor.h
1062  *
1063  * @return EINA_TRUE on success or EINA_FALSE on failure, that may be
1064  *         part not exists or it has "mouse_events: 0".
1065  *
1066  * @ingroup Layout
1067  */
1068 EAPI Eina_Bool
1069 elm_layout_part_cursor_set(Evas_Object *obj, const char *part_name, const char *cursor)
1070 {
1071    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1072    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1073    Widget_Data *wd = elm_widget_data_get(obj);
1074    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
1075    Evas_Object *part_obj;
1076    Part_Cursor *pc;
1077
1078    part_obj = (Evas_Object *)edje_object_part_object_get(wd->lay, part_name);
1079    if (!part_obj)
1080      {
1081         const char *group, *file;
1082         edje_object_file_get(wd->lay, &file, &group);
1083         WRN("no part '%s' in group '%s' of file '%s'. Cannot set cursor '%s'",
1084             part_name, group, file, cursor);
1085         return EINA_FALSE;
1086      }
1087    if (evas_object_pass_events_get(part_obj))
1088      {
1089         const char *group, *file;
1090         edje_object_file_get(wd->lay, &file, &group);
1091         WRN("part '%s' in group '%s' of file '%s' has mouse_events: 0. "
1092             "Cannot set cursor '%s'",
1093             part_name, group, file, cursor);
1094         return EINA_FALSE;
1095      }
1096
1097    pc = _parts_cursors_find(wd, part_name);
1098    if (pc) eina_stringshare_replace(&pc->cursor, cursor);
1099    else
1100      {
1101         pc = calloc(1, sizeof(*pc));
1102         pc->part = eina_stringshare_add(part_name);
1103         pc->cursor = eina_stringshare_add(cursor);
1104      }
1105
1106    pc->obj = part_obj;
1107    elm_object_sub_cursor_set(part_obj, obj, pc->cursor);
1108    return EINA_TRUE;
1109 }
1110
1111 /**
1112  * Get the cursor to be shown when mouse is over an edje part
1113  *
1114  * @param obj The layout object.
1115  * @param part_name a part from loaded edje group.
1116  * @return the cursor name.
1117  *
1118  * @ingroup Layout
1119  */
1120 EAPI const char *
1121 elm_layout_part_cursor_get(const Evas_Object *obj, const char *part_name)
1122 {
1123    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1124    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL);
1125    Widget_Data *wd = elm_widget_data_get(obj);
1126    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
1127    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
1128    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL);
1129    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL);
1130    return elm_object_cursor_get(pc->obj);
1131 }
1132
1133 /**
1134  * Unsets a cursor previously set with elm_layout_part_cursor_set().
1135  *
1136  * @param obj The layout object.
1137  * @param part_name a part from loaded edje group, that had a cursor set
1138  *        with elm_layout_part_cursor_set().
1139  *
1140  * @ingroup Layout
1141  */
1142 EAPI void
1143 elm_layout_part_cursor_unset(Evas_Object *obj, const char *part_name)
1144 {
1145    ELM_CHECK_WIDTYPE(obj, widtype);
1146    EINA_SAFETY_ON_NULL_RETURN(part_name);
1147    Widget_Data *wd = elm_widget_data_get(obj);
1148    EINA_SAFETY_ON_NULL_RETURN(wd);
1149    Eina_List *l;
1150    Part_Cursor *pc;
1151
1152    EINA_LIST_FOREACH(wd->parts_cursors, l, pc)
1153      {
1154         if (!strcmp(part_name, pc->part))
1155           {
1156              if (pc->obj) elm_object_cursor_unset(pc->obj);
1157              _part_cursor_free(pc);
1158              wd->parts_cursors = eina_list_remove_list(wd->parts_cursors, l);
1159              return;
1160           }
1161      }
1162 }
1163
1164 /**
1165  * Sets a specific cursor style for an edje part.
1166  *
1167  * @param obj The layout object.
1168  * @param part_name a part from loaded edje group.
1169  * @param style the theme style to use (default, transparent, ...)
1170  *
1171  * @return EINA_TRUE on success or EINA_FALSE on failure, that may be
1172  *         part not exists or it did not had a cursor set.
1173  *
1174  * @ingroup Layout
1175  */
1176 EAPI Eina_Bool
1177 elm_layout_part_cursor_style_set(Evas_Object *obj, const char *part_name, const char *style)
1178 {
1179    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1180    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1181    Widget_Data *wd = elm_widget_data_get(obj);
1182    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
1183    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
1184    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
1185    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
1186
1187    eina_stringshare_replace(&pc->style, style);
1188    elm_object_cursor_style_set(pc->obj, pc->style);
1189    return EINA_TRUE;
1190 }
1191
1192 /**
1193  * Gets a specific cursor style for an edje part.
1194  *
1195  * @param obj The layout object.
1196  * @param part_name a part from loaded edje group.
1197  *
1198  * @return the theme style in use, defaults to "default". If the
1199  *         object does not have a cursor set, then NULL is returned.
1200  *
1201  * @ingroup Layout
1202  */
1203 EAPI const char *
1204 elm_layout_part_cursor_style_get(const Evas_Object *obj, const char *part_name)
1205 {
1206    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1207    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL);
1208    Widget_Data *wd = elm_widget_data_get(obj);
1209    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
1210    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
1211    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL);
1212    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL);
1213    return elm_object_cursor_style_get(pc->obj);
1214 }
1215
1216 /**
1217  * Sets if the cursor set should be searched on the theme or should use
1218  * the provided by the engine, only.
1219  *
1220  * @note before you set if should look on theme you should define a
1221  * cursor with elm_layout_part_cursor_set(). By default it will only
1222  * look for cursors provided by the engine.
1223  *
1224  * @param obj The layout object.
1225  * @param part_name a part from loaded edje group.
1226  * @param engine_only if cursors should be just provided by the engine
1227  *        or should also search on widget's theme as well
1228  *
1229  * @return EINA_TRUE on success or EINA_FALSE on failure, that may be
1230  *         part not exists or it did not had a cursor set.
1231  *
1232  * @ingroup Layout
1233  */
1234 EAPI Eina_Bool
1235 elm_layout_part_cursor_engine_only_set(Evas_Object *obj, const char *part_name, Eina_Bool engine_only)
1236 {
1237    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1238    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1239    Widget_Data *wd = elm_widget_data_get(obj);
1240    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
1241    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
1242    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
1243    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
1244
1245    pc->engine_only = !!engine_only;
1246    elm_object_cursor_engine_only_set(pc->obj, pc->engine_only);
1247    return EINA_TRUE;
1248 }
1249
1250 /**
1251  * Gets a specific cursor engine_only for an edje part.
1252  *
1253  * @param obj The layout object.
1254  * @param part_name a part from loaded edje group.
1255  *
1256  * @return whenever the cursor is just provided by engine or also from theme.
1257  *
1258  * @ingroup Layout
1259  */
1260 EAPI Eina_Bool
1261 elm_layout_part_cursor_engine_only_get(const Evas_Object *obj, const char *part_name)
1262 {
1263    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1264    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1265    Widget_Data *wd = elm_widget_data_get(obj);
1266    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
1267    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
1268    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
1269    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
1270    return elm_object_cursor_engine_only_get(pc->obj);
1271 }
1272
1273
1274