elementary/map - map supports language,changed
[framework/uifw/elementary.git] / src / lib / elm_layout.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_layout.h"
4
5 EAPI const char ELM_LAYOUT_SMART_NAME[] = "elm_layout";
6
7 static const char SIG_THEME_CHANGED[] = "theme,changed";
8
9 /* no *direct* instantiation of this class, so far */
10 __UNUSED__ static Evas_Smart *_elm_layout_smart_class_new(void);
11
12 /* smart callbacks coming from elm layout objects: */
13 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
14    {SIG_THEME_CHANGED, ""},
15    {NULL, NULL}
16 };
17
18 /* these are data operated by layout's class functions internally, and
19  * should not be messed up by inhering classes */
20 typedef struct _Elm_Layout_Sub_Object_Data   Elm_Layout_Sub_Object_Data;
21 typedef struct _Elm_Layout_Sub_Object_Cursor Elm_Layout_Sub_Object_Cursor;
22
23 struct _Elm_Layout_Sub_Object_Data
24 {
25    const char  *part;
26    Evas_Object *obj;
27
28    enum {
29       SWALLOW,
30       BOX_APPEND,
31       BOX_PREPEND,
32       BOX_INSERT_BEFORE,
33       BOX_INSERT_AT,
34       TABLE_PACK,
35       TEXT
36    } type;
37
38    union {
39       union {
40          const Evas_Object *reference;
41          unsigned int       pos;
42       } box;
43       struct
44       {
45          unsigned short col, row, colspan, rowspan;
46       } table;
47       struct
48       {
49          const char *text;
50       } text;
51    } p;
52 };
53
54 struct _Elm_Layout_Sub_Object_Cursor
55 {
56    Evas_Object *obj;
57    const char  *part;
58    const char  *cursor;
59    const char  *style;
60
61    Eina_Bool    engine_only : 1;
62 };
63
64 /* layout's sizing evaluation is deferred. evaluation requests are
65  * queued up and only flag the object as 'changed'. when it comes to
66  * Evas's rendering phase, it will be addressed, finally (see
67  * _elm_layout_smart_calculate()). */
68 static void
69 _elm_layout_smart_sizing_eval(Evas_Object *obj)
70 {
71    ELM_LAYOUT_DATA_GET(obj, sd);
72
73    if (sd->needs_size_calc) return;
74    sd->needs_size_calc = EINA_TRUE;
75
76    evas_object_smart_changed(obj);
77 }
78
79 static void
80 _on_sub_object_size_hint_change(void *data,
81                                 Evas *e __UNUSED__,
82                                 Evas_Object *obj __UNUSED__,
83                                 void *event_info __UNUSED__)
84 {
85    ELM_LAYOUT_DATA_GET(data, sd);
86    if (ELM_WIDGET_DATA(sd)->frozen) return;
87    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(data);
88 }
89
90 static void
91 _part_cursor_free(Elm_Layout_Sub_Object_Cursor *pc)
92 {
93    eina_stringshare_del(pc->part);
94    eina_stringshare_del(pc->style);
95    eina_stringshare_del(pc->cursor);
96
97    free(pc);
98 }
99
100 /* Elementary smart class for all widgets having an Edje layout as a
101  * building block */
102 EVAS_SMART_SUBCLASS_NEW
103   (ELM_LAYOUT_SMART_NAME, _elm_layout, Elm_Layout_Smart_Class,
104   Elm_Container_Smart_Class, elm_container_smart_class_get, _smart_callbacks);
105
106 EAPI const Elm_Layout_Smart_Class *
107 elm_layout_smart_class_get(void)
108 {
109    static Elm_Layout_Smart_Class _sc =
110      ELM_LAYOUT_SMART_CLASS_INIT_NAME_VERSION(ELM_LAYOUT_SMART_NAME);
111    static const Elm_Layout_Smart_Class *class = NULL;
112    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
113
114    if (class)
115      return class;
116
117    _elm_layout_smart_set(&_sc);
118    esc->callbacks = _smart_callbacks;
119    class = &_sc;
120
121    return class;
122 }
123
124 static void
125 _sizing_eval(Evas_Object *obj, Elm_Layout_Smart_Data *sd)
126 {
127    Evas_Coord minw = -1, minh = -1;
128
129    edje_object_size_min_calc(ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh);
130    evas_object_size_hint_min_set(obj, minw, minh);
131    evas_object_size_hint_max_set(obj, -1, -1);
132 }
133
134 /* common content cases for layout objects: icon and text */
135 static inline void
136 _icon_signal_emit(Elm_Layout_Smart_Data *sd,
137                   Elm_Layout_Sub_Object_Data *sub_d,
138                   Eina_Bool visible)
139 {
140    char buf[1024];
141    const char *type;
142
143    if (sub_d->type != SWALLOW ||
144        (strcmp("elm.swallow.icon", sub_d->part) &&
145         (strcmp("elm.swallow.end", sub_d->part))))
146      return;
147
148    if (strncmp(sub_d->part, "elm.swallow.", sizeof("elm.swallow.") - 1) == 0)
149      type = sub_d->part + sizeof("elm.swallow.") - 1;
150    else
151      type = sub_d->part;
152
153    snprintf(buf, sizeof(buf), "elm,state,%s,%s", type,
154             visible ? "visible" : "hidden");
155
156    edje_object_signal_emit(ELM_WIDGET_DATA(sd)->resize_obj, buf, "elm");
157
158    /* themes might need imediate action here */
159    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
160 }
161
162 static inline void
163 _text_signal_emit(Elm_Layout_Smart_Data *sd,
164                   Elm_Layout_Sub_Object_Data *sub_d,
165                   Eina_Bool visible)
166 {
167    char buf[1024];
168    const char *type;
169
170    if (sub_d->type != TEXT || strcmp("elm.text", sub_d->part))
171      return;
172
173    if (strncmp(sub_d->part, "elm.text.", sizeof("elm.text.") - 1) == 0)
174      type = sub_d->part + sizeof("elm.text.") - 1;
175    else
176      type = sub_d->part;
177
178    snprintf(buf, sizeof(buf), "elm,state,%s,%s", type,
179             visible ? "visible" : "hidden");
180    edje_object_signal_emit(ELM_WIDGET_DATA(sd)->resize_obj, buf, "elm");
181
182    /* TODO: is this right? It was like that, but IMO it should be removed: */
183    snprintf(buf, sizeof(buf),
184             visible ? "elm,state,text,visible" : "elm,state,text,hidden");
185
186    edje_object_signal_emit(ELM_WIDGET_DATA(sd)->resize_obj, buf, "elm");
187
188    /* themes might need imediate action here */
189    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
190 }
191
192 static void
193 _parts_signals_emit(Elm_Layout_Smart_Data *sd)
194 {
195    const Eina_List *l;
196    Elm_Layout_Sub_Object_Data *sub_d;
197
198    EINA_LIST_FOREACH(sd->subs, l, sub_d)
199      {
200         _icon_signal_emit(sd, sub_d, EINA_TRUE);
201         _text_signal_emit(sd, sub_d, EINA_TRUE);
202      }
203 }
204
205 static void
206 _parts_text_fix(Elm_Layout_Smart_Data *sd)
207 {
208    const Eina_List *l;
209    Elm_Layout_Sub_Object_Data *sub_d;
210
211    EINA_LIST_FOREACH(sd->subs, l, sub_d)
212      {
213         if (sub_d->type == TEXT)
214           {
215              edje_object_part_text_escaped_set
216                (ELM_WIDGET_DATA(sd)->resize_obj, sub_d->part,
217                sub_d->p.text.text);
218           }
219      }
220 }
221
222 static void
223 _part_cursor_part_apply(const Elm_Layout_Sub_Object_Cursor *pc)
224 {
225    elm_object_cursor_set(pc->obj, pc->cursor);
226    elm_object_cursor_style_set(pc->obj, pc->style);
227    elm_object_cursor_theme_search_enabled_set(pc->obj, pc->engine_only);
228 }
229
230 static void
231 _parts_cursors_apply(Elm_Layout_Smart_Data *sd)
232 {
233    const Eina_List *l;
234    const char *file, *group;
235    Elm_Layout_Sub_Object_Cursor *pc;
236
237    edje_object_file_get(ELM_WIDGET_DATA(sd)->resize_obj, &file, &group);
238
239    EINA_LIST_FOREACH(sd->parts_cursors, l, pc)
240      {
241         Evas_Object *obj = (Evas_Object *)edje_object_part_object_get
242             (ELM_WIDGET_DATA(sd)->resize_obj, 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 _reload_theme(void *data, Evas_Object *obj,
268               const char *emission __UNUSED__, const char *source __UNUSED__)
269 {
270    Evas_Object *layout = data;
271    const char *file;
272    const char *group;
273
274    edje_object_file_get(obj, &file, &group);
275    elm_layout_file_set(layout, file, group);
276 }
277
278 static void
279 _visuals_refresh(Evas_Object *obj,
280                  Elm_Layout_Smart_Data *sd)
281 {
282    _parts_text_fix(sd);
283    _parts_signals_emit(sd);
284    _parts_cursors_apply(sd);
285
286    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
287
288    edje_object_signal_callback_del(ELM_WIDGET_DATA(sd)->resize_obj,
289                                    "edje,change,file", "edje",
290                                    _reload_theme);
291    edje_object_signal_callback_add(ELM_WIDGET_DATA(sd)->resize_obj,
292                                    "edje,change,file", "edje",
293                                    _reload_theme, obj);
294 }
295
296 static Eina_Bool
297 _elm_layout_smart_disable(Evas_Object *obj)
298 {
299    ELM_LAYOUT_DATA_GET(obj, sd);
300
301    if (elm_object_disabled_get(obj))
302      edje_object_signal_emit
303        (ELM_WIDGET_DATA(sd)->resize_obj, "elm,state,disabled", "elm");
304    else
305      edje_object_signal_emit
306        (ELM_WIDGET_DATA(sd)->resize_obj, "elm,state,enabled", "elm");
307
308    return EINA_TRUE;
309 }
310
311 static Eina_Bool
312 _elm_layout_smart_theme(Evas_Object *obj)
313 {
314    Eina_Bool ret;
315    const char *fh;
316
317    ELM_LAYOUT_DATA_GET(obj, sd);
318
319    if (!ELM_WIDGET_CLASS(_elm_layout_parent_sc)->theme(obj)) return EINA_FALSE;
320
321    /* function already prints error messages, if any */
322    ret = elm_widget_theme_object_set
323        (obj, ELM_WIDGET_DATA(sd)->resize_obj, sd->klass, sd->group,
324        elm_widget_style_get(obj));
325
326    edje_object_mirrored_set
327      (ELM_WIDGET_DATA(sd)->resize_obj, elm_widget_mirrored_get(obj));
328
329    edje_object_scale_set
330      (ELM_WIDGET_DATA(sd)->resize_obj,
331      elm_widget_scale_get(obj) * elm_config_scale_get());
332
333    fh = edje_object_data_get
334        (ELM_WIDGET_DATA(sd)->resize_obj, "focus_highlight");
335    if ((fh) && (!strcmp(fh, "on")))
336      elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
337    else
338      elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
339
340    evas_object_smart_callback_call(obj, SIG_THEME_CHANGED, NULL);
341
342    _visuals_refresh(obj, sd);
343
344    return ret;
345 }
346
347 static void *
348 _elm_layout_list_data_get(const Eina_List *list)
349 {
350    Elm_Layout_Sub_Object_Data *sub_d = eina_list_data_get(list);
351
352    return sub_d->obj;
353 }
354
355 static Eina_Bool
356 _elm_layout_smart_on_focus(Evas_Object *obj)
357 {
358    ELM_LAYOUT_DATA_GET(obj, sd);
359
360    if (elm_widget_focus_get(obj))
361      {
362         elm_layout_signal_emit(obj, "elm,action,focus", "elm");
363         evas_object_focus_set(ELM_WIDGET_DATA(sd)->resize_obj, EINA_TRUE);
364      }
365    else
366      {
367         elm_layout_signal_emit(obj, "elm,action,unfocus", "elm");
368         evas_object_focus_set(ELM_WIDGET_DATA(sd)->resize_obj, EINA_FALSE);
369      }
370
371    return EINA_TRUE;
372 }
373
374 /* WARNING: if you're making a widget *not* supposed to have focusable
375  * child objects, but still inheriting from elm_layout, just set its
376  * focus_next smart function back to NULL */
377 static Eina_Bool
378 _elm_layout_smart_focus_next(const Evas_Object *obj,
379                              Elm_Focus_Direction dir,
380                              Evas_Object **next)
381 {
382    const Eina_List *items;
383    void *(*list_data_get)(const Eina_List *list);
384
385    ELM_LAYOUT_DATA_GET(obj, sd);
386
387    if ((items = elm_widget_focus_custom_chain_get(obj)))
388      list_data_get = eina_list_data_get;
389    else
390      {
391         items = sd->subs;
392         list_data_get = _elm_layout_list_data_get;
393
394         if (!items) return EINA_FALSE;
395      }
396
397    return elm_widget_focus_list_next_get
398             (obj, items, list_data_get, dir, next);
399 }
400
401 static Eina_Bool
402 _elm_layout_smart_sub_object_add(Evas_Object *obj,
403                                  Evas_Object *sobj)
404 {
405    if (evas_object_data_get(sobj, "elm-parent") == obj)
406      return EINA_TRUE;
407
408    if (!ELM_WIDGET_CLASS(_elm_layout_parent_sc)->sub_object_add(obj, sobj))
409      return EINA_FALSE;
410
411    evas_object_event_callback_add
412      (sobj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
413      _on_sub_object_size_hint_change, obj);
414
415    return EINA_TRUE;
416 }
417
418 static Eina_Bool
419 _elm_layout_smart_sub_object_del(Evas_Object *obj,
420                                  Evas_Object *sobj)
421 {
422    Eina_List *l;
423    Elm_Layout_Sub_Object_Data *sub_d;
424
425    ELM_LAYOUT_DATA_GET(obj, sd);
426
427    evas_object_event_callback_del_full
428      (sobj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
429      _on_sub_object_size_hint_change, obj);
430
431    if (!ELM_WIDGET_CLASS(_elm_layout_parent_sc)->sub_object_del(obj, sobj))
432      return EINA_FALSE;
433
434    EINA_LIST_FOREACH(sd->subs, l, sub_d)
435      {
436         if (sub_d->obj != sobj) continue;
437
438         sd->subs = eina_list_remove_list(sd->subs, l);
439
440         _icon_signal_emit(sd, sub_d, EINA_FALSE);
441
442         eina_stringshare_del(sub_d->part);
443         free(sub_d);
444
445         break;
446      }
447
448    if (ELM_WIDGET_DATA(sd)->frozen) return EINA_TRUE;
449    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
450
451    return EINA_TRUE;
452 }
453
454 static Eina_Bool
455 _elm_layout_smart_focus_direction(const Evas_Object *obj,
456                                   const Evas_Object *base,
457                                   double degree,
458                                   Evas_Object **direction,
459                                   double *weight)
460 {
461    const Eina_List *items;
462    void *(*list_data_get)(const Eina_List *list);
463
464    ELM_LAYOUT_DATA_GET(obj, sd);
465
466    if (!sd->subs) return EINA_FALSE;
467
468    /* Focus chain (This block is diferent of elm_win cycle) */
469    if ((items = elm_widget_focus_custom_chain_get(obj)))
470      list_data_get = eina_list_data_get;
471    else
472      {
473         items = sd->subs;
474         list_data_get = _elm_layout_list_data_get;
475
476         if (!items) return EINA_FALSE;
477      }
478
479    return elm_widget_focus_list_direction_get
480             (obj, base, items, list_data_get, degree, direction, weight);
481 }
482
483 static void
484 _elm_layout_smart_signal(Evas_Object *obj,
485                          const char *emission,
486                          const char *source)
487 {
488    ELM_LAYOUT_DATA_GET(obj, sd);
489
490    edje_object_signal_emit(ELM_WIDGET_DATA(sd)->resize_obj, emission, source);
491 }
492
493 static void
494 _edje_signal_callback(void *data,
495                       Evas_Object *obj __UNUSED__,
496                       const char *emission,
497                       const char *source)
498 {
499    Edje_Signal_Data *esd = data;
500
501    esd->func(esd->data, esd->obj, emission, source);
502 }
503
504 static void
505 _elm_layout_smart_callback_add(Evas_Object *obj,
506                                const char *emission,
507                                const char *source,
508                                Edje_Signal_Cb func_cb,
509                                void *data)
510 {
511    Edje_Signal_Data *esd;
512
513    ELM_LAYOUT_DATA_GET(obj, sd);
514
515    esd = ELM_NEW(Edje_Signal_Data);
516    if (!esd) return;
517
518    esd->obj = obj;
519    esd->func = func_cb;
520    esd->emission = eina_stringshare_add(emission);
521    esd->source = eina_stringshare_add(source);
522    esd->data = data;
523    sd->edje_signals = eina_list_append(sd->edje_signals, esd);
524
525    edje_object_signal_callback_add
526      (ELM_WIDGET_DATA(sd)->resize_obj, emission, source,
527      _edje_signal_callback, esd);
528 }
529
530 static void *
531 _elm_layout_smart_callback_del(Evas_Object *obj,
532                                const char *emission,
533                                const char *source,
534                                Edje_Signal_Cb func_cb)
535 {
536    Edje_Signal_Data *esd = NULL;
537    void *data = NULL;
538    Eina_List *l;
539
540    ELM_LAYOUT_DATA_GET(obj, sd);
541
542    EINA_LIST_FOREACH(sd->edje_signals, l, esd)
543      {
544         if ((esd->func == func_cb) && (!strcmp(esd->emission, emission)) &&
545             (!strcmp(esd->source, source)))
546           {
547              sd->edje_signals = eina_list_remove_list(sd->edje_signals, l);
548              eina_stringshare_del(esd->emission);
549              eina_stringshare_del(esd->source);
550              data = esd->data;
551              free(esd);
552
553              edje_object_signal_callback_del_full
554                (ELM_WIDGET_DATA(sd)->resize_obj, emission, source,
555                _edje_signal_callback, esd);
556
557              return data; /* stop at 1st match */
558           }
559      }
560
561    return data;
562 }
563
564 static Eina_Bool
565 _elm_layout_part_aliasing_eval(Elm_Layout_Smart_Data *sd,
566                                const char **part,
567                                Eina_Bool is_text)
568 {
569 #define ALIAS_LIST(_sd, _list) \
570   ((ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(_sd)->api))->_list)
571
572    const Elm_Layout_Part_Alias_Description *aliases = is_text ?
573      ALIAS_LIST(sd, text_aliases) : ALIAS_LIST(sd, content_aliases);
574
575 #undef ALIAS_LIST
576
577    if (!aliases && !*part) return EINA_FALSE;
578    if (!aliases) return EINA_TRUE;
579
580    while (aliases->alias && aliases->real_part)
581      {
582         /* NULL matches the 1st */
583         if ((!*part) || (!strcmp(*part, aliases->alias)))
584           {
585              *part = aliases->real_part;
586              break;
587           }
588
589         aliases++;
590      }
591
592    if (!*part)
593      {
594         ERR("no default content part set for object %p -- "
595             "part must not be NULL", ELM_WIDGET_DATA(sd)->obj);
596         return EINA_FALSE;
597      }
598
599    /* if no match, part goes on with the same value */
600
601    return EINA_TRUE;
602 }
603
604 static Eina_Bool
605 _elm_layout_smart_text_set(Evas_Object *obj,
606                            const char *part,
607                            const char *text)
608 {
609    Eina_List *l;
610    Elm_Layout_Sub_Object_Data *sub_d = NULL;
611
612    ELM_LAYOUT_DATA_GET(obj, sd);
613
614    if (!_elm_layout_part_aliasing_eval(sd, &part, EINA_TRUE))
615      return EINA_FALSE;
616
617    EINA_LIST_FOREACH(sd->subs, l, sub_d)
618      {
619         if ((sub_d->type == TEXT) && (!strcmp(part, sub_d->part)))
620           {
621              if (!text)
622                {
623                   eina_stringshare_del(sub_d->part);
624                   eina_stringshare_del(sub_d->p.text.text);
625                   free(sub_d);
626                   edje_object_part_text_escaped_set
627                     (ELM_WIDGET_DATA(sd)->resize_obj, part, NULL);
628                   sd->subs = eina_list_remove_list(sd->subs, l);
629                   return EINA_TRUE;
630                }
631              else
632                break;
633           }
634         sub_d = NULL;
635      }
636
637    if (!edje_object_part_text_escaped_set
638          (ELM_WIDGET_DATA(sd)->resize_obj, part, text))
639      return EINA_FALSE;
640
641    if (!sub_d)
642      {
643         sub_d = ELM_NEW(Elm_Layout_Sub_Object_Data);
644         if (!sub_d) return EINA_FALSE;
645         sub_d->type = TEXT;
646         sub_d->part = eina_stringshare_add(part);
647         sd->subs = eina_list_append(sd->subs, sub_d);
648      }
649
650    eina_stringshare_replace(&sub_d->p.text.text, text);
651
652    _text_signal_emit(sd, sub_d, !!text);
653
654    if (!ELM_WIDGET_DATA(sd)->frozen)
655      {
656         ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
657      }
658
659    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON &&
660        ELM_WIDGET_DATA(sd)->can_access && !(sub_d->obj))
661      sub_d->obj = _elm_access_edje_object_part_object_register
662          (obj, elm_layout_edje_get(obj), part);
663
664    return EINA_TRUE;
665 }
666
667 static const char *
668 _elm_layout_smart_text_get(const Evas_Object *obj,
669                            const char *part)
670 {
671    ELM_LAYOUT_DATA_GET(obj, sd);
672
673    if (!_elm_layout_part_aliasing_eval(sd, &part, EINA_TRUE))
674      return EINA_FALSE;
675
676    return edje_object_part_text_get(ELM_WIDGET_DATA(sd)->resize_obj, part);
677 }
678
679 static Eina_Bool
680 _elm_layout_smart_content_set(Evas_Object *obj,
681                               const char *part,
682                               Evas_Object *content)
683 {
684    Elm_Layout_Sub_Object_Data *sub_d;
685    const Eina_List *l;
686
687    ELM_LAYOUT_DATA_GET(obj, sd);
688
689    if (!_elm_layout_part_aliasing_eval(sd, &part, EINA_FALSE))
690      return EINA_FALSE;
691
692    EINA_LIST_FOREACH(sd->subs, l, sub_d)
693      {
694         if ((sub_d->type == SWALLOW))
695           {
696              if (!strcmp(part, sub_d->part))
697                {
698                   if (content == sub_d->obj) return EINA_TRUE;
699                   evas_object_del(sub_d->obj);
700                   break;
701                }
702              /* was previously swallowed at another part -- mimic
703               * edje_object_part_swallow()'s behavior, then */
704              else if (content == sub_d->obj)
705                {
706                   elm_widget_sub_object_del(obj, content);
707                   break;
708                }
709           }
710      }
711
712    if (content)
713      {
714         if (!elm_widget_sub_object_add(obj, content))
715           {
716              ERR("could not add %p as sub object of %p", content, obj);
717              return EINA_FALSE;
718           }
719
720         if (!edje_object_part_swallow
721               (ELM_WIDGET_DATA(sd)->resize_obj, part, content))
722           {
723              ERR("could not swallow %p into part '%s'", content, part);
724              return EINA_FALSE;
725           }
726
727         sub_d = ELM_NEW(Elm_Layout_Sub_Object_Data);
728         sub_d->type = SWALLOW;
729         sub_d->part = eina_stringshare_add(part);
730         sub_d->obj = content;
731         sd->subs = eina_list_append(sd->subs, sub_d);
732
733         _icon_signal_emit(sd, sub_d, EINA_TRUE);
734      }
735
736    if (ELM_WIDGET_DATA(sd)->frozen) return EINA_TRUE;
737    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
738
739    return EINA_TRUE;
740 }
741
742 static Evas_Object *
743 _elm_layout_smart_content_get(const Evas_Object *obj,
744                               const char *part)
745 {
746    const Eina_List *l;
747    Elm_Layout_Sub_Object_Data *sub_d;
748
749    ELM_LAYOUT_DATA_GET(obj, sd);
750
751    if (!_elm_layout_part_aliasing_eval(sd, &part, EINA_FALSE))
752      return EINA_FALSE;
753
754    EINA_LIST_FOREACH(sd->subs, l, sub_d)
755      {
756         if ((sub_d->type == SWALLOW) && !strcmp(part, sub_d->part))
757           return sub_d->obj;
758      }
759    return NULL;
760 }
761
762 static Evas_Object *
763 _elm_layout_smart_content_unset(Evas_Object *obj,
764                                 const char *part)
765 {
766    Elm_Layout_Sub_Object_Data *sub_d;
767    const Eina_List *l;
768
769    ELM_LAYOUT_DATA_GET(obj, sd);
770
771    if (!_elm_layout_part_aliasing_eval(sd, &part, EINA_FALSE))
772      return EINA_FALSE;
773
774    EINA_LIST_FOREACH(sd->subs, l, sub_d)
775      {
776         if ((sub_d->type == SWALLOW) && (!strcmp(part, sub_d->part)))
777           {
778              Evas_Object *content;
779
780              if (!sub_d->obj) return NULL;
781
782              content = sub_d->obj; /* sub_d will die in
783                                     * _elm_layout_smart_sub_object_del */
784
785              if (!elm_widget_sub_object_del(obj, content))
786                {
787                   ERR("could not remove sub object %p from %p", content, obj);
788                   return NULL;
789                }
790
791              edje_object_part_unswallow
792                (ELM_WIDGET_DATA(sd)->resize_obj, content);
793              return content;
794           }
795      }
796
797    return NULL;
798 }
799
800 static Eina_Bool
801 _elm_layout_smart_box_append(Evas_Object *obj,
802                              const char *part,
803                              Evas_Object *child)
804 {
805    Elm_Layout_Sub_Object_Data *sub_d;
806
807    ELM_LAYOUT_DATA_GET(obj, sd);
808
809    if (!edje_object_part_box_append
810          (ELM_WIDGET_DATA(sd)->resize_obj, part, child))
811      {
812         ERR("child %p could not be appended to box part '%s'", child, part);
813         return EINA_FALSE;
814      }
815
816    if (!elm_widget_sub_object_add(obj, child))
817      {
818         ERR("could not add %p as sub object of %p", child, obj);
819         edje_object_part_box_remove
820           (ELM_WIDGET_DATA(sd)->resize_obj, part, child);
821         return EINA_FALSE;
822      }
823
824    sub_d = ELM_NEW(Elm_Layout_Sub_Object_Data);
825    sub_d->type = BOX_APPEND;
826    sub_d->part = eina_stringshare_add(part);
827    sub_d->obj = child;
828    sd->subs = eina_list_append(sd->subs, sub_d);
829
830    if (ELM_WIDGET_DATA(sd)->frozen) return EINA_TRUE;
831    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
832
833    return EINA_TRUE;
834 }
835
836 static Eina_Bool
837 _elm_layout_smart_box_prepend(Evas_Object *obj,
838                               const char *part,
839                               Evas_Object *child)
840 {
841    Elm_Layout_Sub_Object_Data *sub_d;
842
843    ELM_LAYOUT_DATA_GET(obj, sd);
844
845    if (!edje_object_part_box_prepend
846          (ELM_WIDGET_DATA(sd)->resize_obj, part, child))
847      {
848         ERR("child %p could not be prepended to box part '%s'", child, part);
849         return EINA_FALSE;
850      }
851
852    if (!elm_widget_sub_object_add(obj, child))
853      {
854         ERR("could not add %p as sub object of %p", child, obj);
855         edje_object_part_box_remove
856           (ELM_WIDGET_DATA(sd)->resize_obj, part, child);
857         return EINA_FALSE;
858      }
859
860    sub_d = ELM_NEW(Elm_Layout_Sub_Object_Data);
861    sub_d->type = BOX_PREPEND;
862    sub_d->part = eina_stringshare_add(part);
863    sub_d->obj = child;
864    sd->subs = eina_list_prepend(sd->subs, sub_d);
865
866    if (ELM_WIDGET_DATA(sd)->frozen) return EINA_TRUE;
867    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
868
869    return EINA_TRUE;
870 }
871
872 static void
873 _box_reference_del(void *data,
874                    Evas *e __UNUSED__,
875                    Evas_Object *obj __UNUSED__,
876                    void *event_info __UNUSED__)
877 {
878    Elm_Layout_Sub_Object_Data *sub_d = data;
879    sub_d->p.box.reference = NULL;
880 }
881
882 static Eina_Bool
883 _elm_layout_smart_box_insert_before(Evas_Object *obj,
884                                     const char *part,
885                                     Evas_Object *child,
886                                     const Evas_Object *reference)
887 {
888    Elm_Layout_Sub_Object_Data *sub_d;
889
890    ELM_LAYOUT_DATA_GET(obj, sd);
891
892    if (!edje_object_part_box_insert_before
893          (ELM_WIDGET_DATA(sd)->resize_obj, part, child, reference))
894      {
895         ERR("child %p could not be inserted before %p inf box part '%s'",
896             child, reference, part);
897         return EINA_FALSE;
898      }
899
900    if (!elm_widget_sub_object_add(obj, child))
901      {
902         ERR("could not add %p as sub object of %p", child, obj);
903         edje_object_part_box_remove
904           (ELM_WIDGET_DATA(sd)->resize_obj, part, child);
905         return EINA_FALSE;
906      }
907
908    sub_d = ELM_NEW(Elm_Layout_Sub_Object_Data);
909    sub_d->type = BOX_INSERT_BEFORE;
910    sub_d->part = eina_stringshare_add(part);
911    sub_d->obj = child;
912    sub_d->p.box.reference = reference;
913    sd->subs = eina_list_append(sd->subs, sub_d);
914
915    evas_object_event_callback_add
916      ((Evas_Object *)reference, EVAS_CALLBACK_DEL, _box_reference_del, sub_d);
917
918    if (ELM_WIDGET_DATA(sd)->frozen) return EINA_TRUE;
919    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
920
921    return EINA_TRUE;
922 }
923
924 static Eina_Bool
925 _elm_layout_smart_box_insert_at(Evas_Object *obj,
926                                 const char *part,
927                                 Evas_Object *child,
928                                 unsigned int pos)
929 {
930    Elm_Layout_Sub_Object_Data *sub_d;
931
932    ELM_LAYOUT_DATA_GET(obj, sd);
933
934    if (!edje_object_part_box_insert_at
935          (ELM_WIDGET_DATA(sd)->resize_obj, part, child, pos))
936      {
937         ERR("child %p could not be inserted at %u to box part '%s'",
938             child, pos, part);
939         return EINA_FALSE;
940      }
941
942    if (!elm_widget_sub_object_add(obj, child))
943      {
944         ERR("could not add %p as sub object of %p", child, obj);
945         edje_object_part_box_remove
946           (ELM_WIDGET_DATA(sd)->resize_obj, part, child);
947         return EINA_FALSE;
948      }
949
950    sub_d = ELM_NEW(Elm_Layout_Sub_Object_Data);
951    sub_d->type = BOX_INSERT_AT;
952    sub_d->part = eina_stringshare_add(part);
953    sub_d->obj = child;
954    sub_d->p.box.pos = pos;
955    sd->subs = eina_list_append(sd->subs, sub_d);
956
957    if (ELM_WIDGET_DATA(sd)->frozen) return EINA_TRUE;
958    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
959
960    return EINA_TRUE;
961 }
962
963 static Evas_Object *
964 _sub_box_remove(Evas_Object *obj,
965                 Elm_Layout_Smart_Data *sd,
966                 Elm_Layout_Sub_Object_Data *sub_d)
967 {
968    Evas_Object *child = sub_d->obj; /* sub_d will die in
969                                      * _elm_layout_smart_sub_object_del */
970
971    if (sub_d->type == BOX_INSERT_BEFORE)
972      evas_object_event_callback_del_full
973        ((Evas_Object *)sub_d->p.box.reference,
974        EVAS_CALLBACK_DEL, _box_reference_del, sub_d);
975
976    edje_object_part_box_remove
977      (ELM_WIDGET_DATA(sd)->resize_obj, sub_d->part, child);
978
979    if (!elm_widget_sub_object_del(obj, child))
980      {
981         ERR("could not remove sub object %p from %p", child, obj);
982         return NULL;
983      }
984
985    return child;
986 }
987
988 static Eina_Bool
989 _sub_box_is(const Elm_Layout_Sub_Object_Data *sub_d)
990 {
991    switch (sub_d->type)
992      {
993       case BOX_APPEND:
994       case BOX_PREPEND:
995       case BOX_INSERT_BEFORE:
996       case BOX_INSERT_AT:
997         return EINA_TRUE;
998
999       default:
1000         return EINA_FALSE;
1001      }
1002 }
1003
1004 static Evas_Object *
1005 _elm_layout_smart_box_remove(Evas_Object *obj,
1006                              const char *part,
1007                              Evas_Object *child)
1008 {
1009    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
1010    EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
1011
1012    ELM_LAYOUT_DATA_GET(obj, sd);
1013
1014    const Eina_List *l;
1015    Elm_Layout_Sub_Object_Data *sub_d;
1016
1017    EINA_LIST_FOREACH(sd->subs, l, sub_d)
1018      {
1019         if (!_sub_box_is(sub_d)) continue;
1020         if ((sub_d->obj == child) && (!strcmp(sub_d->part, part)))
1021           return _sub_box_remove(obj, sd, sub_d);
1022      }
1023
1024    return NULL;
1025 }
1026
1027 static Eina_Bool
1028 _elm_layout_smart_box_remove_all(Evas_Object *obj,
1029                                  const char *part,
1030                                  Eina_Bool clear)
1031 {
1032    EINA_SAFETY_ON_NULL_RETURN_VAL(part, EINA_FALSE);
1033
1034    ELM_LAYOUT_DATA_GET(obj, sd);
1035
1036    Elm_Layout_Sub_Object_Data *sub_d;
1037    Eina_List *lst;
1038
1039    lst = eina_list_clone(sd->subs);
1040    EINA_LIST_FREE (lst, sub_d)
1041      {
1042         if (!_sub_box_is(sub_d)) continue;
1043         if (!strcmp(sub_d->part, part))
1044           {
1045              /* original item's deletion handled at sub-obj-del */
1046              Evas_Object *child = _sub_box_remove(obj, sd, sub_d);
1047              if ((clear) && (child)) evas_object_del(child);
1048           }
1049      }
1050
1051    /* eventually something may not be added with elm_layout, delete them
1052     * as well */
1053    edje_object_part_box_remove_all
1054      (ELM_WIDGET_DATA(sd)->resize_obj, part, clear);
1055
1056    return EINA_TRUE;
1057 }
1058
1059 static Eina_Bool
1060 _elm_layout_smart_table_pack(Evas_Object *obj,
1061                              const char *part,
1062                              Evas_Object *child,
1063                              unsigned short col,
1064                              unsigned short row,
1065                              unsigned short colspan,
1066                              unsigned short rowspan)
1067 {
1068    Elm_Layout_Sub_Object_Data *sub_d;
1069
1070    ELM_LAYOUT_DATA_GET(obj, sd);
1071
1072    if (!edje_object_part_table_pack
1073          (ELM_WIDGET_DATA(sd)->resize_obj, part, child, col,
1074          row, colspan, rowspan))
1075      {
1076         ERR("child %p could not be packed into box part '%s' col=%uh, row=%hu,"
1077             " colspan=%hu, rowspan=%hu", child, part, col, row, colspan,
1078             rowspan);
1079         return EINA_FALSE;
1080      }
1081
1082    if (!elm_widget_sub_object_add(obj, child))
1083      {
1084         ERR("could not add %p as sub object of %p", child, obj);
1085         edje_object_part_table_unpack
1086           (ELM_WIDGET_DATA(sd)->resize_obj, part, child);
1087         return EINA_FALSE;
1088      }
1089
1090    sub_d = ELM_NEW(Elm_Layout_Sub_Object_Data);
1091    sub_d->type = TABLE_PACK;
1092    sub_d->part = eina_stringshare_add(part);
1093    sub_d->obj = child;
1094    sub_d->p.table.col = col;
1095    sub_d->p.table.row = row;
1096    sub_d->p.table.colspan = colspan;
1097    sub_d->p.table.rowspan = rowspan;
1098    sd->subs = eina_list_append(sd->subs, sub_d);
1099
1100    if (ELM_WIDGET_DATA(sd)->frozen) return EINA_TRUE;
1101    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
1102
1103    return EINA_TRUE;
1104 }
1105
1106 static Evas_Object *
1107 _sub_table_remove(Evas_Object *obj,
1108                   Elm_Layout_Smart_Data *sd,
1109                   Elm_Layout_Sub_Object_Data *sub_d)
1110 {
1111    Evas_Object *child;
1112
1113    child = sub_d->obj; /* sub_d will die in _elm_layout_smart_sub_object_del */
1114
1115    edje_object_part_table_unpack
1116      (ELM_WIDGET_DATA(sd)->resize_obj, sub_d->part, child);
1117
1118    if (!elm_widget_sub_object_del(obj, child))
1119      {
1120         ERR("could not remove sub object %p from %p", child, obj);
1121         return NULL;
1122      }
1123
1124    return child;
1125 }
1126
1127 static Evas_Object *
1128 _elm_layout_smart_table_unpack(Evas_Object *obj,
1129                                const char *part,
1130                                Evas_Object *child)
1131 {
1132    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
1133    EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
1134
1135    ELM_LAYOUT_DATA_GET(obj, sd);
1136
1137    const Eina_List *l;
1138    Elm_Layout_Sub_Object_Data *sub_d;
1139
1140    EINA_LIST_FOREACH(sd->subs, l, sub_d)
1141      {
1142         if (sub_d->type != TABLE_PACK) continue;
1143         if ((sub_d->obj == child) && (!strcmp(sub_d->part, part)))
1144           return _sub_table_remove(obj, sd, sub_d);
1145      }
1146
1147    return NULL;
1148 }
1149
1150 static Eina_Bool
1151 _elm_layout_smart_table_clear(Evas_Object *obj,
1152                               const char *part,
1153                               Eina_Bool clear)
1154 {
1155    EINA_SAFETY_ON_NULL_RETURN_VAL(part, EINA_FALSE);
1156    ELM_LAYOUT_DATA_GET(obj, sd);
1157
1158    Elm_Layout_Sub_Object_Data *sub_d;
1159    Eina_List *lst;
1160
1161    lst = eina_list_clone(sd->subs);
1162    EINA_LIST_FREE (lst, sub_d)
1163      {
1164         if (sub_d->type != TABLE_PACK) continue;
1165         if (!strcmp(sub_d->part, part))
1166           {
1167              /* original item's deletion handled at sub-obj-del */
1168              Evas_Object *child = _sub_table_remove(obj, sd, sub_d);
1169              if ((clear) && (child)) evas_object_del(child);
1170           }
1171      }
1172
1173    /* eventually something may not be added with elm_layout, delete them
1174     * as well */
1175    edje_object_part_table_clear(ELM_WIDGET_DATA(sd)->resize_obj, part, clear);
1176
1177    return EINA_TRUE;
1178 }
1179
1180 static void
1181 _on_size_evaluate_signal(void *data,
1182                          Evas_Object *obj __UNUSED__,
1183                          const char *emission __UNUSED__,
1184                          const char *source __UNUSED__)
1185 {
1186    ELM_LAYOUT_DATA_GET(data, sd);
1187    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(data);
1188 }
1189
1190 static void
1191 _elm_layout_smart_add(Evas_Object *obj)
1192 {
1193    EVAS_SMART_DATA_ALLOC(obj, Elm_Layout_Smart_Data);
1194
1195    /* has to be there *before* parent's smart_add() */
1196    ELM_WIDGET_DATA(priv)->resize_obj =
1197      edje_object_add(evas_object_evas_get(obj));
1198
1199    ELM_WIDGET_CLASS(_elm_layout_parent_sc)->base.add(obj);
1200
1201    elm_widget_can_focus_set(obj, EINA_FALSE);
1202
1203    edje_object_signal_callback_add
1204      (ELM_WIDGET_DATA(priv)->resize_obj, "size,eval", "elm",
1205      _on_size_evaluate_signal, obj);
1206
1207    if (ELM_WIDGET_DATA(priv)->frozen) return;
1208    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(priv)->api)->sizing_eval(obj);
1209 }
1210
1211 static void
1212 _elm_layout_smart_del(Evas_Object *obj)
1213 {
1214    Elm_Layout_Sub_Object_Data *sub_d;
1215    Elm_Layout_Sub_Object_Cursor *pc;
1216    Edje_Signal_Data *esd;
1217    Evas_Object *child;
1218    Eina_List *l;
1219
1220    ELM_LAYOUT_DATA_GET(obj, sd);
1221
1222    elm_layout_freeze(obj);
1223
1224    EINA_LIST_FREE (sd->subs, sub_d)
1225      {
1226         eina_stringshare_del(sub_d->part);
1227
1228         if (sub_d->type == TEXT)
1229           eina_stringshare_del(sub_d->p.text.text);
1230
1231         free(sub_d);
1232      }
1233
1234    EINA_LIST_FREE (sd->parts_cursors, pc)
1235      _part_cursor_free(pc);
1236
1237    EINA_LIST_FREE (sd->edje_signals, esd)
1238      {
1239         eina_stringshare_del(esd->emission);
1240         eina_stringshare_del(esd->source);
1241         free(esd);
1242      }
1243
1244    eina_stringshare_del(sd->klass);
1245    eina_stringshare_del(sd->group);
1246
1247    /* let's make our Edje object the *last* to be processed, since it
1248     * may (smart) parent other sub objects here */
1249    EINA_LIST_FOREACH(ELM_WIDGET_DATA(sd)->subobjs, l, child)
1250      {
1251         if (child == ELM_WIDGET_DATA(sd)->resize_obj)
1252           {
1253              ELM_WIDGET_DATA(sd)->subobjs =
1254                eina_list_demote_list(ELM_WIDGET_DATA(sd)->subobjs, l);
1255              break;
1256           }
1257      }
1258
1259    ELM_WIDGET_CLASS(_elm_layout_parent_sc)->base.del(obj);
1260 }
1261
1262 /* rewrite or extend this one on your derived class as to suit your
1263  * needs */
1264 static void
1265 _elm_layout_smart_calculate(Evas_Object *obj)
1266 {
1267    ELM_LAYOUT_DATA_GET(obj, sd);
1268
1269    if (sd->needs_size_calc)
1270      {
1271         _sizing_eval(obj, sd);
1272         sd->needs_size_calc = EINA_FALSE;
1273      }
1274 }
1275
1276 static void
1277 _elm_layout_smart_set_user(Elm_Layout_Smart_Class *sc)
1278 {
1279    ELM_WIDGET_CLASS(sc)->base.add = _elm_layout_smart_add;
1280    ELM_WIDGET_CLASS(sc)->base.del = _elm_layout_smart_del;
1281    ELM_WIDGET_CLASS(sc)->base.calculate = _elm_layout_smart_calculate;
1282
1283    ELM_WIDGET_CLASS(sc)->theme = _elm_layout_smart_theme;
1284    ELM_WIDGET_CLASS(sc)->disable = _elm_layout_smart_disable;
1285    ELM_WIDGET_CLASS(sc)->focus_next = _elm_layout_smart_focus_next;
1286    ELM_WIDGET_CLASS(sc)->focus_direction = _elm_layout_smart_focus_direction;
1287    ELM_WIDGET_CLASS(sc)->on_focus = _elm_layout_smart_on_focus;
1288
1289    ELM_WIDGET_CLASS(sc)->sub_object_add = _elm_layout_smart_sub_object_add;
1290    ELM_WIDGET_CLASS(sc)->sub_object_del = _elm_layout_smart_sub_object_del;
1291
1292    ELM_CONTAINER_CLASS(sc)->content_set = _elm_layout_smart_content_set;
1293    ELM_CONTAINER_CLASS(sc)->content_get = _elm_layout_smart_content_get;
1294    ELM_CONTAINER_CLASS(sc)->content_unset = _elm_layout_smart_content_unset;
1295
1296    sc->sizing_eval = _elm_layout_smart_sizing_eval;
1297    sc->signal = _elm_layout_smart_signal;
1298    sc->callback_add = _elm_layout_smart_callback_add;
1299    sc->callback_del = _elm_layout_smart_callback_del;
1300    sc->text_set = _elm_layout_smart_text_set;
1301    sc->text_get = _elm_layout_smart_text_get;
1302    sc->box_append = _elm_layout_smart_box_append;
1303    sc->box_prepend = _elm_layout_smart_box_prepend;
1304    sc->box_insert_before = _elm_layout_smart_box_insert_before;
1305    sc->box_insert_at = _elm_layout_smart_box_insert_at;
1306    sc->box_remove = _elm_layout_smart_box_remove;
1307    sc->box_remove_all = _elm_layout_smart_box_remove_all;
1308    sc->table_pack = _elm_layout_smart_table_pack;
1309    sc->table_unpack = _elm_layout_smart_table_unpack;
1310    sc->table_clear = _elm_layout_smart_table_clear;
1311 }
1312
1313 static Elm_Layout_Sub_Object_Cursor *
1314 _parts_cursors_find(Elm_Layout_Smart_Data *sd,
1315                     const char *part)
1316 {
1317    const Eina_List *l;
1318    Elm_Layout_Sub_Object_Cursor *pc;
1319
1320    EINA_LIST_FOREACH(sd->parts_cursors, l, pc)
1321      {
1322         if (!strcmp(pc->part, part))
1323           return pc;
1324      }
1325
1326    return NULL;
1327 }
1328
1329 /* The public functions down here are meant to operate on whichever
1330  * widget inheriting from elm_layout */
1331
1332 EAPI Eina_Bool
1333 elm_layout_file_set(Evas_Object *obj,
1334                     const char *file,
1335                     const char *group)
1336 {
1337    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1338    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1339
1340    Eina_Bool ret =
1341      edje_object_file_set(ELM_WIDGET_DATA(sd)->resize_obj, file, group);
1342
1343    if (ret) _visuals_refresh(obj, sd);
1344    else
1345      ERR("failed to set edje file '%s', group '%s': %s",
1346          file, group,
1347          edje_load_error_str
1348            (edje_object_load_error_get(ELM_WIDGET_DATA(sd)->resize_obj)));
1349
1350    return ret;
1351 }
1352
1353 EAPI Eina_Bool
1354 elm_layout_theme_set(Evas_Object *obj,
1355                      const char *klass,
1356                      const char *group,
1357                      const char *style)
1358 {
1359    Eina_Bool ret;
1360
1361    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1362    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1363
1364    eina_stringshare_replace(&(sd->klass), klass);
1365    eina_stringshare_replace(&(sd->group), group);
1366    eina_stringshare_replace(&(ELM_WIDGET_DATA(sd)->style), style);
1367
1368    /* not issuing smart theme directly here, because one may want to
1369       use this function inside a smart theme routine of its own */
1370    ret = elm_widget_theme_object_set
1371        (obj, ELM_WIDGET_DATA(sd)->resize_obj, sd->klass, sd->group,
1372        elm_widget_style_get(obj));
1373    evas_object_smart_callback_call(obj, SIG_THEME_CHANGED, NULL);
1374
1375    return ret;
1376 }
1377
1378 EAPI void
1379 elm_layout_signal_emit(Evas_Object *obj,
1380                        const char *emission,
1381                        const char *source)
1382 {
1383    ELM_LAYOUT_CHECK(obj);
1384    ELM_LAYOUT_DATA_GET_OR_RETURN(obj, sd);
1385
1386    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->signal(obj, emission, source);
1387 }
1388
1389 EAPI void
1390 elm_layout_signal_callback_add(Evas_Object *obj,
1391                                const char *emission,
1392                                const char *source,
1393                                Edje_Signal_Cb func,
1394                                void *data)
1395 {
1396    ELM_LAYOUT_CHECK(obj);
1397    ELM_LAYOUT_DATA_GET_OR_RETURN(obj, sd);
1398
1399    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->callback_add
1400      (obj, emission, source, func, data);
1401 }
1402
1403 EAPI void *
1404 elm_layout_signal_callback_del(Evas_Object *obj,
1405                                const char *emission,
1406                                const char *source,
1407                                Edje_Signal_Cb func)
1408 {
1409    ELM_LAYOUT_CHECK(obj) NULL;
1410    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1411
1412    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->callback_del
1413             (obj, emission, source, func);
1414 }
1415
1416 EAPI Eina_Bool
1417 elm_layout_content_set(Evas_Object *obj,
1418                        const char *swallow,
1419                        Evas_Object *content)
1420 {
1421    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1422    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1423
1424    return ELM_CONTAINER_CLASS(ELM_WIDGET_DATA(sd)->api)->content_set
1425             (obj, swallow, content);
1426 }
1427
1428 EAPI Evas_Object *
1429 elm_layout_content_get(const Evas_Object *obj,
1430                        const char *swallow)
1431 {
1432    ELM_LAYOUT_CHECK(obj) NULL;
1433    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1434
1435    return ELM_CONTAINER_CLASS(ELM_WIDGET_DATA(sd)->api)->content_get
1436             (obj, swallow);
1437 }
1438
1439 EAPI Evas_Object *
1440 elm_layout_content_unset(Evas_Object *obj,
1441                          const char *swallow)
1442 {
1443    ELM_LAYOUT_CHECK(obj) NULL;
1444    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1445
1446    return ELM_CONTAINER_CLASS(ELM_WIDGET_DATA(sd)->api)->content_unset
1447             (obj, swallow);
1448 }
1449
1450 EAPI Eina_Bool
1451 elm_layout_text_set(Evas_Object *obj,
1452                     const char *part,
1453                     const char *text)
1454 {
1455    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1456    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1457
1458    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->text_set
1459             (obj, part, text);
1460 }
1461
1462 EAPI const char *
1463 elm_layout_text_get(const Evas_Object *obj,
1464                     const char *part)
1465 {
1466    ELM_LAYOUT_CHECK(obj) NULL;
1467    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1468
1469    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->text_get(obj, part);
1470 }
1471
1472 EAPI Eina_Bool
1473 elm_layout_box_append(Evas_Object *obj,
1474                       const char *part,
1475                       Evas_Object *child)
1476 {
1477    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1478    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1479    EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
1480
1481    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->box_append
1482             (obj, part, child);
1483 }
1484
1485 EAPI Eina_Bool
1486 elm_layout_box_prepend(Evas_Object *obj,
1487                        const char *part,
1488                        Evas_Object *child)
1489 {
1490    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1491    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1492    EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
1493
1494    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->box_prepend
1495             (obj, part, child);
1496 }
1497
1498 EAPI Eina_Bool
1499 elm_layout_box_insert_before(Evas_Object *obj,
1500                              const char *part,
1501                              Evas_Object *child,
1502                              const Evas_Object *reference)
1503 {
1504    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1505    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1506    EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
1507    EINA_SAFETY_ON_NULL_RETURN_VAL(reference, EINA_FALSE);
1508
1509    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->box_insert_before
1510             (obj, part, child, reference);
1511 }
1512
1513 EAPI Eina_Bool
1514 elm_layout_box_insert_at(Evas_Object *obj,
1515                          const char *part,
1516                          Evas_Object *child,
1517                          unsigned int pos)
1518 {
1519    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1520    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1521    EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
1522
1523    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->box_insert_at
1524             (obj, part, child, pos);
1525 }
1526
1527 EAPI Evas_Object *
1528 elm_layout_box_remove(Evas_Object *obj,
1529                       const char *part,
1530                       Evas_Object *child)
1531 {
1532    ELM_LAYOUT_CHECK(obj) NULL;
1533    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1534
1535    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->box_remove
1536             (obj, part, child);
1537 }
1538
1539 EAPI Eina_Bool
1540 elm_layout_box_remove_all(Evas_Object *obj,
1541                           const char *part,
1542                           Eina_Bool clear)
1543 {
1544    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1545    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1546
1547    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->box_remove_all
1548             (obj, part, clear);
1549 }
1550
1551 EAPI Eina_Bool
1552 elm_layout_table_pack(Evas_Object *obj,
1553                       const char *part,
1554                       Evas_Object *child,
1555                       unsigned short col,
1556                       unsigned short row,
1557                       unsigned short colspan,
1558                       unsigned short rowspan)
1559 {
1560    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1561    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1562
1563    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->table_pack
1564             (obj, part, child, col, row, colspan, rowspan);
1565 }
1566
1567 EAPI Evas_Object *
1568 elm_layout_table_unpack(Evas_Object *obj,
1569                         const char *part,
1570                         Evas_Object *child)
1571 {
1572    ELM_LAYOUT_CHECK(obj) NULL;
1573    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1574
1575    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->table_unpack
1576             (obj, part, child);
1577 }
1578
1579 EAPI Eina_Bool
1580 elm_layout_table_clear(Evas_Object *obj,
1581                        const char *part,
1582                        Eina_Bool clear)
1583 {
1584    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1585    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1586
1587    return ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->table_clear
1588             (obj, part, clear);
1589 }
1590
1591 EAPI Evas_Object *
1592 elm_layout_edje_get(const Evas_Object *obj)
1593 {
1594    ELM_LAYOUT_CHECK(obj) NULL;
1595    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1596
1597    return ELM_WIDGET_DATA(sd)->resize_obj;
1598 }
1599
1600 EAPI const char *
1601 elm_layout_data_get(const Evas_Object *obj,
1602                     const char *key)
1603 {
1604    ELM_LAYOUT_CHECK(obj) NULL;
1605    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1606
1607    return edje_object_data_get(ELM_WIDGET_DATA(sd)->resize_obj, key);
1608 }
1609
1610 EAPI void
1611 elm_layout_sizing_eval(Evas_Object *obj)
1612 {
1613    ELM_LAYOUT_CHECK(obj);
1614    ELM_LAYOUT_DATA_GET(obj, sd);
1615
1616    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
1617 }
1618
1619 EAPI int
1620 elm_layout_freeze(Evas_Object *obj)
1621 {
1622    ELM_LAYOUT_CHECK(obj) 0;
1623    ELM_LAYOUT_DATA_GET(obj, sd);
1624
1625    if ((ELM_WIDGET_DATA(sd)->frozen)++ != 0)
1626      return ELM_WIDGET_DATA(sd)->frozen;
1627
1628    edje_object_freeze(ELM_WIDGET_DATA(sd)->resize_obj);
1629
1630    return 1;
1631 }
1632
1633 EAPI int
1634 elm_layout_thaw(Evas_Object *obj)
1635 {
1636    ELM_LAYOUT_CHECK(obj) 0;
1637    ELM_LAYOUT_DATA_GET(obj, sd);
1638
1639    if (--(ELM_WIDGET_DATA(sd)->frozen) != 0)
1640      return ELM_WIDGET_DATA(sd)->frozen;
1641
1642    edje_object_thaw(ELM_WIDGET_DATA(sd)->resize_obj);
1643
1644    ELM_LAYOUT_CLASS(ELM_WIDGET_DATA(sd)->api)->sizing_eval(obj);
1645
1646    return 0;
1647 }
1648
1649 EAPI Eina_Bool
1650 elm_layout_part_cursor_set(Evas_Object *obj,
1651                            const char *part_name,
1652                            const char *cursor)
1653 {
1654    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1655    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1656    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1657
1658    Evas_Object *part_obj;
1659    Elm_Layout_Sub_Object_Cursor *pc;
1660
1661    part_obj = (Evas_Object *)edje_object_part_object_get
1662        (ELM_WIDGET_DATA(sd)->resize_obj, part_name);
1663    if (!part_obj)
1664      {
1665         const char *group, *file;
1666
1667         edje_object_file_get(ELM_WIDGET_DATA(sd)->resize_obj, &file, &group);
1668         ERR("no part '%s' in group '%s' of file '%s'. Cannot set cursor '%s'",
1669             part_name, group, file, cursor);
1670         return EINA_FALSE;
1671      }
1672    if (evas_object_pass_events_get(part_obj))
1673      {
1674         const char *group, *file;
1675
1676         edje_object_file_get(ELM_WIDGET_DATA(sd)->resize_obj, &file, &group);
1677         ERR("part '%s' in group '%s' of file '%s' has mouse_events: 0. "
1678             "Cannot set cursor '%s'",
1679             part_name, group, file, cursor);
1680         return EINA_FALSE;
1681      }
1682
1683    pc = _parts_cursors_find(sd, part_name);
1684    if (pc) eina_stringshare_replace(&pc->cursor, cursor);
1685    else
1686      {
1687         pc = calloc(1, sizeof(*pc));
1688         pc->part = eina_stringshare_add(part_name);
1689         pc->cursor = eina_stringshare_add(cursor);
1690         pc->style = eina_stringshare_add("default");
1691         sd->parts_cursors = eina_list_append(sd->parts_cursors, pc);
1692      }
1693
1694    pc->obj = part_obj;
1695    elm_object_sub_cursor_set(part_obj, obj, pc->cursor);
1696
1697    return EINA_TRUE;
1698 }
1699
1700 EAPI const char *
1701 elm_layout_part_cursor_get(const Evas_Object *obj,
1702                            const char *part_name)
1703 {
1704    ELM_LAYOUT_CHECK(obj) NULL;
1705    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1706    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL);
1707
1708    Elm_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name);
1709    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL);
1710    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL);
1711
1712    return elm_object_cursor_get(pc->obj);
1713 }
1714
1715 EAPI Eina_Bool
1716 elm_layout_part_cursor_unset(Evas_Object *obj,
1717                              const char *part_name)
1718 {
1719    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1720    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1721    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1722
1723    Eina_List *l;
1724    Elm_Layout_Sub_Object_Cursor *pc;
1725
1726    EINA_LIST_FOREACH(sd->parts_cursors, l, pc)
1727      {
1728         if (!strcmp(part_name, pc->part))
1729           {
1730              if (pc->obj) elm_object_cursor_unset(pc->obj);
1731              _part_cursor_free(pc);
1732              sd->parts_cursors = eina_list_remove_list(sd->parts_cursors, l);
1733              return EINA_TRUE;
1734           }
1735      }
1736
1737    return EINA_FALSE;
1738 }
1739
1740 EAPI Eina_Bool
1741 elm_layout_part_cursor_style_set(Evas_Object *obj,
1742                                  const char *part_name,
1743                                  const char *style)
1744 {
1745    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1746    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1747    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1748
1749    Elm_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name);
1750    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
1751    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
1752
1753    eina_stringshare_replace(&pc->style, style);
1754    elm_object_cursor_style_set(pc->obj, pc->style);
1755
1756    return EINA_TRUE;
1757 }
1758
1759 EAPI const char *
1760 elm_layout_part_cursor_style_get(const Evas_Object *obj,
1761                                  const char *part_name)
1762 {
1763    ELM_LAYOUT_CHECK(obj) NULL;
1764    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
1765    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL);
1766
1767    Elm_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name);
1768    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL);
1769    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL);
1770
1771    return elm_object_cursor_style_get(pc->obj);
1772 }
1773
1774 EAPI Eina_Bool
1775 elm_layout_part_cursor_engine_only_set(Evas_Object *obj,
1776                                        const char *part_name,
1777                                        Eina_Bool engine_only)
1778 {
1779    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1780    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1781    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1782
1783    Elm_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name);
1784    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
1785    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
1786
1787    pc->engine_only = !!engine_only;
1788    elm_object_cursor_theme_search_enabled_set(pc->obj, pc->engine_only);
1789
1790    return EINA_TRUE;
1791 }
1792
1793 EAPI Eina_Bool
1794 elm_layout_part_cursor_engine_only_get(const Evas_Object *obj,
1795                                        const char *part_name)
1796 {
1797    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1798    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1799    EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE);
1800
1801    Elm_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name);
1802    EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE);
1803    EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE);
1804
1805    return elm_object_cursor_theme_search_enabled_get(pc->obj);
1806 }
1807
1808 EVAS_SMART_SUBCLASS_NEW
1809   (ELM_LAYOUT_SMART_NAME, _elm_layout_widget, Elm_Layout_Smart_Class,
1810   Elm_Layout_Smart_Class, elm_layout_smart_class_get, NULL);
1811
1812 static const Elm_Layout_Part_Alias_Description _text_aliases[] =
1813 {
1814    {"default", "elm.text"},
1815    {NULL, NULL}
1816 };
1817
1818 /* the layout widget (not the base layout) has this extra bit */
1819 static void
1820 _elm_layout_widget_smart_set_user(Elm_Layout_Smart_Class *sc)
1821 {
1822    sc->text_aliases = _text_aliases;
1823 }
1824
1825 EAPI Eina_Bool
1826 elm_layout_edje_object_can_access_set(Evas_Object *obj,
1827                                       Eina_Bool can_access)
1828 {
1829    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1830    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1831
1832    ELM_WIDGET_DATA(sd)->can_access = !!can_access;
1833    return EINA_TRUE;
1834 }
1835
1836 EAPI Eina_Bool
1837 elm_layout_edje_object_can_access_get(Evas_Object *obj)
1838 {
1839    ELM_LAYOUT_CHECK(obj) EINA_FALSE;
1840    ELM_LAYOUT_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
1841
1842    return ELM_WIDGET_DATA(sd)->can_access;
1843 }
1844
1845 /* And now the basic layout widget itself */
1846 EAPI Evas_Object *
1847 elm_layout_add(Evas_Object *parent)
1848 {
1849    Evas_Object *obj;
1850
1851    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1852
1853    obj = elm_widget_add(_elm_layout_widget_smart_class_new(), parent);
1854    if (!obj) return NULL;
1855
1856    if (!elm_widget_sub_object_add(parent, obj))
1857      ERR("could not add %p as sub object of %p", obj, parent);
1858
1859    return obj;
1860 }