fixed plugin image size problem
[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_escaped_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_escaped_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_escaped_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_SAFETY_ON_NULL_RETURN(part);
375    EINA_LIST_FOREACH(wd->subs, l, si)
376      {
377         if ((si->type == SWALLOW) && (!strcmp(part, si->part)))
378           {
379              if (content == si->obj) return;
380              evas_object_del(si->obj);
381              break;
382           }
383      }
384    if (content)
385      {
386         elm_widget_sub_object_add(obj, content);
387         evas_object_event_callback_add(content,
388                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
389                                        _changed_size_hints, wd);
390         if (!edje_object_part_swallow(wd->lay, part, content))
391           WRN("could not swallow %p into part '%s'", content, part);
392         si = ELM_NEW(Subinfo);
393         si->type = SWALLOW;
394         si->part = eina_stringshare_add(part);
395         si->obj = content;
396         wd->subs = eina_list_append(wd->subs, si);
397      }
398    _request_sizing_eval(wd);
399 }
400
401 static Evas_Object *
402 _content_get_hook(const Evas_Object *obj, const char *part)
403 {
404    Widget_Data *wd = elm_widget_data_get(obj);
405    const Eina_List *l;
406    Subinfo *si;
407    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
408
409    EINA_LIST_FOREACH(wd->subs, l, si)
410      {
411         if ((si->type == SWALLOW) && !strcmp(part, si->part))
412           return si->obj;
413      }
414    return NULL;
415 }
416
417 static Evas_Object *
418 _content_unset_hook(Evas_Object *obj, const char *part)
419 {
420    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
421    Widget_Data *wd = elm_widget_data_get(obj);
422    Subinfo *si;
423    const Eina_List *l;
424    if (!wd) return NULL;
425    EINA_LIST_FOREACH(wd->subs, l, si)
426      {
427         if ((si->type == SWALLOW) && (!strcmp(part, si->part)))
428           {
429              Evas_Object *content;
430              if (!si->obj) return NULL;
431              content = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
432              elm_widget_sub_object_del(obj, content);
433              evas_object_event_callback_del_full(content,
434                                                  EVAS_CALLBACK_CHANGED_SIZE_HINTS,
435                                                  _changed_size_hints, wd);
436              edje_object_part_unswallow(wd->lay, content);
437              return content;
438           }
439      }
440    return NULL;
441 }
442
443 EAPI Evas_Object *
444 elm_layout_add(Evas_Object *parent)
445 {
446    Evas_Object *obj;
447    Evas *e;
448    Widget_Data *wd;
449
450    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
451
452    ELM_SET_WIDTYPE(widtype, "layout");
453    elm_widget_type_set(obj, "layout");
454    elm_widget_sub_object_add(parent, obj);
455    elm_widget_data_set(obj, wd);
456    elm_widget_del_hook_set(obj, _del_hook);
457    elm_widget_theme_hook_set(obj, _theme_hook);
458    elm_widget_changed_hook_set(obj, _changed_hook);
459    elm_widget_can_focus_set(obj, EINA_FALSE);
460    elm_widget_focus_next_hook_set(obj, _elm_layout_focus_next_hook);
461    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
462    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
463    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
464    elm_widget_text_set_hook_set(obj, _elm_layout_label_set);
465    elm_widget_text_get_hook_set(obj, _elm_layout_label_get);
466    elm_widget_content_set_hook_set(obj, _content_set_hook);
467    elm_widget_content_get_hook_set(obj, _content_get_hook);
468    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
469
470    wd->obj = obj;
471    wd->lay = edje_object_add(e);
472    elm_widget_resize_object_set(obj, wd->lay);
473    edje_object_signal_callback_add(wd->lay, "size,eval", "elm",
474                                    _signal_size_eval, wd);
475
476    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
477    evas_object_smart_callbacks_descriptions_set(obj, _signals);
478
479    _mirrored_set(obj, elm_widget_mirrored_get(obj));
480    _request_sizing_eval(wd);
481    return obj;
482 }
483
484 EAPI Eina_Bool
485 elm_layout_file_set(Evas_Object *obj, const char *file, const char *group)
486 {
487    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
488    Widget_Data *wd = elm_widget_data_get(obj);
489    if (!wd) return EINA_FALSE;
490    Eina_Bool ret = edje_object_file_set(wd->lay, file, group);
491    if (ret)
492      {
493         _parts_text_fix(wd);
494         _request_sizing_eval(wd);
495         _parts_cursors_apply(wd);
496      }
497    else DBG("failed to set edje file '%s', group '%s': %s",
498             file, group,
499             edje_load_error_str(edje_object_load_error_get(wd->lay)));
500    return ret;
501 }
502
503 EAPI Eina_Bool
504 elm_layout_theme_set(Evas_Object *obj, const char *clas, const char *group, const char *style)
505 {
506    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
507    Widget_Data *wd = elm_widget_data_get(obj);
508    if (!wd) return EINA_FALSE;
509    Eina_Bool ret = _elm_theme_object_set(obj, wd->lay, clas, group, style);
510    wd->clas = clas;
511    wd->group = group;
512    wd->style = style;
513    if (ret)
514      {
515         _parts_text_fix(wd);
516         _request_sizing_eval(wd);
517         _parts_cursors_apply(wd);
518      }
519    return ret;
520 }
521
522 EAPI Eina_Bool
523 elm_layout_box_append(Evas_Object *obj, const char *part, Evas_Object *child)
524 {
525    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
526    Widget_Data *wd = elm_widget_data_get(obj);
527    Subinfo *si;
528    if (!wd) return EINA_FALSE;
529
530    if (!edje_object_part_box_append(wd->lay, part, child))
531      WRN("child %p could not be appended to box part '%s'", child, part);
532    elm_widget_sub_object_add(obj, child);
533    evas_object_event_callback_add
534       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
535
536    si = ELM_NEW(Subinfo);
537    si->type = BOX_APPEND;
538    si->part = eina_stringshare_add(part);
539    si->obj = child;
540    wd->subs = eina_list_append(wd->subs, si);
541    _request_sizing_eval(wd);
542
543    return EINA_TRUE;
544 }
545
546 EAPI Eina_Bool
547 elm_layout_box_prepend(Evas_Object *obj, const char *part, Evas_Object *child)
548 {
549    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
550    Widget_Data *wd = elm_widget_data_get(obj);
551    Subinfo *si;
552    if (!wd) return EINA_FALSE;
553
554    if (!edje_object_part_box_prepend(wd->lay, part, child))
555      WRN("child %p could not be prepended to box part '%s'", child, part);
556    elm_widget_sub_object_add(obj, child);
557    evas_object_event_callback_add
558       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
559
560    si = ELM_NEW(Subinfo);
561    si->type = BOX_PREPEND;
562    si->part = eina_stringshare_add(part);
563    si->obj = child;
564    wd->subs = eina_list_prepend(wd->subs, si);
565    _request_sizing_eval(wd);
566
567    return EINA_TRUE;
568 }
569
570 static void
571 _box_reference_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
572 {
573    Subinfo *si = data;
574    si->p.box.reference = NULL;
575 }
576
577 EAPI Eina_Bool
578 elm_layout_box_insert_before(Evas_Object *obj, const char *part, Evas_Object *child, const Evas_Object *reference)
579 {
580    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
581    Widget_Data *wd = elm_widget_data_get(obj);
582    Subinfo *si;
583    if (!wd) return EINA_FALSE;
584
585    if (!edje_object_part_box_insert_before(wd->lay, part, child, reference))
586      WRN("child %p could not be inserted before %p inf box part '%s'",
587          child, reference, part);
588
589    si = ELM_NEW(Subinfo);
590    si->type = BOX_INSERT_BEFORE;
591    si->part = eina_stringshare_add(part);
592    si->obj = child;
593    si->p.box.reference = reference;
594
595    elm_widget_sub_object_add(obj, child);
596    evas_object_event_callback_add
597       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
598    evas_object_event_callback_add
599       ((Evas_Object *)reference, EVAS_CALLBACK_DEL, _box_reference_del, si);
600
601    wd->subs = eina_list_append(wd->subs, si);
602    _request_sizing_eval(wd);
603
604    return EINA_TRUE;
605 }
606
607 EAPI Eina_Bool
608 elm_layout_box_insert_at(Evas_Object *obj, const char *part, Evas_Object *child, unsigned int pos)
609 {
610    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
611    Widget_Data *wd = elm_widget_data_get(obj);
612    Subinfo *si;
613    if (!wd) return EINA_FALSE;
614
615    if (!edje_object_part_box_insert_at(wd->lay, part, child, pos))
616      WRN("child %p could not be inserted at %u to box part '%s'",
617          child, pos, part);
618
619    elm_widget_sub_object_add(obj, child);
620    evas_object_event_callback_add
621       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
622
623    si = ELM_NEW(Subinfo);
624    si->type = BOX_INSERT_AT;
625    si->part = eina_stringshare_add(part);
626    si->obj = child;
627    si->p.box.pos = pos;
628    wd->subs = eina_list_append(wd->subs, si);
629    _request_sizing_eval(wd);
630
631    return EINA_TRUE;
632 }
633
634 static Evas_Object *
635 _sub_box_remove(Widget_Data *wd, Subinfo *si)
636 {
637    Evas_Object *child;
638
639    if (si->type == BOX_INSERT_BEFORE)
640      evas_object_event_callback_del_full
641         ((Evas_Object *)si->p.box.reference,
642          EVAS_CALLBACK_DEL, _box_reference_del, si);
643
644    child = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
645    edje_object_part_box_remove(wd->lay, si->part, child);
646    elm_widget_sub_object_del(wd->obj, child);
647    return child;
648 }
649
650 static Evas_Object *
651 _sub_table_remove(Widget_Data *wd, Subinfo *si)
652 {
653    Evas_Object *child;
654
655    child = si->obj; /* si will die in _sub_del due elm_widget_sub_object_del() */
656    edje_object_part_table_unpack(wd->lay, si->part, child);
657    elm_widget_sub_object_del(wd->obj, child);
658    return child;
659 }
660
661 static Eina_Bool
662 _sub_box_is(const Subinfo *si)
663 {
664    switch (si->type)
665      {
666       case BOX_APPEND:
667       case BOX_PREPEND:
668       case BOX_INSERT_BEFORE:
669       case BOX_INSERT_AT:
670          return EINA_TRUE;
671       default:
672          return EINA_FALSE;
673      }
674 }
675
676 EAPI Evas_Object *
677 elm_layout_box_remove(Evas_Object *obj, const char *part, Evas_Object *child)
678 {
679    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
680    Widget_Data *wd = elm_widget_data_get(obj);
681    const Eina_List *l;
682    Subinfo *si;
683
684    if (!wd) return NULL;
685
686    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
687    EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
688    EINA_LIST_FOREACH(wd->subs, l, si)
689      {
690         if (!_sub_box_is(si)) continue;
691         if ((si->obj == child) && (!strcmp(si->part, part)))
692           return _sub_box_remove(wd, si);
693      }
694    return NULL;
695 }
696
697 EAPI Eina_Bool
698 elm_layout_box_remove_all(Evas_Object *obj, const char *part, Eina_Bool clear)
699 {
700    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
701    Widget_Data *wd = elm_widget_data_get(obj);
702    Subinfo *si;
703    Eina_List *lst;
704
705    if (!wd) return EINA_FALSE;
706    EINA_SAFETY_ON_NULL_RETURN_VAL(part, EINA_FALSE);
707
708    lst = eina_list_clone(wd->subs);
709    EINA_LIST_FREE(lst, si)
710      {
711         if (!_sub_box_is(si)) continue;
712         if (!strcmp(si->part, part))
713           {
714              Evas_Object *child = _sub_box_remove(wd, si);
715              if ((clear) && (child)) evas_object_del(child);
716           }
717      }
718    /* eventually something may not be added with layout, del them as well */
719    edje_object_part_box_remove_all(wd->lay, part, clear);
720
721    return EINA_TRUE;
722 }
723
724 EAPI Eina_Bool
725 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)
726 {
727    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
728    Widget_Data *wd = elm_widget_data_get(obj);
729    Subinfo *si;
730    if (!wd) return EINA_FALSE;
731
732    if (!edje_object_part_table_pack
733        (wd->lay, part, child, col, row, colspan, rowspan))
734      WRN("child %p could not be packed into box part '%s' col=%uh, row=%hu, "
735          "colspan=%hu, rowspan=%hu", child, part, col, row, colspan, rowspan);
736
737    elm_widget_sub_object_add(obj, child);
738    evas_object_event_callback_add
739       (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, wd);
740
741    si = ELM_NEW(Subinfo);
742    si->type = TABLE_PACK;
743    si->part = eina_stringshare_add(part);
744    si->obj = child;
745    si->p.table.col = col;
746    si->p.table.row = row;
747    si->p.table.colspan = colspan;
748    si->p.table.rowspan = rowspan;
749    wd->subs = eina_list_append(wd->subs, si);
750    _request_sizing_eval(wd);
751
752    return EINA_TRUE;
753 }
754
755 EAPI Evas_Object *
756 elm_layout_table_unpack(Evas_Object *obj, const char *part, Evas_Object *child)
757 {
758    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
759    Widget_Data *wd = elm_widget_data_get(obj);
760    const Eina_List *l;
761    Subinfo *si;
762
763    if (!wd) return NULL;
764
765    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
766    EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
767    EINA_LIST_FOREACH(wd->subs, l, si)
768      {
769         if (si->type != TABLE_PACK) continue;
770         if ((si->obj == child) && (!strcmp(si->part, part)))
771           return _sub_table_remove(wd, si);
772      }
773    return NULL;
774 }
775
776 EAPI Eina_Bool
777 elm_layout_table_clear(Evas_Object *obj, const char *part, Eina_Bool clear)
778 {
779    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
780    Widget_Data *wd = elm_widget_data_get(obj);
781    Subinfo *si;
782    Eina_List *lst;
783
784    if (!wd) return EINA_FALSE;
785    EINA_SAFETY_ON_NULL_RETURN_VAL(part, EINA_FALSE);
786
787    lst = eina_list_clone(wd->subs);
788    EINA_LIST_FREE(lst, si)
789      {
790         if (si->type != TABLE_PACK) continue;
791         if (!strcmp(si->part, part))
792           {
793              Evas_Object *child = _sub_table_remove(wd, si);
794              if ((clear) && (child)) evas_object_del(child);
795           }
796      }
797    /* eventually something may not be added with layout, del them as well */
798    edje_object_part_table_clear(wd->lay, part, clear);
799
800    return EINA_TRUE;
801 }
802
803 EAPI Evas_Object *
804 elm_layout_edje_get(const Evas_Object *obj)
805 {
806    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
807    Widget_Data *wd = elm_widget_data_get(obj);
808    if (!wd) return NULL;
809    return wd->lay;
810 }
811
812 EAPI const char *
813 elm_layout_data_get(const Evas_Object *obj, const char *key)
814 {
815    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
816    Widget_Data *wd = elm_widget_data_get(obj);
817    return edje_object_data_get(wd->lay, key);
818 }
819
820 EAPI void
821 elm_layout_sizing_eval(Evas_Object *obj)
822 {
823    ELM_CHECK_WIDTYPE(obj, widtype);
824    Widget_Data *wd = elm_widget_data_get(obj);
825    EINA_SAFETY_ON_NULL_RETURN(wd);
826    _request_sizing_eval(wd);
827 }
828
829 EAPI Eina_Bool
830 elm_layout_part_cursor_set(Evas_Object *obj, const char *part_name, const char *cursor)
831 {
832    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
833    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
834    Widget_Data *wd = elm_widget_data_get(obj);
835    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
836    Evas_Object *part_obj;
837    Part_Cursor *pc;
838
839    part_obj = (Evas_Object *)edje_object_part_object_get(wd->lay, part_name);
840    if (!part_obj)
841      {
842         const char *group, *file;
843         edje_object_file_get(wd->lay, &file, &group);
844         WRN("no part '%s' in group '%s' of file '%s'. Cannot set cursor '%s'",
845             part_name, group, file, cursor);
846         return EINA_FALSE;
847      }
848    if (evas_object_pass_events_get(part_obj))
849      {
850         const char *group, *file;
851         edje_object_file_get(wd->lay, &file, &group);
852         WRN("part '%s' in group '%s' of file '%s' has mouse_events: 0. "
853             "Cannot set cursor '%s'",
854             part_name, group, file, cursor);
855         return EINA_FALSE;
856      }
857
858    pc = _parts_cursors_find(wd, part_name);
859    if (pc) eina_stringshare_replace(&pc->cursor, cursor);
860    else
861      {
862         pc = calloc(1, sizeof(*pc));
863         pc->part = eina_stringshare_add(part_name);
864         pc->cursor = eina_stringshare_add(cursor);
865         pc->style = eina_stringshare_add("default");
866         wd->parts_cursors = eina_list_append(wd->parts_cursors, pc);
867      }
868
869    pc->obj = part_obj;
870    elm_object_sub_cursor_set(part_obj, obj, pc->cursor);
871    return EINA_TRUE;
872 }
873
874 EAPI const char *
875 elm_layout_part_cursor_get(const Evas_Object *obj, const char *part_name)
876 {
877    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
878    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL);
879    Widget_Data *wd = elm_widget_data_get(obj);
880    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
881    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
882    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL);
883    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL);
884    return elm_object_cursor_get(pc->obj);
885 }
886
887 EAPI Eina_Bool
888 elm_layout_part_cursor_unset(Evas_Object *obj, const char *part_name)
889 {
890    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
891    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
892    Widget_Data *wd = elm_widget_data_get(obj);
893    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
894    Eina_List *l;
895    Part_Cursor *pc;
896
897    EINA_LIST_FOREACH(wd->parts_cursors, l, pc)
898      {
899         if (!strcmp(part_name, pc->part))
900           {
901              if (pc->obj) elm_object_cursor_unset(pc->obj);
902              _part_cursor_free(pc);
903              wd->parts_cursors = eina_list_remove_list(wd->parts_cursors, l);
904              return EINA_TRUE;
905           }
906      }
907
908    return EINA_FALSE;
909 }
910
911 EAPI Eina_Bool
912 elm_layout_part_cursor_style_set(Evas_Object *obj, const char *part_name, const char *style)
913 {
914    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
915    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
916    Widget_Data *wd = elm_widget_data_get(obj);
917    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
918    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
919    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
920    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
921
922    eina_stringshare_replace(&pc->style, style);
923    elm_object_cursor_style_set(pc->obj, pc->style);
924    return EINA_TRUE;
925 }
926
927 EAPI const char *
928 elm_layout_part_cursor_style_get(const Evas_Object *obj, const char *part_name)
929 {
930    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
931    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL);
932    Widget_Data *wd = elm_widget_data_get(obj);
933    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, NULL);
934    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
935    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL);
936    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL);
937    return elm_object_cursor_style_get(pc->obj);
938 }
939
940 EAPI Eina_Bool
941 elm_layout_part_cursor_engine_only_set(Evas_Object *obj, const char *part_name, Eina_Bool engine_only)
942 {
943    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
944    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
945    Widget_Data *wd = elm_widget_data_get(obj);
946    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
947    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
948    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
949    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
950
951    pc->engine_only = !!engine_only;
952    elm_object_cursor_theme_search_enabled_set(pc->obj, pc->engine_only);
953    return EINA_TRUE;
954 }
955
956 EAPI Eina_Bool
957 elm_layout_part_cursor_engine_only_get(const Evas_Object *obj, const char *part_name)
958 {
959    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
960    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
961    Widget_Data *wd = elm_widget_data_get(obj);
962    EINA_SAFETY_ON_NULL_RETURN_VAL(wd, EINA_FALSE);
963    Part_Cursor *pc = _parts_cursors_find(wd, part_name);
964    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
965    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
966    return elm_object_cursor_theme_search_enabled_get(pc->obj);
967 }