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