Elementary migration revision 69832
[framework/uifw/elementary.git] / src / lib / elm_layout.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5 typedef struct _Subinfo Subinfo;
6 typedef struct _Part_Cursor Part_Cursor;
7
8 struct _Widget_Data
9 {
10    Evas_Object *obj;
11    Evas_Object *lay;
12    Eina_List *subs;
13    Eina_List *parts_cursors;
14    Eina_Bool needs_size_calc:1;
15    const char *clas, *group, *style;
16 };
17
18 struct _Subinfo
19 {
20    const char *part;
21    Evas_Object *obj;
22    enum
23      {
24         SWALLOW,
25         BOX_APPEND,
26         BOX_PREPEND,
27         BOX_INSERT_BEFORE,
28         BOX_INSERT_AT,
29         TABLE_PACK,
30         TEXT
31      } type;
32    union
33      {
34         union
35           {
36              const Evas_Object *reference;
37              unsigned int pos;
38           } box;
39         struct
40           {
41              unsigned short col, row, colspan, rowspan;
42           } table;
43         struct
44           {
45              const char *text;
46           } text;
47      } p;
48 };
49
50 struct _Part_Cursor
51 {
52    Evas_Object *obj;
53    const char *part;
54    const char *cursor;
55    const char *style;
56    Eina_Bool engine_only:1;
57 };
58
59 static const char *widtype = NULL;
60 static void _del_hook(Evas_Object *obj);
61 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
62 static void _theme_hook(Evas_Object *obj);
63 static void _sizing_eval(Widget_Data *wd);
64 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
65 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
66 static void _part_cursor_free(Part_Cursor *pc);
67
68 static const char SIG_THEME_CHANGED[] = "theme,changed";
69
70 static const Evas_Smart_Cb_Description _signals[] = {
71    {SIG_THEME_CHANGED, ""},
72    {NULL, NULL}
73 };
74
75 static void
76 _del_hook(Evas_Object *obj)
77 {
78    Widget_Data *wd = elm_widget_data_get(obj);
79    Subinfo *si;
80    Part_Cursor *pc;
81
82    if (!wd) return;
83    EINA_LIST_FREE(wd->subs, si)
84      {
85         eina_stringshare_del(si->part);
86         if (si->type == TEXT)
87           eina_stringshare_del(si->p.text.text);
88         free(si);
89      }
90    EINA_LIST_FREE(wd->parts_cursors, pc) _part_cursor_free(pc);
91    free(wd);
92 }
93
94 static void
95 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
96 {
97    Widget_Data *wd = elm_widget_data_get(obj);
98    if (!wd) return;
99    edje_object_mirrored_set(wd->lay, rtl);
100 }
101
102 static void
103 _theme_hook(Evas_Object *obj)
104 {
105    Widget_Data *wd = elm_widget_data_get(obj);
106    if (!wd) return;
107    _elm_widget_mirrored_reload(obj);
108    _mirrored_set(obj, elm_widget_mirrored_get(obj));
109    _elm_theme_object_set(obj, wd->lay, wd->clas, wd->group, wd->style);
110    edje_object_scale_set(wd->lay, elm_widget_scale_get(obj) *
111                          _elm_config->scale);
112    evas_object_smart_callback_call(obj, SIG_THEME_CHANGED, NULL);
113    _sizing_eval(wd);
114 }
115
116 static void
117 _changed_hook(Evas_Object *obj)
118 {
119    Widget_Data *wd = elm_widget_data_get(obj);
120    if (!wd) return;
121    if (wd->needs_size_calc)
122      {
123         _sizing_eval(wd);
124         wd->needs_size_calc = 0;
125      }
126 }
127
128 static void
129 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
130 {
131    Widget_Data *wd = elm_widget_data_get(obj);
132    edje_object_signal_emit(wd->lay, emission, source);
133 }
134
135 static void
136 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
137 {
138    Widget_Data *wd = elm_widget_data_get(obj);
139    edje_object_signal_callback_add(wd->lay, emission, source, func_cb, data);
140 }
141
142 static void
143 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
144 {
145    Widget_Data *wd = elm_widget_data_get(obj);
146    edje_object_signal_callback_del_full(wd->lay, emission, source, func_cb,
147                                         data);
148 }
149
150
151 static void *
152 _elm_layout_list_data_get(const Eina_List *list)
153 {
154    Subinfo *si = eina_list_data_get(list);
155    return si->obj;
156 }
157
158 static Eina_Bool
159 _elm_layout_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
160 {
161    Widget_Data *wd = elm_widget_data_get(obj);
162    const Eina_List *items;
163    void *(*list_data_get) (const Eina_List *list);
164
165    if ((!wd) || (!wd->subs))
166      return EINA_FALSE;
167
168    /* Focus chain (This block is diferent of elm_win cycle)*/
169    if ((items = elm_widget_focus_custom_chain_get(obj)))
170      list_data_get = eina_list_data_get;
171    else
172      {
173         items = wd->subs;
174         list_data_get = _elm_layout_list_data_get;
175
176         if (!items) return EINA_FALSE;
177      }
178
179    return elm_widget_focus_list_next_get(obj, items, list_data_get, dir,
180                                          next);
181 }
182
183 static void
184 _sizing_eval(Widget_Data *wd)
185 {
186    Evas_Coord minw = -1, minh = -1;
187    edje_object_size_min_calc(wd->lay, &minw, &minh);
188    evas_object_size_hint_min_set(wd->obj, minw, minh);
189    evas_object_size_hint_max_set(wd->obj, -1, -1);
190 }
191
192 static void
193 _request_sizing_eval(Widget_Data *wd)
194 {
195    if (wd->needs_size_calc) return;
196    wd->needs_size_calc = 1;
197    evas_object_smart_changed(wd->obj);
198 }
199
200 static void
201 _part_cursor_free(Part_Cursor *pc)
202 {
203    eina_stringshare_del(pc->part);
204    eina_stringshare_del(pc->style);
205    eina_stringshare_del(pc->cursor);
206    free(pc);
207 }
208
209 static void
210 _part_cursor_part_apply(const Part_Cursor *pc)
211 {
212    elm_object_cursor_set(pc->obj, pc->cursor);
213    elm_object_cursor_style_set(pc->obj, pc->style);
214    elm_object_cursor_theme_search_enabled_set(pc->obj, pc->engine_only);
215 }
216
217 static Part_Cursor *
218 _parts_cursors_find(Widget_Data *wd, const char *part)
219 {
220    const Eina_List *l;
221    Part_Cursor *pc;
222    EINA_LIST_FOREACH(wd->parts_cursors, l, pc)
223      {
224         if (!strcmp(pc->part, part))
225           return pc;
226      }
227    return NULL;
228 }
229
230 static void
231 _parts_cursors_apply(Widget_Data *wd)
232 {
233    const char *file, *group;
234    const Eina_List *l;
235    Part_Cursor *pc;
236
237    edje_object_file_get(wd->lay, &file, &group);
238
239    EINA_LIST_FOREACH(wd->parts_cursors, l, pc)
240      {
241         Evas_Object *obj = (Evas_Object *)edje_object_part_object_get
242            (wd->lay, pc->part);
243
244         if (!obj)
245           {
246              pc->obj = NULL;
247              WRN("no part '%s' in group '%s' of file '%s'. "
248                  "Cannot set cursor '%s'",
249                  pc->part, group, file, pc->cursor);
250              continue;
251           }
252         else if (evas_object_pass_events_get(obj))
253           {
254              pc->obj = NULL;
255              WRN("part '%s' in group '%s' of file '%s' has mouse_events: 0. "
256                  "Cannot set cursor '%s'",
257                  pc->part, group, file, pc->cursor);
258              continue;
259           }
260
261         pc->obj = obj;
262         _part_cursor_part_apply(pc);
263      }
264 }
265
266 static void
267 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
268 {
269    _request_sizing_eval(data);
270 }
271
272 static void
273 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
274 {
275    Widget_Data *wd = elm_widget_data_get(obj);
276    Evas_Object *sub = event_info;
277    Eina_List *l;
278    Subinfo *si;
279    if (!wd) return;
280    EINA_LIST_FOREACH(wd->subs, l, si)
281      {
282         if (si->obj == sub)
283           {
284              evas_object_event_callback_del_full(sub,
285                                                  EVAS_CALLBACK_CHANGED_SIZE_HINTS,
286                                                  _changed_size_hints,
287                                                  wd);
288              wd->subs = eina_list_remove_list(wd->subs, l);
289              eina_stringshare_del(si->part);
290              free(si);
291              break;
292           }
293      }
294 }
295
296 static void
297 _signal_size_eval(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
298 {
299    _request_sizing_eval(data);
300 }
301
302 static void
303 _parts_text_fix(Widget_Data *wd)
304 {
305    const Eina_List *l;
306    Subinfo *si;
307
308    EINA_LIST_FOREACH(wd->subs, l, si)
309      {
310         if (si->type == TEXT)
311           edje_object_part_text_set(wd->lay, si->part, si->p.text.text);
312      }
313 }
314
315 static void
316 _elm_layout_label_set(Evas_Object *obj, const char *part, const char *text)
317 {
318    Widget_Data *wd = elm_widget_data_get(obj);
319    Subinfo *si = NULL;
320    Eina_List *l;
321    ELM_CHECK_WIDTYPE(obj, widtype);
322    if (!part) part = "elm.text";
323
324    EINA_LIST_FOREACH(wd->subs, l, si)
325      {
326         if ((si->type == TEXT) && (!strcmp(part, si->part)))
327           {
328              if (!text)
329                {
330                   eina_stringshare_del(si->part);
331                   eina_stringshare_del(si->p.text.text);
332                   free(si);
333                   edje_object_part_text_set(wd->lay, part, NULL);
334                   wd->subs = eina_list_remove_list(wd->subs, l);
335                   return;
336                }
337              else
338                break;
339           }
340         si = NULL;
341      }
342
343    if (!si)
344      {
345         si = ELM_NEW(Subinfo);
346         if (!si) return;
347         si->type = TEXT;
348         si->part = eina_stringshare_add(part);
349         wd->subs = eina_list_append(wd->subs, si);
350      }
351
352    eina_stringshare_replace(&si->p.text.text, text);
353    edje_object_part_text_set(wd->lay, part, text);
354    _request_sizing_eval(wd);
355 }
356
357 static const char *
358 _elm_layout_label_get(const Evas_Object *obj, const char *part)
359 {
360    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
361    Widget_Data *wd = elm_widget_data_get(obj);
362    if (!part) part = "elm.text";
363    return edje_object_part_text_get(wd->lay, part);
364 }
365
366 static void
367 _content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
368 {
369    ELM_CHECK_WIDTYPE(obj, widtype);
370    Widget_Data *wd = elm_widget_data_get(obj);
371    Subinfo *si;
372    const Eina_List *l;
373    if (!wd) return;
374    EINA_LIST_FOREACH(wd->subs, l, si)
375      {
376         if ((si->type == SWALLOW) && (!strcmp(part, si->part)))
377           {
378              if (content == si->obj) return;
379              evas_object_del(si->obj);
380              break;
381           }
382      }
383    if (content)
384      {
385         elm_widget_sub_object_add(obj, content);
386         evas_object_event_callback_add(content,
387                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
388                                        _changed_size_hints, wd);
389         if (!edje_object_part_swallow(wd->lay, part, content))
390           WRN("could not swallow %p into part '%s'", content, part);
391         si = ELM_NEW(Subinfo);
392         si->type = SWALLOW;
393         si->part = eina_stringshare_add(part);
394         si->obj = content;
395         wd->subs = eina_list_append(wd->subs, si);
396      }
397    _request_sizing_eval(wd);
398 }
399
400 static Evas_Object *
401 _content_get_hook(const Evas_Object *obj, const char *part)
402 {
403    Widget_Data *wd = elm_widget_data_get(obj);
404    const Eina_List *l;
405    Subinfo *si;
406    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
407
408    EINA_LIST_FOREACH(wd->subs, l, si)
409      {
410         if ((si->type == SWALLOW) && !strcmp(part, si->part))
411           return si->obj;
412      }
413    return NULL;
414 }
415
416 static Evas_Object *
417 _content_unset_hook(Evas_Object *obj, const char *part)
418 {
419    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
420    Widget_Data *wd = elm_widget_data_get(obj);
421    Subinfo *si;
422    const Eina_List *l;
423    if (!wd) return NULL;
424    EINA_LIST_FOREACH(wd->subs, l, si)
425      {
426         if ((si->type == SWALLOW) && (!strcmp(part, si->part)))
427           {
428              Evas_Object *content;
429              if (!si->obj) return NULL;
430              content = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
431              elm_widget_sub_object_del(obj, content);
432              evas_object_event_callback_del_full(content,
433                                                  EVAS_CALLBACK_CHANGED_SIZE_HINTS,
434                                                  _changed_size_hints, wd);
435              edje_object_part_unswallow(wd->lay, content);
436              return content;
437           }
438      }
439    return NULL;
440 }
441
442 EAPI Evas_Object *
443 elm_layout_add(Evas_Object *parent)
444 {
445    Evas_Object *obj;
446    Evas *e;
447    Widget_Data *wd;
448
449    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
450
451    ELM_SET_WIDTYPE(widtype, "layout");
452    elm_widget_type_set(obj, "layout");
453    elm_widget_sub_object_add(parent, obj);
454    elm_widget_data_set(obj, wd);
455    elm_widget_del_hook_set(obj, _del_hook);
456    elm_widget_theme_hook_set(obj, _theme_hook);
457    elm_widget_changed_hook_set(obj, _changed_hook);
458    elm_widget_can_focus_set(obj, EINA_FALSE);
459    elm_widget_focus_next_hook_set(obj, _elm_layout_focus_next_hook);
460    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
461    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
462    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
463    elm_widget_text_set_hook_set(obj, _elm_layout_label_set);
464    elm_widget_text_get_hook_set(obj, _elm_layout_label_get);
465    elm_widget_content_set_hook_set(obj, _content_set_hook);
466    elm_widget_content_get_hook_set(obj, _content_get_hook);
467    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
468
469    wd->obj = obj;
470    wd->lay = edje_object_add(e);
471    elm_widget_resize_object_set(obj, wd->lay);
472    edje_object_signal_callback_add(wd->lay, "size,eval", "elm",
473                                    _signal_size_eval, wd);
474
475    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
476    evas_object_smart_callbacks_descriptions_set(obj, _signals);
477
478    _mirrored_set(obj, elm_widget_mirrored_get(obj));
479    _request_sizing_eval(wd);
480    return obj;
481 }
482
483 EAPI Eina_Bool
484 elm_layout_file_set(Evas_Object *obj, const char *file, const char *group)
485 {
486    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
487    Widget_Data *wd = elm_widget_data_get(obj);
488    if (!wd) return EINA_FALSE;
489    Eina_Bool ret = edje_object_file_set(wd->lay, file, group);
490    if (ret)
491      {
492         _parts_text_fix(wd);
493         _request_sizing_eval(wd);
494         _parts_cursors_apply(wd);
495      }
496    else DBG("failed to set edje file '%s', group '%s': %s",
497             file, group,
498             edje_load_error_str(edje_object_load_error_get(wd->lay)));
499    return ret;
500 }
501
502 EAPI Eina_Bool
503 elm_layout_theme_set(Evas_Object *obj, const char *clas, const char *group, const char *style)
504 {
505    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
506    Widget_Data *wd = elm_widget_data_get(obj);
507    if (!wd) return EINA_FALSE;
508    Eina_Bool ret = _elm_theme_object_set(obj, wd->lay, clas, group, style);
509    wd->clas = clas;
510    wd->group = group;
511    wd->style = style;
512    if (ret)
513      {
514         _parts_text_fix(wd);
515         _request_sizing_eval(wd);
516         _parts_cursors_apply(wd);
517      }
518    return ret;
519 }
520
521 EAPI Eina_Bool
522 elm_layout_box_append(Evas_Object *obj, const char *part, Evas_Object *child)
523 {
524    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
525    Widget_Data *wd = elm_widget_data_get(obj);
526    Subinfo *si;
527    if (!wd) return EINA_FALSE;
528
529    if (!edje_object_part_box_append(wd->lay, part, child))
530      WRN("child %p could not be appended to box part '%s'", child, part);
531    elm_widget_sub_object_add(obj, child);
532    evas_object_event_callback_add
533       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
534
535    si = ELM_NEW(Subinfo);
536    si->type = BOX_APPEND;
537    si->part = eina_stringshare_add(part);
538    si->obj = child;
539    wd->subs = eina_list_append(wd->subs, si);
540    _request_sizing_eval(wd);
541
542    return EINA_TRUE;
543 }
544
545 EAPI Eina_Bool
546 elm_layout_box_prepend(Evas_Object *obj, const char *part, Evas_Object *child)
547 {
548    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
549    Widget_Data *wd = elm_widget_data_get(obj);
550    Subinfo *si;
551    if (!wd) return EINA_FALSE;
552
553    if (!edje_object_part_box_prepend(wd->lay, part, child))
554      WRN("child %p could not be prepended to box part '%s'", child, part);
555    elm_widget_sub_object_add(obj, child);
556    evas_object_event_callback_add
557       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
558
559    si = ELM_NEW(Subinfo);
560    si->type = BOX_PREPEND;
561    si->part = eina_stringshare_add(part);
562    si->obj = child;
563    wd->subs = eina_list_prepend(wd->subs, si);
564    _request_sizing_eval(wd);
565
566    return EINA_TRUE;
567 }
568
569 static void
570 _box_reference_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
571 {
572    Subinfo *si = data;
573    si->p.box.reference = NULL;
574 }
575
576 EAPI Eina_Bool
577 elm_layout_box_insert_before(Evas_Object *obj, const char *part, Evas_Object *child, const Evas_Object *reference)
578 {
579    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
580    Widget_Data *wd = elm_widget_data_get(obj);
581    Subinfo *si;
582    if (!wd) return EINA_FALSE;
583
584    if (!edje_object_part_box_insert_before(wd->lay, part, child, reference))
585      WRN("child %p could not be inserted before %p inf box part '%s'",
586          child, reference, part);
587
588    si = ELM_NEW(Subinfo);
589    si->type = BOX_INSERT_BEFORE;
590    si->part = eina_stringshare_add(part);
591    si->obj = child;
592    si->p.box.reference = reference;
593
594    elm_widget_sub_object_add(obj, child);
595    evas_object_event_callback_add
596       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
597    evas_object_event_callback_add
598       ((Evas_Object *)reference, EVAS_CALLBACK_DEL, _box_reference_del, si);
599
600    wd->subs = eina_list_append(wd->subs, si);
601    _request_sizing_eval(wd);
602
603    return EINA_TRUE;
604 }
605
606 EAPI Eina_Bool
607 elm_layout_box_insert_at(Evas_Object *obj, const char *part, Evas_Object *child, unsigned int pos)
608 {
609    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
610    Widget_Data *wd = elm_widget_data_get(obj);
611    Subinfo *si;
612    if (!wd) return EINA_FALSE;
613
614    if (!edje_object_part_box_insert_at(wd->lay, part, child, pos))
615      WRN("child %p could not be inserted at %u to box part '%s'",
616          child, pos, part);
617
618    elm_widget_sub_object_add(obj, child);
619    evas_object_event_callback_add
620       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
621
622    si = ELM_NEW(Subinfo);
623    si->type = BOX_INSERT_AT;
624    si->part = eina_stringshare_add(part);
625    si->obj = child;
626    si->p.box.pos = pos;
627    wd->subs = eina_list_append(wd->subs, si);
628    _request_sizing_eval(wd);
629
630    return EINA_TRUE;
631 }
632
633 static Evas_Object *
634 _sub_box_remove(Widget_Data *wd, Subinfo *si)
635 {
636    Evas_Object *child;
637
638    if (si->type == BOX_INSERT_BEFORE)
639      evas_object_event_callback_del_full
640         ((Evas_Object *)si->p.box.reference,
641          EVAS_CALLBACK_DEL, _box_reference_del, si);
642
643    child = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
644    edje_object_part_box_remove(wd->lay, si->part, child);
645    elm_widget_sub_object_del(wd->obj, child);
646    return child;
647 }
648
649 static Evas_Object *
650 _sub_table_remove(Widget_Data *wd, Subinfo *si)
651 {
652    Evas_Object *child;
653
654    child = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
655    edje_object_part_table_unpack(wd->lay, si->part, child);
656    elm_widget_sub_object_del(wd->obj, child);
657    return child;
658 }
659
660 static Eina_Bool
661 _sub_box_is(const Subinfo *si)
662 {
663    switch (si->type)
664      {
665       case BOX_APPEND:
666       case BOX_PREPEND:
667       case BOX_INSERT_BEFORE:
668       case BOX_INSERT_AT:
669          return EINA_TRUE;
670       default:
671          return EINA_FALSE;
672      }
673 }
674
675 EAPI Evas_Object *
676 elm_layout_box_remove(Evas_Object *obj, const char *part, Evas_Object *child)
677 {
678    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
679    Widget_Data *wd = elm_widget_data_get(obj);
680    const Eina_List *l;
681    Subinfo *si;
682
683    if (!wd) return NULL;
684
685    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
686    EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
687    EINA_LIST_FOREACH(wd->subs, l, si)
688      {
689         if (!_sub_box_is(si)) continue;
690         if ((si->obj == child) && (!strcmp(si->part, part)))
691           return _sub_box_remove(wd, si);
692      }
693    return NULL;
694 }
695
696 EAPI Eina_Bool
697 elm_layout_box_remove_all(Evas_Object *obj, const char *part, Eina_Bool clear)
698 {
699    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
700    Widget_Data *wd = elm_widget_data_get(obj);
701    Subinfo *si;
702    Eina_List *lst;
703
704    if (!wd) return EINA_FALSE;
705    EINA_SAFETY_ON_NULL_RETURN_VAL(part, EINA_FALSE);
706
707    lst = eina_list_clone(wd->subs);
708    EINA_LIST_FREE(lst, si)
709      {
710         if (!_sub_box_is(si)) continue;
711         if (!strcmp(si->part, part))
712           {
713              Evas_Object *child = _sub_box_remove(wd, si);
714              if ((clear) && (child)) evas_object_del(child);
715           }
716      }
717    /* eventually something may not be added with layout, del them as well */
718    edje_object_part_box_remove_all(wd->lay, part, clear);
719
720    return EINA_TRUE;
721 }
722
723 EAPI Eina_Bool
724 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)
725 {
726    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
727    Widget_Data *wd = elm_widget_data_get(obj);
728    Subinfo *si;
729    if (!wd) return EINA_FALSE;
730
731    if (!edje_object_part_table_pack
732        (wd->lay, part, child, col, row, colspan, rowspan))
733      WRN("child %p could not be packed into box part '%s' col=%uh, row=%hu, "
734          "colspan=%hu, rowspan=%hu", child, part, col, row, colspan, rowspan);
735
736    elm_widget_sub_object_add(obj, child);
737    evas_object_event_callback_add
738       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
739
740    si = ELM_NEW(Subinfo);
741    si->type = TABLE_PACK;
742    si->part = eina_stringshare_add(part);
743    si->obj = child;
744    si->p.table.col = col;
745    si->p.table.row = row;
746    si->p.table.colspan = colspan;
747    si->p.table.rowspan = rowspan;
748    wd->subs = eina_list_append(wd->subs, si);
749    _request_sizing_eval(wd);
750
751    return EINA_TRUE;
752 }
753
754 EAPI Evas_Object *
755 elm_layout_table_unpack(Evas_Object *obj, const char *part, Evas_Object *child)
756 {
757    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
758    Widget_Data *wd = elm_widget_data_get(obj);
759    const Eina_List *l;
760    Subinfo *si;
761
762    if (!wd) return NULL;
763
764    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
765    EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
766    EINA_LIST_FOREACH(wd->subs, l, si)
767      {
768         if (si->type != TABLE_PACK) continue;
769         if ((si->obj == child) && (!strcmp(si->part, part)))
770           return _sub_table_remove(wd, si);
771      }
772    return NULL;
773 }
774
775 EAPI Eina_Bool
776 elm_layout_table_clear(Evas_Object *obj, const char *part, Eina_Bool clear)
777 {
778    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
779    Widget_Data *wd = elm_widget_data_get(obj);
780    Subinfo *si;
781    Eina_List *lst;
782
783    if (!wd) return EINA_FALSE;
784    EINA_SAFETY_ON_NULL_RETURN_VAL(part, EINA_FALSE);
785
786    lst = eina_list_clone(wd->subs);
787    EINA_LIST_FREE(lst, si)
788      {
789         if (si->type != TABLE_PACK) continue;
790         if (!strcmp(si->part, part))
791           {
792              Evas_Object *child = _sub_table_remove(wd, si);
793              if ((clear) && (child)) evas_object_del(child);
794           }
795      }
796    /* eventually something may not be added with layout, del them as well */
797    edje_object_part_table_clear(wd->lay, part, clear);
798
799    return EINA_TRUE;
800 }
801
802 EAPI Evas_Object *
803 elm_layout_edje_get(const Evas_Object *obj)
804 {
805    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
806    Widget_Data *wd = elm_widget_data_get(obj);
807    if (!wd) return NULL;
808    return wd->lay;
809 }
810
811 EAPI const char *
812 elm_layout_data_get(const Evas_Object *obj, const char *key)
813 {
814    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
815    Widget_Data *wd = elm_widget_data_get(obj);
816    return edje_object_data_get(wd->lay, key);
817 }
818
819 EAPI void
820 elm_layout_sizing_eval(Evas_Object *obj)
821 {
822    ELM_CHECK_WIDTYPE(obj, widtype);
823    Widget_Data *wd = elm_widget_data_get(obj);
824    EINA_SAFETY_ON_NULL_RETURN(wd);
825    _request_sizing_eval(wd);
826 }
827
828 EAPI Eina_Bool
829 elm_layout_part_cursor_set(Evas_Object *obj, const char *part_name, const char *cursor)
830 {
831    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
832    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
833    Widget_Data *wd = elm_widget_data_get(obj);
834    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
835    Evas_Object *part_obj;
836    Part_Cursor *pc;
837
838    part_obj = (Evas_Object *)edje_object_part_object_get(wd->lay, part_name);
839    if (!part_obj)
840      {
841         const char *group, *file;
842         edje_object_file_get(wd->lay, &file, &group);
843         WRN("no part '%s' in group '%s' of file '%s'. Cannot set cursor '%s'",
844             part_name, group, file, cursor);
845         return EINA_FALSE;
846      }
847    if (evas_object_pass_events_get(part_obj))
848      {
849         const char *group, *file;
850         edje_object_file_get(wd->lay, &file, &group);
851         WRN("part '%s' in group '%s' of file '%s' has mouse_events: 0. "
852             "Cannot set cursor '%s'",
853             part_name, group, file, cursor);
854         return EINA_FALSE;
855      }
856
857    pc = _parts_cursors_find(wd, part_name);
858    if (pc) eina_stringshare_replace(&pc->cursor, cursor);
859    else
860      {
861         pc = calloc(1, sizeof(*pc));
862         pc->part = eina_stringshare_add(part_name);
863         pc->cursor = eina_stringshare_add(cursor);
864         pc->style = eina_stringshare_add("default");
865         wd->parts_cursors = eina_list_append(wd->parts_cursors, pc);
866      }
867
868    pc->obj = part_obj;
869    elm_object_sub_cursor_set(part_obj, obj, pc->cursor);
870    return EINA_TRUE;
871 }
872
873 EAPI const char *
874 elm_layout_part_cursor_get(const Evas_Object *obj, const char *part_name)
875 {
876    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
877    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL);
878    Widget_Data *wd = elm_widget_data_get(obj);
879    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
880    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
881    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL);
882    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL);
883    return elm_object_cursor_get(pc->obj);
884 }
885
886 EAPI Eina_Bool
887 elm_layout_part_cursor_unset(Evas_Object *obj, const char *part_name)
888 {
889    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
890    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
891    Widget_Data *wd = elm_widget_data_get(obj);
892    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
893    Eina_List *l;
894    Part_Cursor *pc;
895
896    EINA_LIST_FOREACH(wd->parts_cursors, l, pc)
897      {
898         if (!strcmp(part_name, pc->part))
899           {
900              if (pc->obj) elm_object_cursor_unset(pc->obj);
901              _part_cursor_free(pc);
902              wd->parts_cursors = eina_list_remove_list(wd->parts_cursors, l);
903              return EINA_TRUE;
904           }
905      }
906
907    return EINA_FALSE;
908 }
909
910 EAPI Eina_Bool
911 elm_layout_part_cursor_style_set(Evas_Object *obj, const char *part_name, const char *style)
912 {
913    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
914    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
915    Widget_Data *wd = elm_widget_data_get(obj);
916    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
917    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
918    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
919    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
920
921    eina_stringshare_replace(&pc->style, style);
922    elm_object_cursor_style_set(pc->obj, pc->style);
923    return EINA_TRUE;
924 }
925
926 EAPI const char *
927 elm_layout_part_cursor_style_get(const Evas_Object *obj, const char *part_name)
928 {
929    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
930    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL);
931    Widget_Data *wd = elm_widget_data_get(obj);
932    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
933    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
934    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL);
935    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL);
936    return elm_object_cursor_style_get(pc->obj);
937 }
938
939 EAPI Eina_Bool
940 elm_layout_part_cursor_engine_only_set(Evas_Object *obj, const char *part_name, Eina_Bool engine_only)
941 {
942    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
943    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
944    Widget_Data *wd = elm_widget_data_get(obj);
945    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
946    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
947    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
948    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
949
950    pc->engine_only = !!engine_only;
951    elm_object_cursor_theme_search_enabled_set(pc->obj, pc->engine_only);
952    return EINA_TRUE;
953 }
954
955 EAPI Eina_Bool
956 elm_layout_part_cursor_engine_only_get(const Evas_Object *obj, const char *part_name)
957 {
958    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
959    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
960    Widget_Data *wd = elm_widget_data_get(obj);
961    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
962    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
963    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
964    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
965    return elm_object_cursor_theme_search_enabled_get(pc->obj);
966 }