Edje text: Added edje_object_part_text_append.
[framework/uifw/edje.git] / src / lib / edje_util.c
1 #include "edje_private.h"
2
3 typedef struct _Edje_Box_Layout Edje_Box_Layout;
4 struct _Edje_Box_Layout
5 {
6    EINA_RBTREE;
7    Evas_Object_Box_Layout func;
8    void *(*layout_data_get)(void *);
9    void (*layout_data_free)(void *);
10    void *data;
11    void (*free_data)(void *);
12    char name[];
13 };
14
15 static Eina_Hash *_edje_color_class_hash = NULL;
16 static Eina_Hash *_edje_color_class_member_hash = NULL;
17
18 static Eina_Hash *_edje_text_class_hash = NULL;
19 static Eina_Hash *_edje_text_class_member_hash = NULL;
20
21 static Eina_Rbtree *_edje_box_layout_registry = NULL;
22
23 char *_edje_fontset_append = NULL;
24 FLOAT_T _edje_scale = ZERO;
25 int _edje_freeze_val = 0;
26 int _edje_freeze_calc_count = 0;
27 Eina_List *_edje_freeze_calc_list = NULL;
28
29 typedef struct _Edje_List_Foreach_Data Edje_List_Foreach_Data;
30 struct _Edje_List_Foreach_Data
31 {
32    Eina_List *list;
33 };
34
35 static Eina_Bool _edje_color_class_list_foreach(const Eina_Hash *hash, const void *key, void *data, void *fdata);
36 static Eina_Bool _edje_text_class_list_foreach(const Eina_Hash *hash, const void *key, void *data, void *fdata);
37 static void _edje_object_image_preload_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
38 static void _edje_object_signal_preload_cb(void *data, Evas_Object *obj, const char *emission, const char *source);
39
40 Edje_Real_Part *_edje_real_part_recursive_get_helper(const Edje *ed, char **path);
41
42 /************************** API Routines **************************/
43
44 #define FASTFREEZE 1
45
46 EAPI void
47 edje_freeze(void)
48 {
49 #ifdef FASTFREEZE
50    _edje_freeze_val++;
51    INF("fr ++ ->%i", _edje_freeze_val);
52 #else
53 // FIXME: could just have a global freeze instead of per object
54 // above i tried.. but this broke some things. notable e17's menus. why?
55    Eina_List *l;
56    Evas_Object *data;
57
58    EINA_LIST_FOREACH(_edje_edjes, l, data)
59      edje_object_freeze(data);
60 #endif
61 }
62
63 #ifdef FASTFREEZE
64 static void
65 _edje_thaw_edje(Edje *ed)
66 {
67    unsigned int i;
68
69    for (i = 0; i < ed->table_parts_size; i++)
70      {
71         Edje_Real_Part *rp;
72
73         rp = ed->table_parts[i];
74         if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
75           {
76              Edje *ed2;
77
78              ed2 = _edje_fetch(rp->swallowed_object);
79              if (ed2) _edje_thaw_edje(ed2);
80           }
81      }
82    if ((ed->recalc) && (ed->freeze <= 0)) _edje_recalc_do(ed);
83 }
84 #endif
85
86 EAPI void
87 edje_thaw(void)
88 {
89 #ifdef FASTFREEZE
90    _edje_freeze_val--;
91    INF("fr -- ->%i", _edje_freeze_val);
92    if ((_edje_freeze_val <= 0) && (_edje_freeze_calc_count > 0))
93      {
94         Edje *ed;
95
96         _edje_freeze_calc_count = 0;
97         EINA_LIST_FREE(_edje_freeze_calc_list, ed)
98           {
99              _edje_thaw_edje(ed);
100              ed->freeze_calc = 0;
101           }
102      }
103 #else
104   Evas_Object *data;
105
106 // FIXME: could just have a global freeze instead of per object
107 // comment as above.. why?
108    Eina_List *l;
109
110    EINA_LIST_FOREACH(_edje_edjes, l, data)
111      edje_object_thaw(data);
112 #endif
113 }
114
115 EAPI void
116 edje_fontset_append_set(const char *fonts)
117 {
118    if (_edje_fontset_append)
119      free(_edje_fontset_append);
120    _edje_fontset_append = fonts ? strdup(fonts) : NULL;
121 }
122
123 EAPI const char *
124 edje_fontset_append_get(void)
125 {
126    return _edje_fontset_append;
127 }
128
129 EAPI void
130 edje_scale_set(double scale)
131 {
132    Eina_List *l;
133    Evas_Object *data;
134
135    if (_edje_scale == FROM_DOUBLE(scale)) return;
136    _edje_scale = FROM_DOUBLE(scale);
137    EINA_LIST_FOREACH(_edje_edjes, l, data)
138      edje_object_calc_force(data);
139 }
140
141 EAPI double
142 edje_scale_get(void)
143 {
144   return TO_DOUBLE(_edje_scale);
145 }
146
147 EAPI Eina_Bool
148 edje_object_scale_set(Evas_Object *obj, double scale)
149 {
150    Edje *ed;
151
152    ed = _edje_fetch(obj);
153    if (!ed) return EINA_FALSE;
154    if (ed->scale == scale) return EINA_TRUE;
155    ed->scale = FROM_DOUBLE(scale);
156    edje_object_calc_force(obj);
157    return EINA_TRUE;
158 }
159
160 EAPI double
161 edje_object_scale_get(const Evas_Object *obj)
162 {
163    Edje *ed;
164
165    ed = _edje_fetch(obj);
166    if (!ed) return 0.0;
167    return TO_DOUBLE(ed->scale);
168 }
169
170 EAPI Eina_Bool
171 edje_object_mirrored_get(const Evas_Object *obj)
172 {
173    Edje *ed;
174
175    ed = _edje_fetch(obj);
176    if (!ed) return EINA_FALSE;
177
178    return ed->is_rtl;
179 }
180
181 void
182 _edje_object_orientation_inform(Evas_Object *obj)
183 {
184    if (edje_object_mirrored_get(obj))
185      edje_object_signal_emit(obj, "edje,state,rtl", "edje");
186    else
187      edje_object_signal_emit(obj, "edje,state,ltr", "edje");
188 }
189
190 EAPI void
191 edje_object_mirrored_set(Evas_Object *obj, Eina_Bool rtl)
192 {
193    Edje *ed;
194    unsigned int i;
195
196    ed = _edje_fetch(obj);
197    if (!ed) return;
198    if (ed->is_rtl == rtl) return;
199
200    ed->is_rtl = rtl;
201
202    for (i = 0 ; i < ed->table_parts_size ; i++)
203      {
204         Edje_Real_Part *ep;
205         const char *s;
206         double v;
207
208         ep = ed->table_parts[i];
209         s = ep->param1.description->state.name,
210         v = ep->param1.description->state.value;
211         _edje_part_description_apply(ed, ep, s, v , NULL, 0.0);
212         ep->chosen_description = ep->param1.description;
213      }
214    _edje_recalc_do(ed);
215
216    _edje_object_orientation_inform(obj);
217
218    return;
219 }
220
221 EAPI const char *
222 edje_object_data_get(const Evas_Object *obj, const char *key)
223 {
224    Edje *ed;
225
226    ed = _edje_fetch(obj);
227    if ((!ed) || (!key))
228      return NULL;
229    if (!ed->collection) return NULL;
230    if (!ed->collection->data) return NULL;
231    return edje_string_get(eina_hash_find(ed->collection->data, key));
232 }
233
234 EAPI int
235 edje_object_freeze(Evas_Object *obj)
236 {
237    Edje *ed;
238    unsigned int i;
239
240    ed = _edje_fetch(obj);
241    if (!ed) return 0;
242    for (i = 0; i < ed->table_parts_size; i++)
243      {
244         Edje_Real_Part *rp;
245         rp = ed->table_parts[i];
246         if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
247           edje_object_freeze(rp->swallowed_object);
248      }
249    return _edje_freeze(ed);
250 }
251
252 EAPI int
253 edje_object_thaw(Evas_Object *obj)
254 {
255    Edje *ed;
256    unsigned int i;
257
258    ed = _edje_fetch(obj);
259    if (!ed) return 0;
260    for (i = 0; i < ed->table_parts_size; i++)
261      {
262         Edje_Real_Part *rp;
263
264         rp = ed->table_parts[i];
265         if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
266           edje_object_thaw(rp->swallowed_object);
267      }
268    return _edje_thaw(ed);
269 }
270
271 EAPI Eina_Bool
272 edje_color_class_set(const char *color_class, int r, int g, int b, int a, int r2, int g2, int b2, int a2, int r3, int g3, int b3, int a3)
273 {
274    Eina_List *members;
275    Edje_Color_Class *cc;
276
277    if (!color_class) return EINA_FALSE;
278
279    cc = eina_hash_find(_edje_color_class_hash, color_class);
280    if (!cc)
281      {
282         cc = calloc(1, sizeof(Edje_Color_Class));
283         if (!cc) return EINA_FALSE;
284         cc->name = eina_stringshare_add(color_class);
285         if (!cc->name)
286           {
287              free(cc);
288              return EINA_FALSE;
289           }
290         if (!_edje_color_class_hash)
291           _edje_color_class_hash = eina_hash_string_superfast_new(NULL);
292         eina_hash_add(_edje_color_class_hash, color_class, cc);
293      }
294
295    if (r < 0)        r = 0;
296    else if (r > 255) r = 255;
297    if (g < 0)        g = 0;
298    else if (g > 255) g = 255;
299    if (b < 0)        b = 0;
300    else if (b > 255) b = 255;
301    if (a < 0)        a = 0;
302    else if (a > 255) a = 255;
303    if ((cc->r == r) && (cc->g == g) &&
304        (cc->b == b) && (cc->a == a) &&
305        (cc->r2 == r2) && (cc->g2 == g2) &&
306        (cc->b2 == b2) && (cc->a2 == a2) &&
307        (cc->r3 == r3) && (cc->g3 == g3) &&
308        (cc->b3 == b3) && (cc->a3 == a3))
309      return EINA_TRUE;
310    cc->r = r;
311    cc->g = g;
312    cc->b = b;
313    cc->a = a;
314    cc->r2 = r2;
315    cc->g2 = g2;
316    cc->b2 = b2;
317    cc->a2 = a2;
318    cc->r3 = r3;
319    cc->g3 = g3;
320    cc->b3 = b3;
321    cc->a3 = a3;
322
323    members = eina_hash_find(_edje_color_class_member_hash, color_class);
324    while (members)
325      {
326         Edje *ed;
327
328         ed = eina_list_data_get(members);
329         ed->dirty = 1;
330 #ifdef EDJE_CALC_CACHE
331         ed->all_part_change = 1;
332 #endif
333         _edje_recalc(ed);
334         _edje_emit(ed, "color_class,set", color_class);
335         members = eina_list_next(members);
336      }
337    return EINA_TRUE;
338 }
339
340 EAPI Eina_Bool
341 edje_color_class_get(const char *color_class, int *r, int *g, int *b, int *a, int *r2, int *g2, int *b2, int *a2, int *r3, int *g3, int *b3, int *a3)
342 {
343    Edje_Color_Class *cc;
344
345    if (!color_class)
346      cc = NULL;
347    else
348      cc = eina_hash_find(_edje_color_class_hash, color_class);
349
350    if (cc)
351      {
352 #define X(C) if (C) *C = cc->C
353 #define S(_r, _g, _b, _a) X(_r); X(_g); X(_b); X(_a)
354         S(r, g, b, a);
355         S(r2, g2, b2, a2);
356         S(r3, g3, b3, a3);
357 #undef S
358 #undef X
359         return EINA_TRUE;
360      }
361    else
362      {
363 #define X(C) if (C) *C = 0
364 #define S(_r, _g, _b, _a) X(_r); X(_g); X(_b); X(_a)
365         S(r, g, b, a);
366         S(r2, g2, b2, a2);
367         S(r3, g3, b3, a3);
368 #undef S
369 #undef X
370         return EINA_FALSE;
371      }
372 }
373
374 void
375 edje_color_class_del(const char *color_class)
376 {
377    Edje_Color_Class *cc;
378    Eina_List *members;
379
380    if (!color_class) return;
381
382    cc = eina_hash_find(_edje_color_class_hash, color_class);
383    if (!cc) return;
384
385    eina_hash_del(_edje_color_class_hash, color_class, cc);
386    eina_stringshare_del(cc->name);
387    free(cc);
388
389    members = eina_hash_find(_edje_color_class_member_hash, color_class);
390    while (members)
391      {
392         Edje *ed;
393
394         ed = eina_list_data_get(members);
395         ed->dirty = 1;
396 #ifdef EDJE_CALC_CACHE
397         ed->all_part_change = 1;
398 #endif
399         _edje_recalc(ed);
400         _edje_emit(ed, "color_class,del", color_class);
401         members = eina_list_next(members);
402      }
403 }
404
405 Eina_List *
406 edje_color_class_list(void)
407 {
408    Edje_List_Foreach_Data fdata;
409
410    memset(&fdata, 0, sizeof(Edje_List_Foreach_Data));
411    eina_hash_foreach(_edje_color_class_member_hash,
412                      _edje_color_class_list_foreach, &fdata);
413
414    return fdata.list;
415 }
416
417 static Eina_Bool
418 _edje_color_class_list_foreach(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata)
419 {
420    Edje_List_Foreach_Data *fd;
421
422    fd = fdata;
423    fd->list = eina_list_append(fd->list, strdup(key));
424    return EINA_TRUE;
425 }
426
427 EAPI Eina_Bool
428 edje_object_color_class_set(Evas_Object *obj, const char *color_class, int r, int g, int b, int a, int r2, int g2, int b2, int a2, int r3, int g3, int b3, int a3)
429 {
430    Edje *ed;
431    Eina_List *l;
432    Edje_Color_Class *cc;
433    unsigned int i;
434
435    ed = _edje_fetch(obj);
436    if ((!ed) || (!color_class)) return EINA_FALSE;
437    if (r < 0)        r = 0;
438    else if (r > 255) r = 255;
439    if (g < 0)        g = 0;
440    else if (g > 255) g = 255;
441    if (b < 0)        b = 0;
442    else if (b > 255) b = 255;
443    if (a < 0)        a = 0;
444    else if (a > 255) a = 255;
445    color_class = eina_stringshare_add(color_class);
446    if (!color_class) return EINA_FALSE;
447    EINA_LIST_FOREACH(ed->color_classes, l, cc)
448      {
449         if (cc->name == color_class)
450           {
451              eina_stringshare_del(color_class);
452
453              if ((cc->r == r) && (cc->g == g) &&
454                  (cc->b == b) && (cc->a == a) &&
455                  (cc->r2 == r2) && (cc->g2 == g2) &&
456                  (cc->b2 == b2) && (cc->a2 == a2) &&
457                  (cc->r3 == r3) && (cc->g3 == g3) &&
458                  (cc->b3 == b3) && (cc->a3 == a3))
459                return EINA_TRUE;
460              cc->r = r;
461              cc->g = g;
462              cc->b = b;
463              cc->a = a;
464              cc->r2 = r2;
465              cc->g2 = g2;
466              cc->b2 = b2;
467              cc->a2 = a2;
468              cc->r3 = r3;
469              cc->g3 = g3;
470              cc->b3 = b3;
471              cc->a3 = a3;
472              ed->dirty = 1;
473 #ifdef EDJE_CALC_CACHE
474              ed->all_part_change = 1;
475 #endif
476              _edje_recalc(ed);
477              return EINA_TRUE;
478           }
479      }
480    cc = malloc(sizeof(Edje_Color_Class));
481    if (!cc)
482      {
483         eina_stringshare_del(color_class);
484         return EINA_FALSE;
485      }
486    cc->name = color_class;
487    cc->r = r;
488    cc->g = g;
489    cc->b = b;
490    cc->a = a;
491    cc->r2 = r2;
492    cc->g2 = g2;
493    cc->b2 = b2;
494    cc->a2 = a2;
495    cc->r3 = r3;
496    cc->g3 = g3;
497    cc->b3 = b3;
498    cc->a3 = a3;
499    ed->color_classes = eina_list_append(ed->color_classes, cc);
500    ed->dirty = 1;
501 #ifdef EDJE_CALC_CACHE
502    ed->all_part_change = 1;
503 #endif
504
505    for (i = 0; i < ed->table_parts_size; i++)
506      {
507         Edje_Real_Part *rp;
508
509         rp = ed->table_parts[i];
510         if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
511           edje_object_color_class_set(rp->swallowed_object, color_class,
512                                       r, g, b, a, r2, g2, b2, a2, r3, g3, b3,
513                                       a3);
514      }
515
516    _edje_recalc(ed);
517    _edje_emit(ed, "color_class,set", color_class);
518    return EINA_TRUE;
519 }
520
521 EAPI Eina_Bool
522 edje_object_color_class_get(const Evas_Object *obj, const char *color_class, int *r, int *g, int *b, int *a, int *r2, int *g2, int *b2, int *a2, int *r3, int *g3, int *b3, int *a3)
523 {
524    Edje *ed = _edje_fetch(obj);
525    Edje_Color_Class *cc = _edje_color_class_find(ed, color_class);
526
527    if (cc)
528      {
529 #define X(C) if (C) *C = cc->C
530 #define S(_r, _g, _b, _a) X(_r); X(_g); X(_b); X(_a)
531         S(r, g, b, a);
532         S(r2, g2, b2, a2);
533         S(r3, g3, b3, a3);
534 #undef S
535 #undef X
536         return EINA_TRUE;
537      }
538    else
539      {
540 #define X(C) if (C) *C = 0
541 #define S(_r, _g, _b, _a) X(_r); X(_g); X(_b); X(_a)
542         S(r, g, b, a);
543         S(r2, g2, b2, a2);
544         S(r3, g3, b3, a3);
545 #undef S
546 #undef X
547         return EINA_FALSE;
548      }
549 }
550
551 void
552 edje_object_color_class_del(Evas_Object *obj, const char *color_class)
553 {
554    Edje *ed;
555    Eina_List *l;
556    Edje_Color_Class *cc = NULL;
557    unsigned int i;
558
559    if (!color_class) return;
560
561    ed = _edje_fetch(obj);
562    EINA_LIST_FOREACH(ed->color_classes, l, cc)
563      {
564         if (!strcmp(cc->name, color_class))
565           {
566              ed->color_classes = eina_list_remove(ed->color_classes, cc);
567              eina_stringshare_del(cc->name);
568              free(cc);
569              return;
570           }
571      }
572
573    for (i = 0; i < ed->table_parts_size; i++)
574      {
575         Edje_Real_Part *rp;
576
577         rp = ed->table_parts[i];
578         if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
579           edje_object_color_class_del(rp->swallowed_object, color_class);
580      }
581
582    ed->dirty = 1;
583 #ifdef EDJE_CALC_CACHE
584    ed->all_part_change = 1;
585 #endif
586    _edje_recalc(ed);
587    _edje_emit(ed, "color_class,del", color_class);
588 }
589
590 EAPI Eina_Bool
591 edje_text_class_set(const char *text_class, const char *font, Evas_Font_Size size)
592 {
593    Eina_List *members;
594    Edje_Text_Class *tc;
595
596    if (!text_class) return EINA_FALSE;
597    if (!font) font = "";
598
599    tc = eina_hash_find(_edje_text_class_hash, text_class);
600    /* Create new text class */
601    if (!tc)
602      {
603         tc = calloc(1, sizeof(Edje_Text_Class));
604         if (!tc) return EINA_FALSE;
605         tc->name = eina_stringshare_add(text_class);
606         if (!tc->name)
607           {
608              free(tc);
609              return EINA_FALSE;
610           }
611         if (!_edje_text_class_hash) _edje_text_class_hash = eina_hash_string_superfast_new(NULL);
612         eina_hash_add(_edje_text_class_hash, text_class, tc);
613
614         tc->font = eina_stringshare_add(font);
615         tc->size = size;
616         return EINA_FALSE;
617      }
618
619    /* If the class found is the same just return */
620    if ((tc->size == size) && (tc->font) && (!strcmp(tc->font, font)))
621      return EINA_TRUE;
622
623    /* Update the class found */
624    eina_stringshare_del(tc->font);
625    tc->font = eina_stringshare_add(font);
626    if (!tc->font)
627      {
628         eina_hash_del(_edje_text_class_hash, text_class, tc);
629         free(tc);
630         return EINA_FALSE;
631      }
632    tc->size = size;
633
634    /* Tell all members of the text class to recalc */
635    members = eina_hash_find(_edje_text_class_member_hash, text_class);
636    while (members)
637      {
638         Edje *ed;
639
640         ed = eina_list_data_get(members);
641         ed->dirty = 1;
642         _edje_textblock_style_all_update(ed);
643 #ifdef EDJE_CALC_CACHE
644         ed->text_part_change = 1;
645 #endif
646         _edje_recalc(ed);
647         members = eina_list_next(members);
648      }
649    return EINA_TRUE;
650 }
651
652 void
653 edje_text_class_del(const char *text_class)
654 {
655    Edje_Text_Class *tc;
656    Eina_List *members;
657
658    if (!text_class) return;
659
660    tc = eina_hash_find(_edje_text_class_hash, text_class);
661    if (!tc) return;
662
663    eina_hash_del(_edje_text_class_hash, text_class, tc);
664    eina_stringshare_del(tc->name);
665    eina_stringshare_del(tc->font);
666    free(tc);
667
668    members = eina_hash_find(_edje_text_class_member_hash, text_class);
669    while (members)
670      {
671         Edje *ed;
672
673         ed = eina_list_data_get(members);
674         ed->dirty = 1;
675         _edje_textblock_style_all_update(ed);
676 #ifdef EDJE_CALC_CACHE
677         ed->text_part_change = 1;
678 #endif
679         _edje_recalc(ed);
680         members = eina_list_next(members);
681      }
682 }
683
684 Eina_List *
685 edje_text_class_list(void)
686 {
687    Edje_List_Foreach_Data fdata;
688
689    memset(&fdata, 0, sizeof(Edje_List_Foreach_Data));
690    eina_hash_foreach(_edje_text_class_member_hash,
691                      _edje_text_class_list_foreach, &fdata);
692    return fdata.list;
693 }
694
695 static Eina_Bool
696 _edje_text_class_list_foreach(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata)
697 {
698    Edje_List_Foreach_Data *fd;
699
700    fd = fdata;
701    fd->list = eina_list_append(fd->list, eina_stringshare_add(key));
702    return EINA_TRUE;
703 }
704
705 EAPI Eina_Bool
706 edje_object_text_class_set(Evas_Object *obj, const char *text_class, const char *font, Evas_Font_Size size)
707 {
708    Edje *ed;
709    Eina_List *l;
710    Edje_Text_Class *tc;
711    unsigned int i;
712
713    ed = _edje_fetch(obj);
714    if ((!ed) || (!text_class)) return EINA_FALSE;
715
716    /* for each text_class in the edje */
717    EINA_LIST_FOREACH(ed->text_classes, l, tc)
718      {
719         if ((tc->name) && (!strcmp(tc->name, text_class)))
720           {
721              /* Match and the same, return */
722              if ((tc->font) && (font) && (!strcmp(tc->font, font)) &&
723                  (tc->size == size))
724                return EINA_TRUE;
725
726              /* No font but size is the same, return */
727              if ((!tc->font) && (!font) && (tc->size == size)) return EINA_TRUE;
728
729              /* Update new text class properties */
730              if (tc->font) eina_stringshare_del(tc->font);
731              if (font) tc->font = eina_stringshare_add(font);
732              else tc->font = NULL;
733              tc->size = size;
734
735              /* Update edje */
736              ed->dirty = 1;
737 #ifdef EDJE_CALC_CACHE
738              ed->text_part_change = 1;
739 #endif
740              _edje_recalc(ed);
741              return EINA_TRUE;
742           }
743      }
744
745    /* No matches, create a new text class */
746    tc = calloc(1, sizeof(Edje_Text_Class));
747    if (!tc) return EINA_FALSE;
748    tc->name = eina_stringshare_add(text_class);
749    if (!tc->name)
750      {
751         free(tc);
752         return EINA_FALSE;
753      }
754    if (font) tc->font = eina_stringshare_add(font);
755    else tc->font = NULL;
756    tc->size = size;
757
758    for (i = 0; i < ed->table_parts_size; i++)
759      {
760         Edje_Real_Part *rp;
761
762         rp = ed->table_parts[i];
763         if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
764           edje_object_text_class_set(rp->swallowed_object, text_class,
765                                      font, size);
766      }
767
768    /* Add to edje's text class list */
769    ed->text_classes = eina_list_append(ed->text_classes, tc);
770    ed->dirty = 1;
771 #ifdef EDJE_CALC_CACHE
772    ed->text_part_change = 1;
773 #endif
774    _edje_textblock_style_all_update(ed);
775    _edje_recalc(ed);
776    return EINA_TRUE;
777 }
778
779 EAPI Eina_Bool
780 edje_object_part_exists(const Evas_Object *obj, const char *part)
781 {
782    Edje *ed;
783    Edje_Real_Part *rp;
784
785    ed = _edje_fetch(obj);
786    if ((!ed) || (!part)) return EINA_FALSE;
787    rp = _edje_real_part_recursive_get(ed, (char *)part);
788    if (!rp) return EINA_FALSE;
789    return EINA_TRUE;
790 }
791
792 EAPI const Evas_Object *
793 edje_object_part_object_get(const Evas_Object *obj, const char *part)
794 {
795    Edje *ed;
796    Edje_Real_Part *rp;
797
798    ed = _edje_fetch(obj);
799    if ((!ed) || (!part)) return NULL;
800
801    /* Need to recalc before providing the object. */
802    _edje_recalc_do(ed);
803
804    rp = _edje_real_part_recursive_get(ed, (char *)part);
805    if (!rp) return NULL;
806    return rp->object;
807 }
808
809 EAPI Eina_Bool
810 edje_object_part_geometry_get(const Evas_Object *obj, const char *part, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h )
811 {
812    Edje *ed;
813    Edje_Real_Part *rp;
814
815    ed = _edje_fetch(obj);
816    if ((!ed) || (!part))
817      {
818         if (x) *x = 0;
819         if (y) *y = 0;
820         if (w) *w = 0;
821         if (h) *h = 0;
822         return EINA_FALSE;
823      }
824
825    /* Need to recalc before providing the object. */
826    _edje_recalc_do(ed);
827
828    rp = _edje_real_part_recursive_get(ed, (char *)part);
829    if (!rp)
830      {
831         if (x) *x = 0;
832         if (y) *y = 0;
833         if (w) *w = 0;
834         if (h) *h = 0;
835         return EINA_FALSE;
836      }
837    if (x) *x = rp->x;
838    if (y) *y = rp->y;
839    if (w) *w = rp->w;
840    if (h) *h = rp->h;
841    return EINA_TRUE;
842 }
843
844 EAPI void
845 edje_object_item_provider_set(Evas_Object *obj, Edje_Item_Provider_Cb func, void *data)
846 {
847    Edje *ed;
848
849    ed = _edje_fetch(obj);
850    if (!ed) return;
851    ed->item_provider.func = func;
852    ed->item_provider.data = data;
853 }
854
855 /* FIXDOC: New Function */
856 EAPI void
857 edje_object_text_change_cb_set(Evas_Object *obj, Edje_Text_Change_Cb func, void *data)
858 {
859    Edje *ed;
860    unsigned int i;
861
862    ed = _edje_fetch(obj);
863    if (!ed) return;
864    ed->text_change.func = func;
865    ed->text_change.data = data;
866
867    for (i = 0; i < ed->table_parts_size; i++)
868      {
869         Edje_Real_Part *rp;
870
871         rp = ed->table_parts[i];
872         if ((rp->part->type == EDJE_PART_TYPE_GROUP) && (rp->swallowed_object))
873            edje_object_text_change_cb_set(rp->swallowed_object, func, data);
874      }
875 }
876
877 Eina_Bool
878 _edje_object_part_text_raw_set(Evas_Object *obj, Edje_Real_Part *rp, const char *part, const char *text)
879 {
880    if ((!rp->text.text) && (!text))
881      return EINA_FALSE;
882    if ((rp->text.text) && (text) &&
883        (!strcmp(rp->text.text, text)))
884      return EINA_FALSE;
885    if (rp->text.text)
886      {
887         eina_stringshare_del(rp->text.text);
888         rp->text.text = NULL;
889      }
890    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
891      _edje_entry_text_markup_set(rp, text);
892    else
893      if (text) rp->text.text = eina_stringshare_add(text);
894    rp->edje->dirty = 1;
895 #ifdef EDJE_CALC_CACHE
896    rp->invalidate = 1;
897 #endif
898    _edje_recalc(rp->edje);
899    if (rp->edje->text_change.func)
900      rp->edje->text_change.func(rp->edje->text_change.data, obj, part);
901    return EINA_TRUE;
902 }
903
904 /** Sets the text for an object part
905  * @param obj A valid Evas Object handle
906  * @param part The part name
907  * @param text The text string
908  */
909 EAPI Eina_Bool
910 edje_object_part_text_set(Evas_Object *obj, const char *part, const char *text)
911 {
912    Edje *ed;
913    Edje_Real_Part *rp;
914
915    ed = _edje_fetch(obj);
916    if ((!ed) || (!part)) return EINA_FALSE;
917    rp = _edje_real_part_recursive_get(ed, (char *)part);
918    if (!rp) return EINA_FALSE;
919    if ((rp->part->type != EDJE_PART_TYPE_TEXT) &&
920        (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK)) return EINA_FALSE;
921    return _edje_object_part_text_raw_set(obj, rp, part, text);
922 }
923
924 EAPI const char *
925 edje_object_part_text_get(const Evas_Object *obj, const char *part)
926 {
927    Edje *ed;
928    Edje_Real_Part *rp;
929
930    ed = _edje_fetch(obj);
931    if ((!ed) || (!part)) return NULL;
932
933    /* Need to recalc before providing the object. */
934    _edje_recalc_do(ed);
935
936    rp = _edje_real_part_recursive_get(ed, (char *)part);
937    if (!rp) return NULL;
938    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
939      return _edje_entry_text_get(rp);
940    else
941      {
942         if (rp->part->type == EDJE_PART_TYPE_TEXT) return rp->text.text;
943         if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
944           return evas_object_textblock_text_markup_get(rp->object);
945      }
946    return NULL;
947 }
948
949 char *
950 _edje_text_escape(const char *text)
951 {
952    Eina_Strbuf *txt;
953    char *ret;
954    const char *text_end;
955    size_t text_len;
956
957    if (!text) return NULL;
958
959    txt = eina_strbuf_new();
960    text_len = strlen(text);
961
962    text_end = text + text_len;
963    while (text < text_end)
964      {
965         int advance;
966         const char *escaped = evas_textblock_string_escape_get(text, &advance);
967         if (!escaped)
968           {
969              eina_strbuf_append_char(txt, text[0]);
970              advance = 1;
971           }
972         else
973           eina_strbuf_append(txt, escaped);
974
975         text += advance;
976      }
977
978    ret = eina_strbuf_string_steal(txt);
979    eina_strbuf_free(txt);
980    return ret;
981 }
982
983 char *
984 _edje_text_unescape(const char *text)
985 {
986    Eina_Strbuf *txt;
987    char *ret;
988    const char *text_end, *last, *escape_start;
989    size_t text_len;
990
991    if (!text) return NULL;
992
993    txt = eina_strbuf_new();
994    text_len = strlen(text);
995
996    text_end = text + text_len;
997    last = text;
998    escape_start = NULL;
999    for (; text < text_end; text++)
1000      {
1001         if (*text == '&')
1002           {
1003              size_t len;
1004              const char *str;
1005
1006              if (last)
1007                {
1008                   len = text - last;
1009                   str = last;
1010                }
1011              else
1012                {
1013                   len = text - escape_start;
1014                   str = escape_start;
1015                }
1016
1017              if (len > 0)
1018                eina_strbuf_append_n(txt, str, len);
1019
1020              escape_start = text;
1021              last = NULL;
1022           }
1023         else if ((*text == ';') && (escape_start))
1024           {
1025              size_t len;
1026              const char *str = evas_textblock_escape_string_range_get(escape_start, text);
1027
1028              if (str)
1029                len = strlen(str);
1030              else
1031                {
1032                   str = escape_start;
1033                   len = text + 1 - escape_start;
1034                }
1035
1036              eina_strbuf_append_n(txt, str, len);
1037
1038              escape_start = NULL;
1039              last = text + 1;
1040           }
1041      }
1042
1043    if (!last && escape_start)
1044      last = escape_start;
1045
1046    if (last && (text > last))
1047      {
1048         size_t len = text - last;
1049         eina_strbuf_append_n(txt, last, len);
1050      }
1051
1052    ret = eina_strbuf_string_steal(txt);
1053    eina_strbuf_free(txt);
1054    return ret;
1055 }
1056
1057 EAPI Eina_Bool
1058 edje_object_part_text_unescaped_set(Evas_Object *obj, const char *part, const char *text_to_escape)
1059 {
1060    Edje *ed;
1061    Edje_Real_Part *rp;
1062    Eina_Bool ret = EINA_FALSE;
1063
1064    ed = _edje_fetch(obj);
1065    if ((!ed) || (!part)) return ret;
1066    rp = _edje_real_part_recursive_get(ed, part);
1067    if (!rp) return ret;
1068    if (rp->part->type == EDJE_PART_TYPE_TEXT)
1069      ret = _edje_object_part_text_raw_set(obj, rp, part, text_to_escape);
1070    else if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
1071      {
1072         char *text = _edje_text_escape(text_to_escape);
1073
1074         ret = _edje_object_part_text_raw_set(obj, rp, part, text);
1075         free(text);
1076      }
1077    return ret;
1078 }
1079
1080 EAPI char *
1081 edje_object_part_text_unescaped_get(const Evas_Object *obj, const char *part)
1082 {
1083    Edje *ed;
1084    Edje_Real_Part *rp;
1085
1086    ed = _edje_fetch(obj);
1087    if ((!ed) || (!part)) return NULL;
1088
1089    /* Need to recalc before providing the object. */
1090    _edje_recalc_do(ed);
1091
1092    rp = _edje_real_part_recursive_get(ed, (char *)part);
1093    if (!rp) return NULL;
1094    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1095      {
1096         const char *t = _edje_entry_text_get(rp);
1097         return _edje_text_unescape(t);
1098      }
1099    else
1100      {
1101         if (rp->part->type == EDJE_PART_TYPE_TEXT) return strdup(rp->text.text);
1102         if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
1103           {
1104              const char *t = evas_object_textblock_text_markup_get(rp->object);
1105              return _edje_text_unescape(t);
1106           }
1107      }
1108    return NULL;
1109 }
1110
1111 EAPI const char *
1112 edje_object_part_text_selection_get(const Evas_Object *obj, const char *part)
1113 {
1114    Edje *ed;
1115    Edje_Real_Part *rp;
1116
1117    ed = _edje_fetch(obj);
1118    if ((!ed) || (!part)) return NULL;
1119    rp = _edje_real_part_recursive_get(ed, (char *)part);
1120    if (!rp) return NULL;
1121    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1122      return _edje_entry_selection_get(rp);
1123    return NULL;
1124 }
1125
1126 EAPI void
1127 edje_object_part_text_select_none(const Evas_Object *obj, const char *part)
1128 {
1129    Edje *ed;
1130    Edje_Real_Part *rp;
1131
1132    ed = _edje_fetch(obj);
1133    if ((!ed) || (!part)) return;
1134    rp = _edje_real_part_recursive_get(ed, (char *)part);
1135    if (!rp) return;
1136    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1137      _edje_entry_select_none(rp);
1138 }
1139
1140 EAPI void
1141 edje_object_part_text_select_all(const Evas_Object *obj, const char *part)
1142 {
1143    Edje *ed;
1144    Edje_Real_Part *rp;
1145
1146    ed = _edje_fetch(obj);
1147    if ((!ed) || (!part)) return;
1148    rp = _edje_real_part_recursive_get(ed, (char *)part);
1149    if (!rp) return;
1150    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1151      _edje_entry_select_all(rp);
1152 }
1153
1154 EAPI void
1155 edje_object_part_text_insert(Evas_Object *obj, const char *part, const char *text)
1156 {
1157    Edje *ed;
1158    Edje_Real_Part *rp;
1159
1160    ed = _edje_fetch(obj);
1161    if ((!ed) || (!part)) return;
1162    rp = _edje_real_part_recursive_get(ed, (char *)part);
1163    if (!rp) return;
1164    if ((rp->part->type != EDJE_PART_TYPE_TEXTBLOCK)) return;
1165    if (rp->part->entry_mode <= EDJE_ENTRY_EDIT_MODE_NONE) return;
1166    _edje_entry_text_markup_insert(rp, text);
1167    rp->edje->dirty = 1;
1168 #ifdef EDJE_CALC_CACHE
1169    rp->invalidate = 1;
1170 #endif
1171    _edje_recalc(rp->edje);
1172    if (rp->edje->text_change.func)
1173      rp->edje->text_change.func(rp->edje->text_change.data, obj, part);
1174 }
1175
1176 EAPI void
1177 edje_object_part_text_append(Evas_Object *obj, const char *part, const char *text)
1178 {
1179    Edje *ed;
1180    Edje_Real_Part *rp;
1181
1182    ed = _edje_fetch(obj);
1183    if ((!ed) || (!part)) return;
1184    rp = _edje_real_part_recursive_get(ed, (char *)part);
1185    if (!rp) return;
1186    if ((rp->part->type != EDJE_PART_TYPE_TEXTBLOCK)) return;
1187    if (rp->part->entry_mode <= EDJE_ENTRY_EDIT_MODE_NONE) return;
1188    _edje_entry_text_markup_append(rp, text);
1189    rp->edje->dirty = 1;
1190 #ifdef EDJE_CALC_CACHE
1191    rp->invalidate = 1;
1192 #endif
1193    _edje_recalc(rp->edje);
1194    if (rp->edje->text_change.func)
1195      rp->edje->text_change.func(rp->edje->text_change.data, obj, part);
1196 }
1197
1198 EAPI const Eina_List *
1199 edje_object_part_text_anchor_list_get(const Evas_Object *obj, const char *part)
1200 {
1201    Edje *ed;
1202    Edje_Real_Part *rp;
1203
1204    ed = _edje_fetch(obj);
1205    if ((!ed) || (!part)) return NULL;
1206    rp = _edje_real_part_recursive_get(ed, (char *)part);
1207    if (!rp) return NULL;
1208    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1209      return _edje_entry_anchors_list(rp);
1210    return NULL;
1211 }
1212
1213 EAPI const Eina_List *
1214 edje_object_part_text_anchor_geometry_get(const Evas_Object *obj, const char *part, const char *anchor)
1215 {
1216    Edje *ed;
1217    Edje_Real_Part *rp;
1218
1219    ed = _edje_fetch(obj);
1220    if ((!ed) || (!part)) return NULL;
1221    rp = _edje_real_part_recursive_get(ed, (char *)part);
1222    if (!rp) return NULL;
1223    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1224      return _edje_entry_anchor_geometry_get(rp, anchor);
1225    return NULL;
1226 }
1227
1228 EAPI const Eina_List *
1229 edje_object_part_text_item_list_get(const Evas_Object *obj, const char *part)
1230 {
1231    Edje *ed;
1232    Edje_Real_Part *rp;
1233
1234    ed = _edje_fetch(obj);
1235    if ((!ed) || (!part)) return NULL;
1236    rp = _edje_real_part_recursive_get(ed, (char *)part);
1237    if (!rp) return NULL;
1238    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1239      return _edje_entry_items_list(rp);
1240    return NULL;
1241 }
1242
1243 EAPI Eina_Bool
1244 edje_object_part_text_item_geometry_get(const Evas_Object *obj, const char *part, const char *item, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
1245 {
1246    Edje *ed;
1247    Edje_Real_Part *rp;
1248
1249    ed = _edje_fetch(obj);
1250    if ((!ed) || (!part)) return EINA_FALSE;
1251    rp = _edje_real_part_recursive_get(ed, (char *)part);
1252    if (!rp) return EINA_FALSE;
1253    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1254      return _edje_entry_item_geometry_get(rp, item, cx, cy, cw, ch);
1255    return EINA_FALSE;
1256 }
1257
1258 EAPI void
1259 edje_object_part_text_cursor_geometry_get(const Evas_Object *obj, const char *part, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
1260 {
1261    Edje *ed;
1262    Edje_Real_Part *rp;
1263
1264    ed = _edje_fetch(obj);
1265    if (x) *x = 0;
1266    if (y) *y = 0;
1267    if (w) *w = 0;
1268    if (h) *h = 0;
1269    if ((!ed) || (!part)) return;
1270    rp = _edje_real_part_recursive_get(ed, (char *)part);
1271    if (!rp) return;
1272    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1273      {
1274         _edje_entry_cursor_geometry_get(rp, x, y, w, h);
1275         if (x) *x -= rp->edje->x;
1276         if (y) *y -= rp->edje->y;
1277      }
1278    return;
1279 }
1280
1281 EAPI void
1282 edje_object_part_text_select_allow_set(const Evas_Object *obj, const char *part, Eina_Bool allow)
1283 {
1284    Edje *ed;
1285    Edje_Real_Part *rp;
1286
1287    ed = _edje_fetch(obj);
1288    if ((!ed) || (!part)) return;
1289    rp = _edje_real_part_recursive_get(ed, (char *)part);
1290    if (!rp) return;
1291    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1292      _edje_entry_select_allow_set(rp, allow);
1293 }
1294
1295 EAPI void
1296 edje_object_part_text_select_abort(const Evas_Object *obj, const char *part)
1297 {
1298    Edje *ed;
1299    Edje_Real_Part *rp;
1300
1301    ed = _edje_fetch(obj);
1302    if ((!ed) || (!part)) return;
1303    rp = _edje_real_part_recursive_get(ed, (char *)part);
1304    if (!rp) return;
1305    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1306      _edje_entry_select_abort(rp);
1307 }
1308
1309 EAPI void
1310 edje_object_part_text_select_begin(const Evas_Object *obj, const char *part)
1311 {
1312    Edje *ed;
1313    Edje_Real_Part *rp;
1314
1315    ed = _edje_fetch(obj);
1316    if ((!ed) || (!part)) return;
1317    rp = _edje_real_part_recursive_get(ed, (char *)part);
1318    if (!rp) return;
1319    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1320      _edje_entry_select_begin(rp);
1321 }
1322
1323 EAPI void
1324 edje_object_part_text_select_extend(const Evas_Object *obj, const char *part)
1325 {
1326    Edje *ed;
1327    Edje_Real_Part *rp;
1328
1329    ed = _edje_fetch(obj);
1330    if ((!ed) || (!part)) return;
1331    rp = _edje_real_part_recursive_get(ed, (char *)part);
1332    if (!rp) return;
1333    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1334      _edje_entry_select_extend(rp);
1335 }
1336
1337 EAPI Eina_Bool
1338 edje_object_part_text_cursor_next(Evas_Object *obj, const char *part, Edje_Cursor cur)
1339 {
1340    Edje *ed;
1341    Edje_Real_Part *rp;
1342
1343    ed = _edje_fetch(obj);
1344    if ((!ed) || (!part)) return EINA_FALSE;
1345    rp = _edje_real_part_recursive_get(ed, (char *)part);
1346    if (!rp) return EINA_FALSE;
1347    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1348      {
1349         return _edje_entry_cursor_next(rp, cur);
1350      }
1351    return EINA_FALSE;
1352 }
1353
1354 EAPI Eina_Bool
1355 edje_object_part_text_cursor_prev(Evas_Object *obj, const char *part, Edje_Cursor cur)
1356 {
1357    Edje *ed;
1358    Edje_Real_Part *rp;
1359
1360    ed = _edje_fetch(obj);
1361    if ((!ed) || (!part)) return EINA_FALSE;
1362    rp = _edje_real_part_recursive_get(ed, (char *)part);
1363    if (!rp) return EINA_FALSE;
1364    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1365      {
1366         return _edje_entry_cursor_prev(rp, cur);
1367      }
1368    return EINA_FALSE;
1369 }
1370
1371 EAPI Eina_Bool
1372 edje_object_part_text_cursor_up(Evas_Object *obj, const char *part, Edje_Cursor cur)
1373 {
1374    Edje *ed;
1375    Edje_Real_Part *rp;
1376
1377    ed = _edje_fetch(obj);
1378    if ((!ed) || (!part)) return EINA_FALSE;
1379    rp = _edje_real_part_recursive_get(ed, (char *)part);
1380    if (!rp) return EINA_FALSE;
1381    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1382      {
1383         return _edje_entry_cursor_up(rp, cur);
1384      }
1385    return EINA_FALSE;
1386 }
1387
1388 EAPI Eina_Bool
1389 edje_object_part_text_cursor_down(Evas_Object *obj, const char *part, Edje_Cursor cur)
1390 {
1391    Edje *ed;
1392    Edje_Real_Part *rp;
1393
1394    ed = _edje_fetch(obj);
1395    if ((!ed) || (!part)) return EINA_FALSE;
1396    rp = _edje_real_part_recursive_get(ed, (char *)part);
1397    if (!rp) return EINA_FALSE;
1398    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1399      {
1400         return _edje_entry_cursor_down(rp, cur);
1401      }
1402    return EINA_FALSE;
1403 }
1404
1405 EAPI void
1406 edje_object_part_text_cursor_begin_set(Evas_Object *obj, const char *part, Edje_Cursor cur)
1407 {
1408    Edje *ed;
1409    Edje_Real_Part *rp;
1410
1411    ed = _edje_fetch(obj);
1412    if ((!ed) || (!part)) return;
1413    rp = _edje_real_part_recursive_get(ed, (char *)part);
1414    if (!rp) return;
1415    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1416      {
1417         _edje_entry_cursor_begin(rp, cur);
1418      }
1419 }
1420
1421 EAPI void
1422 edje_object_part_text_cursor_end_set(Evas_Object *obj, const char *part, Edje_Cursor cur)
1423 {
1424    Edje *ed;
1425    Edje_Real_Part *rp;
1426
1427    ed = _edje_fetch(obj);
1428    if ((!ed) || (!part)) return;
1429    rp = _edje_real_part_recursive_get(ed, (char *)part);
1430    if (!rp) return;
1431    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1432      {
1433         _edje_entry_cursor_end(rp, cur);
1434      }
1435 }
1436
1437 EAPI void
1438 edje_object_part_text_cursor_copy(Evas_Object *obj, const char *part, Edje_Cursor src, Edje_Cursor dst)
1439 {
1440    Edje *ed;
1441    Edje_Real_Part *rp;
1442
1443    ed = _edje_fetch(obj);
1444    if ((!ed) || (!part)) return;
1445    rp = _edje_real_part_recursive_get(ed, (char *)part);
1446    if (!rp) return;
1447    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1448      {
1449         _edje_entry_cursor_copy(rp, src, dst);
1450      }
1451 }
1452
1453 EAPI void
1454 edje_object_part_text_cursor_line_begin_set(Evas_Object *obj, const char *part, Edje_Cursor cur)
1455 {
1456    Edje *ed;
1457    Edje_Real_Part *rp;
1458
1459    ed = _edje_fetch(obj);
1460    if ((!ed) || (!part)) return;
1461    rp = _edje_real_part_recursive_get(ed, (char *)part);
1462    if (!rp) return;
1463    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1464      {
1465         _edje_entry_cursor_line_begin(rp, cur);
1466      }
1467 }
1468
1469 EAPI void
1470 edje_object_part_text_cursor_line_end_set(Evas_Object *obj, const char *part, Edje_Cursor cur)
1471 {
1472    Edje *ed;
1473    Edje_Real_Part *rp;
1474
1475    ed = _edje_fetch(obj);
1476    if ((!ed) || (!part)) return;
1477    rp = _edje_real_part_recursive_get(ed, (char *)part);
1478    if (!rp) return;
1479    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1480      {
1481         _edje_entry_cursor_line_end(rp, cur);
1482      }
1483 }
1484
1485 EAPI Eina_Bool
1486 edje_object_part_text_cursor_coord_set(Evas_Object *obj, const char *part,
1487                 Edje_Cursor cur, Evas_Coord x, Evas_Coord y)
1488 {
1489  Edje *ed;
1490    Edje_Real_Part *rp;
1491
1492    ed = _edje_fetch(obj);
1493    if ((!ed) || (!part)) return EINA_FALSE;
1494    rp = _edje_real_part_recursive_get(ed, (char *)part);
1495    if (!rp) return EINA_FALSE;
1496    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1497      {
1498         return _edje_entry_cursor_coord_set(rp, cur, x, y);
1499      }
1500    return EINA_FALSE;
1501 }
1502
1503 EAPI Eina_Bool
1504 edje_object_part_text_cursor_is_format_get(const Evas_Object *obj, const char *part, Edje_Cursor cur)
1505 {
1506    Edje *ed;
1507    Edje_Real_Part *rp;
1508
1509    ed = _edje_fetch(obj);
1510    if ((!ed) || (!part)) return EINA_FALSE;
1511    rp = _edje_real_part_recursive_get(ed, (char *)part);
1512    if (!rp) return EINA_FALSE;
1513    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1514      {
1515         return _edje_entry_cursor_is_format_get(rp, cur);
1516      }
1517    return EINA_FALSE;
1518 }
1519
1520 EAPI Eina_Bool
1521 edje_object_part_text_cursor_is_visible_format_get(const Evas_Object *obj, const char *part, Edje_Cursor cur)
1522 {
1523    Edje *ed;
1524    Edje_Real_Part *rp;
1525
1526    ed = _edje_fetch(obj);
1527    if ((!ed) || (!part)) return 0;
1528    rp = _edje_real_part_recursive_get(ed, (char *)part);
1529    if (!rp) return 0;
1530    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1531      {
1532         return _edje_entry_cursor_is_visible_format_get(rp, cur);
1533      }
1534    return 0;
1535 }
1536
1537 EAPI const char *
1538 edje_object_part_text_cursor_content_get(const Evas_Object *obj, const char *part, Edje_Cursor cur)
1539 {
1540    Edje *ed;
1541    Edje_Real_Part *rp;
1542
1543    ed = _edje_fetch(obj);
1544    if ((!ed) || (!part)) return NULL;
1545    rp = _edje_real_part_recursive_get(ed, part);
1546    if (!rp) return NULL;
1547    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1548      {
1549         return _edje_entry_cursor_content_get(rp, cur);
1550      }
1551    return NULL;
1552 }
1553
1554 EAPI void
1555 edje_object_part_text_cursor_pos_set(Evas_Object *obj, const char *part, Edje_Cursor cur, int pos)
1556 {
1557    Edje *ed;
1558    Edje_Real_Part *rp;
1559
1560    ed = _edje_fetch(obj);
1561    if ((!ed) || (!part)) return;
1562    rp = _edje_real_part_recursive_get(ed, part);
1563    if (!rp) return;
1564    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1565      {
1566         _edje_entry_cursor_pos_set(rp, cur, pos);
1567      }
1568 }
1569
1570 EAPI int
1571 edje_object_part_text_cursor_pos_get(const Evas_Object *obj, const char *part, Edje_Cursor cur)
1572 {
1573    Edje *ed;
1574    Edje_Real_Part *rp;
1575
1576    ed = _edje_fetch(obj);
1577    if ((!ed) || (!part)) return 0;
1578    rp = _edje_real_part_recursive_get(ed, part);
1579    if (!rp) return 0;
1580    if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1581      {
1582         return _edje_entry_cursor_pos_get(rp, cur);
1583      }
1584    return 0;
1585 }
1586
1587 EAPI void
1588 edje_object_text_insert_filter_callback_add(Evas_Object *obj, const char *part, Edje_Text_Filter_Cb func, void *data)
1589 {
1590    Edje *ed;
1591    Edje_Text_Insert_Filter_Callback *cb;
1592
1593    ed = _edje_fetch(obj);
1594    if ((!ed) || (!part)) return;
1595    cb = calloc(1, sizeof(Edje_Text_Insert_Filter_Callback));
1596    cb->part = eina_stringshare_add(part);
1597    cb->func = func;
1598    cb->data = (void *)data;
1599    ed->text_insert_filter_callbacks =
1600      eina_list_append(ed->text_insert_filter_callbacks, cb);
1601 }
1602
1603 EAPI void *
1604 edje_object_text_insert_filter_callback_del(Evas_Object *obj, const char *part, Edje_Text_Filter_Cb func)
1605 {
1606    Edje *ed;
1607    Edje_Text_Insert_Filter_Callback *cb;
1608    Eina_List *l;
1609
1610    ed = _edje_fetch(obj);
1611    if ((!ed) || (!part)) return NULL;
1612    EINA_LIST_FOREACH(ed->text_insert_filter_callbacks, l, cb)
1613      {
1614         if ((!strcmp(cb->part, part)) && (cb->func == func))
1615           {
1616              void *data = cb->data;
1617              ed->text_insert_filter_callbacks =
1618                 eina_list_remove_list(ed->text_insert_filter_callbacks, l);
1619              eina_stringshare_del(cb->part);
1620              free(cb);
1621              return data;
1622           }
1623      }
1624    return NULL;
1625 }
1626
1627 EAPI void *
1628 edje_object_text_insert_filter_callback_del_full(Evas_Object *obj, const char *part, Edje_Text_Filter_Cb func, void *data)
1629 {
1630    Edje *ed;
1631    Edje_Text_Insert_Filter_Callback *cb;
1632    Eina_List *l;
1633
1634    ed = _edje_fetch(obj);
1635    if ((!ed) || (!part)) return NULL;
1636    EINA_LIST_FOREACH(ed->text_insert_filter_callbacks, l, cb)
1637      {
1638         if ((!strcmp(cb->part, part)) && (cb->func == func) &&
1639             (cb->data == data))
1640           {
1641              void *data = cb->data;
1642              ed->text_insert_filter_callbacks =
1643                 eina_list_remove_list(ed->text_insert_filter_callbacks, l);
1644              eina_stringshare_del(cb->part);
1645              free(cb);
1646              return data;
1647           }
1648      }
1649    return NULL;
1650 }
1651
1652 EAPI Eina_Bool
1653 edje_object_part_swallow(Evas_Object *obj, const char *part, Evas_Object *obj_swallow)
1654 {
1655    Edje *ed;
1656    Edje_Real_Part *rp;
1657
1658    ed = _edje_fetch(obj);
1659    if ((!ed) || (!part)) return EINA_FALSE;
1660
1661    /* Need to recalc before providing the object. */
1662    // XXX: I guess this is not required, removing for testing purposes
1663    // XXX: uncomment if you see glitches in e17 or others.
1664    // XXX: by Gustavo, January 21th 2009.
1665    // XXX: I got a backtrace with over 30000 calls without this,
1666    // XXX: only with 32px shelves. The problem is probably somewhere else,
1667    // XXX: but until it's found, leave this here.
1668    // XXX: by Sachiel, January 21th 2009, 19:30 UTC
1669    _edje_recalc_do(ed);
1670
1671    rp = _edje_real_part_recursive_get(ed, (char *)part);
1672    if (!rp) return EINA_FALSE;
1673    if (rp->part->type != EDJE_PART_TYPE_SWALLOW)
1674      {
1675         ERR("cannot unswallow part %s: not swallow type!", rp->part->name);
1676         return EINA_FALSE;
1677      }
1678    _edje_real_part_swallow(rp, obj_swallow);
1679    return EINA_TRUE;
1680 }
1681
1682 static void
1683 _recalc_extern_parent(Evas_Object *obj)
1684 {
1685    Evas_Object *parent;
1686    Edje *ed;
1687
1688    parent = evas_object_smart_parent_get(obj);
1689    ed = _edje_fetch(parent);
1690
1691    ed->dirty = 1;
1692    _edje_recalc(ed);
1693 }
1694
1695 EAPI void
1696 edje_extern_object_min_size_set(Evas_Object *obj, Evas_Coord minw, Evas_Coord minh)
1697 {
1698    Edje_Real_Part *rp;
1699
1700    evas_object_size_hint_min_set(obj, minw, minh);
1701    rp = evas_object_data_get(obj, "\377 edje.swallowing_part");
1702    if (rp)
1703      {
1704         rp->swallow_params.min.w = minw;
1705         rp->swallow_params.min.h = minh;
1706
1707         _recalc_extern_parent(obj);
1708      }
1709 }
1710
1711 EAPI void
1712 edje_extern_object_max_size_set(Evas_Object *obj, Evas_Coord maxw, Evas_Coord maxh)
1713 {
1714    Edje_Real_Part *rp;
1715
1716    evas_object_size_hint_max_set(obj, maxw, maxh);
1717    rp = evas_object_data_get(obj, "\377 edje.swallowing_part");
1718    if (rp)
1719      {
1720         rp->swallow_params.max.w = maxw;
1721         rp->swallow_params.max.h = maxh;
1722
1723         _recalc_extern_parent(obj);
1724      }
1725 }
1726
1727 EAPI void
1728 edje_extern_object_aspect_set(Evas_Object *obj, Edje_Aspect_Control aspect, Evas_Coord aw, Evas_Coord ah)
1729 {
1730    Edje_Real_Part *rp;
1731    Evas_Aspect_Control asp;
1732
1733    asp = EVAS_ASPECT_CONTROL_NONE;
1734    switch (aspect)
1735      {
1736       case EDJE_ASPECT_CONTROL_NONE: asp = EVAS_ASPECT_CONTROL_NONE; break;
1737       case EDJE_ASPECT_CONTROL_NEITHER: asp = EVAS_ASPECT_CONTROL_NEITHER; break;
1738       case EDJE_ASPECT_CONTROL_HORIZONTAL: asp = EVAS_ASPECT_CONTROL_HORIZONTAL; break;
1739       case EDJE_ASPECT_CONTROL_VERTICAL: asp = EVAS_ASPECT_CONTROL_VERTICAL; break;
1740       case EDJE_ASPECT_CONTROL_BOTH: asp = EVAS_ASPECT_CONTROL_BOTH; break;
1741       default: break;
1742      }
1743    if (aw < 1) aw = 1;
1744    if (ah < 1) ah = 1;
1745    evas_object_size_hint_aspect_set(obj, asp, aw, ah);
1746    rp = evas_object_data_get(obj, "\377 edje.swallowing_part");
1747    if (rp)
1748      {
1749         rp->swallow_params.aspect.mode = aspect;
1750         rp->swallow_params.aspect.w = aw;
1751         rp->swallow_params.aspect.h = ah;
1752         _recalc_extern_parent(obj);
1753      }
1754 }
1755
1756 struct edje_box_layout_builtin {
1757    const char *name;
1758    Evas_Object_Box_Layout cb;
1759 };
1760
1761 static Evas_Object_Box_Layout
1762 _edje_box_layout_builtin_find(const char *name)
1763 {
1764    const struct edje_box_layout_builtin _edje_box_layout_builtin[] = {
1765      {"horizontal", evas_object_box_layout_horizontal},
1766      {"horizontal_flow", evas_object_box_layout_flow_horizontal},
1767      {"horizontal_homogeneous", evas_object_box_layout_homogeneous_horizontal},
1768      {"horizontal_max", evas_object_box_layout_homogeneous_max_size_horizontal},
1769      {"stack", evas_object_box_layout_stack},
1770      {"vertical", evas_object_box_layout_vertical},
1771      {"vertical_flow", evas_object_box_layout_flow_vertical},
1772      {"vertical_homogeneous", evas_object_box_layout_homogeneous_vertical},
1773      {"vertical_max", evas_object_box_layout_homogeneous_max_size_vertical},
1774      {NULL, NULL}
1775    };
1776    const struct edje_box_layout_builtin *base;
1777
1778    switch (name[0])
1779      {
1780       case 'h':
1781          base = _edje_box_layout_builtin + 0;
1782          break;
1783       case 's':
1784          base = _edje_box_layout_builtin + 4;
1785          break;
1786       case 'v':
1787          base = _edje_box_layout_builtin + 5;
1788          break;
1789       default:
1790          return NULL;
1791      }
1792
1793    for (; (base->name) && (base->name[0] == name[0]); base++)
1794      if (strcmp(base->name, name) == 0)
1795        return base->cb;
1796
1797    return NULL;
1798 }
1799
1800 static Eina_Rbtree_Direction
1801 _edje_box_layout_external_node_cmp(const Eina_Rbtree *left, const Eina_Rbtree *right, __UNUSED__ void *data)
1802 {
1803    Edje_Box_Layout *l = (Edje_Box_Layout *)left;
1804    Edje_Box_Layout *r = (Edje_Box_Layout *)right;
1805
1806    if (strcmp(l->name, r->name) < 0)
1807      return EINA_RBTREE_RIGHT;
1808    else
1809      return EINA_RBTREE_LEFT;
1810 }
1811
1812 static int
1813 _edje_box_layout_external_find_cmp(const Eina_Rbtree *node, const void *key, __UNUSED__ int length, __UNUSED__ void *data)
1814 {
1815    Edje_Box_Layout *l = (Edje_Box_Layout *)node;
1816    return strcmp(key, l->name);
1817 }
1818
1819 static Edje_Box_Layout *
1820 _edje_box_layout_external_find(const char *name)
1821 {
1822    return (Edje_Box_Layout *)eina_rbtree_inline_lookup
1823      (_edje_box_layout_registry, name, 0, _edje_box_layout_external_find_cmp,
1824       NULL);
1825 }
1826
1827 Eina_Bool
1828 _edje_box_layout_find(const char *name, Evas_Object_Box_Layout *cb, void **data, void (**free_data)(void *data))
1829 {
1830    const Edje_Box_Layout *l;
1831
1832    if (!name) return EINA_FALSE;
1833
1834    *cb = _edje_box_layout_builtin_find(name);
1835    if (*cb)
1836      {
1837         *free_data = NULL;
1838         *data = NULL;
1839         return EINA_TRUE;
1840      }
1841
1842    l = _edje_box_layout_external_find(name);
1843    if (!l) return EINA_FALSE;
1844
1845    *cb = l->func;
1846    *free_data = l->layout_data_free;
1847    if (l->layout_data_get)
1848      *data = l->layout_data_get(l->data);
1849    else
1850      *data = NULL;
1851
1852    return EINA_TRUE;
1853 }
1854
1855 static void
1856 _edje_box_layout_external_free(Eina_Rbtree *node, __UNUSED__ void *data)
1857 {
1858    Edje_Box_Layout *l = (Edje_Box_Layout *)node;
1859
1860    if (l->data && l->free_data)
1861      l->free_data(l->data);
1862    free(l);
1863 }
1864
1865 static Edje_Box_Layout *
1866 _edje_box_layout_external_new(const char *name, Evas_Object_Box_Layout func, void *(*layout_data_get)(void *), void (*layout_data_free)(void *), void (*free_data)(void *), void *data)
1867 {
1868    Edje_Box_Layout *l;
1869    size_t name_len;
1870
1871    name_len = strlen(name) + 1;
1872    l = malloc(sizeof(Edje_Box_Layout) + name_len);
1873    if (!l)
1874      {
1875         perror("malloc");
1876         return NULL;
1877      }
1878
1879    l->func = func;
1880    l->layout_data_get = layout_data_get;
1881    l->layout_data_free = layout_data_free;
1882    l->free_data = free_data;
1883    l->data = data;
1884
1885    memcpy(l->name, name, name_len);
1886
1887    return l;
1888 }
1889
1890 EAPI void
1891 edje_box_layout_register(const char *name, Evas_Object_Box_Layout func, void *(*layout_data_get)(void *), void (*layout_data_free)(void *), void (*free_data)(void *), void *data)
1892 {
1893    Edje_Box_Layout *l;
1894
1895    if (!name) return;
1896
1897    if (_edje_box_layout_builtin_find(name))
1898      {
1899         ERR("Cannot register layout '%s': would override builtin!",
1900             name);
1901
1902         if (data && free_data) free_data(data);
1903         return;
1904      }
1905
1906    l = _edje_box_layout_external_find(name);
1907    if (!l)
1908      {
1909         if (!func)
1910           {
1911              if (data && free_data) free_data(data);
1912              return;
1913           }
1914
1915         l = _edje_box_layout_external_new
1916           (name, func, layout_data_get, layout_data_free, free_data, data);
1917         if (!l)
1918           return;
1919
1920         _edje_box_layout_registry = eina_rbtree_inline_insert
1921           (_edje_box_layout_registry, (Eina_Rbtree *)l,
1922            _edje_box_layout_external_node_cmp, NULL);
1923      }
1924    else
1925      {
1926         if (func)
1927           {
1928              if (l->data && l->free_data) l->free_data(l->data);
1929
1930              l->func = func;
1931              l->layout_data_get = layout_data_get;
1932              l->layout_data_free = layout_data_free;
1933              l->free_data = free_data;
1934              l->data = data;
1935           }
1936         else
1937           {
1938              if (data && free_data) free_data(data);
1939
1940              _edje_box_layout_registry = eina_rbtree_inline_remove
1941                (_edje_box_layout_registry, (Eina_Rbtree *)l,
1942                 _edje_box_layout_external_node_cmp, NULL);
1943              _edje_box_layout_external_free((Eina_Rbtree *)l, NULL);
1944           }
1945      }
1946 }
1947
1948 EAPI void
1949 edje_object_part_unswallow(Evas_Object *obj __UNUSED__, Evas_Object *obj_swallow)
1950 {
1951    Edje_Real_Part *rp;
1952
1953    if (!obj_swallow) return;
1954
1955    rp = (Edje_Real_Part *)evas_object_data_get(obj_swallow, "\377 edje.swallowing_part");
1956    if (!rp)
1957      return;
1958    if (rp->part->type != EDJE_PART_TYPE_SWALLOW)
1959      {
1960         ERR("cannot unswallow part %s: not swallow type!", rp->part->name);
1961         return;
1962      }
1963    if (rp->swallowed_object == obj_swallow)
1964      {
1965         evas_object_smart_member_del(rp->swallowed_object);
1966         evas_object_event_callback_del_full(rp->swallowed_object,
1967                                             EVAS_CALLBACK_FREE,
1968                                             _edje_object_part_swallow_free_cb,
1969                                             rp->edje->obj);
1970         evas_object_event_callback_del_full(rp->swallowed_object,
1971                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1972                                             _edje_object_part_swallow_changed_hints_cb,
1973                                             rp);
1974         evas_object_clip_unset(rp->swallowed_object);
1975         evas_object_data_del(rp->swallowed_object, "\377 edje.swallowing_part");
1976
1977         if (rp->part->mouse_events)
1978           _edje_callbacks_del(rp->swallowed_object, rp->edje);
1979         _edje_callbacks_focus_del(rp->swallowed_object, rp->edje);
1980
1981         rp->swallowed_object = NULL;
1982         rp->swallow_params.min.w = 0;
1983         rp->swallow_params.min.h = 0;
1984         rp->swallow_params.max.w = 0;
1985         rp->swallow_params.max.h = 0;
1986         rp->edje->dirty = 1;
1987 #ifdef EDJE_CALC_CACHE
1988         rp->invalidate = 1;
1989 #endif
1990         _edje_recalc_do(rp->edje);
1991         return;
1992      }
1993 }
1994
1995 EAPI Evas_Object *
1996 edje_object_part_swallow_get(const Evas_Object *obj, const char *part)
1997 {
1998    Edje *ed;
1999    Edje_Real_Part *rp;
2000
2001    ed = _edje_fetch(obj);
2002    if ((!ed) || (!part)) return NULL;
2003
2004    /* Need to recalc before providing the object. */
2005    _edje_recalc_do(ed);
2006
2007    rp = _edje_real_part_recursive_get(ed, (char *)part);
2008    if (!rp) return NULL;
2009    return rp->swallowed_object;
2010 }
2011
2012 EAPI void
2013 edje_object_size_min_get(const Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh)
2014 {
2015    Edje *ed;
2016
2017    ed = _edje_fetch(obj);
2018    if ((!ed) || (!ed->collection))
2019      {
2020         if (minw) *minw = 0;
2021         if (minh) *minh = 0;
2022         return;
2023      }
2024    if (minw) *minw = ed->collection->prop.min.w;
2025    if (minh) *minh = ed->collection->prop.min.h;
2026 }
2027
2028 EAPI void
2029 edje_object_size_max_get(const Evas_Object *obj, Evas_Coord *maxw, Evas_Coord *maxh)
2030 {
2031    Edje *ed;
2032
2033    ed = _edje_fetch(obj);
2034    if ((!ed) || (!ed->collection))
2035      {
2036         if (maxw) *maxw = 0;
2037         if (maxh) *maxh = 0;
2038         return;
2039      }
2040
2041    /* Need to recalc before providing the object. */
2042    _edje_recalc_do(ed);
2043
2044    if (ed->collection->prop.max.w == 0)
2045      {
2046         /* XXX TODO: convert maxw to 0, fix things that break. */
2047         if (maxw) *maxw = EDJE_INF_MAX_W;
2048      }
2049    else
2050      {
2051         if (maxw) *maxw = ed->collection->prop.max.w;
2052      }
2053    if (ed->collection->prop.max.h == 0)
2054      {
2055         /* XXX TODO: convert maxh to 0, fix things that break. */
2056         if (maxh) *maxh = EDJE_INF_MAX_H;
2057      }
2058    else
2059      {
2060         if (maxh) *maxh = ed->collection->prop.max.h;
2061      }
2062 }
2063
2064 EAPI void
2065 edje_object_calc_force(Evas_Object *obj)
2066 {
2067    Edje *ed;
2068    int pf, pf2;
2069
2070    ed = _edje_fetch(obj);
2071    if (!ed) return;
2072    ed->dirty = 1;
2073 #ifdef EDJE_CALC_CACHE
2074    ed->all_part_change = 1;
2075 #endif
2076
2077    pf2 = _edje_freeze_val;
2078    pf = ed->freeze;
2079
2080    _edje_freeze_val = 0;
2081    ed->freeze = 0;
2082
2083    _edje_recalc_do(ed);
2084
2085    ed->freeze = pf;
2086    _edje_freeze_val = pf2;
2087 }
2088
2089 EAPI void
2090 edje_object_size_min_calc(Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh)
2091 {
2092    edje_object_size_min_restricted_calc(obj, minw, minh, 0, 0);
2093 }
2094
2095 /** Calculate the geometry used by all parts
2096  * @param obj A valid Evas_Object handle
2097  * @param x The x coordinate pointer
2098  * @param y The y coordinate pointer
2099  * @param w The width pointer
2100  * @param h The height pointer
2101  *
2102  * Calculates the geometry used by all object parts. Including out of bounds parts.
2103  */
2104 EAPI Eina_Bool
2105 edje_object_parts_extends_calc(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
2106 {
2107    Edje *ed;
2108    Evas_Coord x1 = INT_MAX, y1 = INT_MAX;
2109    Evas_Coord x2 = 0, y2 = 0;
2110    unsigned int i;
2111
2112    ed = _edje_fetch(obj);
2113    if (!ed)
2114      {
2115         if (x) *x = 0;
2116         if (y) *y = 0;
2117         if (w) *w = 0;
2118         if (h) *h = 0;
2119         return EINA_FALSE;
2120      }
2121
2122    ed->calc_only = 1;
2123
2124    /* Need to recalc before providing the object. */
2125    ed->dirty = 1;
2126    _edje_recalc_do(ed);
2127
2128    for (i = 0; i < ed->table_parts_size; i++)
2129      {
2130         Edje_Real_Part *rp;
2131         Evas_Coord rpx1, rpy1;
2132         Evas_Coord rpx2, rpy2;
2133
2134         rp = ed->table_parts[i];
2135
2136         rpx1 = rp->x;
2137         rpy1 = rp->y;
2138         rpx2 = rpx1 + rp->w;
2139         rpy2 = rpy1 + rp->h;
2140
2141         if (x1 > rpx1) x1 = rpx1;
2142         if (y1 > rpy1) y1 = rpy1;
2143         if (x2 < rpx2) x2 = rpx2;
2144         if (y2 < rpy2) y2 = rpy2;
2145      }
2146
2147    ed->calc_only = 0;
2148
2149    *x = x1;
2150    *y = y1;
2151    *w = x2 - x1;
2152    *h = y2 - y1;
2153
2154    return EINA_TRUE;
2155 }
2156
2157 /** Calculate minimum size
2158  * @param obj A valid Evas_Object handle
2159  * @param minw Minimum width pointer
2160  * @param minh Minimum height pointer
2161  * @param restrictedw Do not allow object min width calc to be less than this
2162  * @param restrictedh Do not allow object min height calc to be less than this
2163  *
2164  * Calculates the object's minimum size ?! Be careful the behaviour of this
2165  * fonction is not really defined when a TEXTBLOCK part is present in the
2166  * Edje_Object. This may change in futur implementation.
2167  */
2168 EAPI void
2169 edje_object_size_min_restricted_calc(Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh, Evas_Coord restrictedw, Evas_Coord restrictedh)
2170 {
2171    Edje *ed;
2172    Evas_Coord pw, ph;
2173    int maxw, maxh;
2174    int ok;
2175    int reset_maxwh;
2176    Edje_Real_Part *pep = NULL;
2177    Eina_Bool has_non_fixed_tb = EINA_FALSE;
2178
2179    ed = _edje_fetch(obj);
2180    if ((!ed) || (!ed->collection))
2181      {
2182         if (minw) *minw = restrictedw;
2183         if (minh) *minh = restrictedh;
2184         return;
2185      }
2186    reset_maxwh = 1;
2187    ed->calc_only = 1;
2188    pw = ed->w;
2189    ph = ed->h;
2190
2191    again:
2192    ed->w = restrictedw;
2193    ed->h = restrictedh;
2194
2195    maxw = 0;
2196    maxh = 0;
2197
2198    ok = 1;
2199    while (ok)
2200      {
2201         unsigned int i;
2202
2203         ok = 0;
2204         ed->dirty = 1;
2205 #ifdef EDJE_CALC_CACHE
2206         ed->all_part_change = 1;
2207 #endif
2208         _edje_recalc_do(ed);
2209         if (reset_maxwh)
2210           {
2211              maxw = 0;
2212              maxh = 0;
2213           }
2214         pep = NULL;
2215         for (i = 0; i < ed->table_parts_size; i++)
2216           {
2217              Edje_Real_Part *ep;
2218              int w, h;
2219              int didw;
2220
2221              ep = ed->table_parts[i];
2222              w = ep->w - ep->req.w;
2223              h = ep->h - ep->req.h;
2224              didw = 0;
2225              if (ep->chosen_description)
2226                {
2227                   if (!ep->chosen_description->fixed.w)
2228                     {
2229                        if ((ep->part->type == EDJE_PART_TYPE_TEXTBLOCK))
2230                          {
2231                             Evas_Coord tb_mw;
2232                             evas_object_textblock_size_formatted_get(ep->object,
2233                                &tb_mw, NULL);
2234                             tb_mw -= ep->req.w;
2235                             if (tb_mw > w)
2236                               {
2237                                  w = tb_mw;
2238                               }
2239                             has_non_fixed_tb = EINA_TRUE;
2240                          }
2241                        if (w > maxw)
2242                          {
2243                             maxw = w;
2244                             ok = 1;
2245                             pep = ep;
2246                             didw = 1;
2247                          }
2248                     }
2249                   if (!ep->chosen_description->fixed.h)
2250                     {
2251                        if (!((ep->part->type == EDJE_PART_TYPE_TEXTBLOCK) &&
2252                              (!((Edje_Part_Description_Text *)ep->chosen_description)->text.min_x) &&
2253                              (didw)))
2254                          {
2255                             if (h > maxh)
2256                               {
2257                                  maxh = h;
2258                                  ok = 1;
2259                                  pep = ep;
2260                               }
2261                             has_non_fixed_tb = EINA_TRUE;
2262                          }
2263                     }
2264                }
2265           }
2266         if (ok)
2267           {
2268              ed->w += maxw;
2269              ed->h += maxh;
2270              if (ed->w < restrictedw) ed->w = restrictedw;
2271              if (ed->h < restrictedh) ed->h = restrictedh;
2272           }
2273         if ((ed->w > 4000) || (ed->h > 4000))
2274           {
2275              /* Only print it if we have a non-fixed textblock.
2276               * We should possibly avoid all of this if in this case, but in
2277               * the meanwhile, just doing this. */
2278              if (!has_non_fixed_tb)
2279                {
2280                   if (pep)
2281                      ERR("file %s, group %s has a non-fixed part '%s'. Adding 'fixed: 1 1;' to source EDC may help. Continuing discarding faulty part.",
2282                          ed->path, ed->group, pep->part->name);
2283                   else
2284                      ERR("file %s, group %s overflowed 4000x4000 with minimum size of %dx%d. Continuing discarding faulty parts.",
2285                          ed->path, ed->group, ed->w, ed->h);
2286                }
2287
2288              if (reset_maxwh)
2289                {
2290                   reset_maxwh = 0;
2291                   goto again;
2292                }
2293           }
2294      }
2295    ed->min.w = ed->w;
2296    ed->min.h = ed->h;
2297
2298    if (minw) *minw = ed->min.w;
2299    if (minh) *minh = ed->min.h;
2300
2301    ed->w = pw;
2302    ed->h = ph;
2303    ed->dirty = 1;
2304 #ifdef EDJE_CALC_CACHE
2305    ed->all_part_change = 1;
2306 #endif
2307    _edje_recalc(ed);
2308    ed->calc_only = 0;
2309 }
2310
2311 /* FIXME: Correctly return other states */
2312 EAPI const char *
2313 edje_object_part_state_get(const Evas_Object *obj, const char *part, double *val_ret)
2314 {
2315    Edje *ed;
2316    Edje_Real_Part *rp;
2317
2318    ed = _edje_fetch(obj);
2319    if ((!ed) || (!part))
2320      {
2321         if (val_ret) *val_ret = 0;
2322         return "";
2323      }
2324
2325    /* Need to recalc before providing the object. */
2326    _edje_recalc_do(ed);
2327
2328    rp = _edje_real_part_recursive_get(ed, (char *)part);
2329    if (!rp)
2330      {
2331         if (val_ret) *val_ret = 0;
2332         INF("part not found");
2333         return "";
2334      }
2335    if (rp->chosen_description)
2336      {
2337         if (val_ret) *val_ret = rp->chosen_description->state.value;
2338         if (rp->chosen_description->state.name)
2339           return rp->chosen_description->state.name;
2340         return "default";
2341      }
2342    else
2343      {
2344         if (rp->param1.description)
2345           {
2346              if (val_ret) *val_ret = rp->param1.description->state.value;
2347              if (rp->param1.description->state.name)
2348                return rp->param1.description->state.name;
2349              return "default";
2350           }
2351      }
2352    if (val_ret) *val_ret = 0;
2353    return "";
2354 }
2355
2356 EAPI Edje_Drag_Dir
2357 edje_object_part_drag_dir_get(const Evas_Object *obj, const char *part)
2358 {
2359    Edje *ed;
2360    Edje_Real_Part *rp;
2361
2362    ed = _edje_fetch(obj);
2363    if ((!ed) || (!part)) return EDJE_DRAG_DIR_NONE;
2364
2365    /* Need to recalc before providing the object. */
2366    _edje_recalc_do(ed);
2367
2368    rp = _edje_real_part_recursive_get(ed, (char *)part);
2369    if (!rp) return EDJE_DRAG_DIR_NONE;
2370    if ((rp->part->dragable.x) && (rp->part->dragable.y)) return EDJE_DRAG_DIR_XY;
2371    else if (rp->part->dragable.x) return EDJE_DRAG_DIR_X;
2372    else if (rp->part->dragable.y) return EDJE_DRAG_DIR_Y;
2373    return EDJE_DRAG_DIR_NONE;
2374 }
2375
2376 EAPI Eina_Bool
2377 edje_object_part_drag_value_set(Evas_Object *obj, const char *part, double dx, double dy)
2378 {
2379    Edje *ed;
2380    Edje_Real_Part *rp;
2381
2382    ed = _edje_fetch(obj);
2383    if ((!ed) || (!part)) return EINA_FALSE;
2384    rp = _edje_real_part_recursive_get(ed, (char *)part);
2385    if (!rp) return EINA_FALSE;
2386    if (!rp->drag) return EINA_FALSE;
2387    if (rp->drag->down.count > 0) return EINA_FALSE;
2388    if (rp->part->dragable.confine_id != -1)
2389      {
2390         dx = CLAMP(dx, 0.0, 1.0);
2391         dy = CLAMP(dy, 0.0, 1.0);
2392      }
2393    if (rp->part->dragable.x < 0) dx = 1.0 - dx;
2394    if (rp->part->dragable.y < 0) dy = 1.0 - dy;
2395    if ((rp->drag->val.x == FROM_DOUBLE(dx)) && (rp->drag->val.y == FROM_DOUBLE(dy))) return EINA_TRUE;
2396    rp->drag->val.x = FROM_DOUBLE(dx);
2397    rp->drag->val.y = FROM_DOUBLE(dy);
2398 #ifdef EDJE_CALC_CACHE
2399    rp->invalidate = 1;
2400 #endif
2401    _edje_dragable_pos_set(rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
2402    _edje_emit(rp->edje, "drag,set", rp->part->name);
2403    return EINA_TRUE;
2404 }
2405
2406 /* FIXME: Should this be x and y instead of dx/dy? */
2407 EAPI Eina_Bool
2408 edje_object_part_drag_value_get(const Evas_Object *obj, const char *part, double *dx, double *dy)
2409 {
2410    Edje *ed;
2411    Edje_Real_Part *rp;
2412    double ddx, ddy;
2413
2414    ed = _edje_fetch(obj);
2415    if ((!ed) || (!part))
2416      {
2417         if (dx) *dx = 0;
2418         if (dy) *dy = 0;
2419         return EINA_FALSE;
2420      }
2421
2422    /* Need to recalc before providing the object. */
2423    _edje_recalc_do(ed);
2424
2425    rp = _edje_real_part_recursive_get(ed, (char *)part);
2426    if (!rp || !rp->drag)
2427      {
2428         if (dx) *dx = 0;
2429         if (dy) *dy = 0;
2430         return EINA_FALSE;
2431      }
2432    ddx = TO_DOUBLE(rp->drag->val.x);
2433    ddy = TO_DOUBLE(rp->drag->val.y);
2434    if (rp->part->dragable.x < 0) ddx = 1.0 - ddx;
2435    if (rp->part->dragable.y < 0) ddy = 1.0 - ddy;
2436    if (dx) *dx = ddx;
2437    if (dy) *dy = ddy;
2438    return EINA_TRUE;
2439 }
2440
2441 EAPI Eina_Bool
2442 edje_object_part_drag_size_set(Evas_Object *obj, const char *part, double dw, double dh)
2443 {
2444    Edje *ed;
2445    Edje_Real_Part *rp;
2446
2447    ed = _edje_fetch(obj);
2448    if ((!ed) || (!part)) return EINA_FALSE;
2449    rp = _edje_real_part_recursive_get(ed, (char *)part);
2450    if (!rp) return EINA_FALSE;
2451    if (!rp->drag) return EINA_FALSE;
2452    if (dw < 0.0) dw = 0.0;
2453    else if (dw > 1.0) dw = 1.0;
2454    if (dh < 0.0) dh = 0.0;
2455    else if (dh > 1.0) dh = 1.0;
2456    if ((rp->drag->size.x == FROM_DOUBLE(dw)) && (rp->drag->size.y == FROM_DOUBLE(dh))) return EINA_TRUE;
2457    rp->drag->size.x = FROM_DOUBLE(dw);
2458    rp->drag->size.y = FROM_DOUBLE(dh);
2459    rp->edje->dirty = 1;
2460 #ifdef EDJE_CALC_CACHE
2461    rp->invalidate = 1;
2462 #endif
2463    _edje_recalc(rp->edje);
2464    return EINA_TRUE;
2465 }
2466
2467 EAPI Eina_Bool
2468 edje_object_part_drag_size_get(const Evas_Object *obj, const char *part, double *dw, double *dh)
2469 {
2470    Edje *ed;
2471    Edje_Real_Part *rp;
2472
2473    ed = _edje_fetch(obj);
2474    if ((!ed) || (!part))
2475      {
2476         if (dw) *dw = 0;
2477         if (dh) *dh = 0;
2478         return EINA_FALSE;
2479      }
2480
2481    /* Need to recalc before providing the object. */
2482    _edje_recalc_do(ed);
2483
2484    rp = _edje_real_part_recursive_get(ed, (char *)part);
2485    if (!rp || !rp->drag)
2486      {
2487         if (dw) *dw = 0;
2488         if (dh) *dh = 0;
2489         return EINA_FALSE;
2490      }
2491    if (dw) *dw = TO_DOUBLE(rp->drag->size.x);
2492    if (dh) *dh = TO_DOUBLE(rp->drag->size.y);
2493    return EINA_TRUE;
2494 }
2495
2496 EAPI Eina_Bool
2497 edje_object_part_drag_step_set(Evas_Object *obj, const char *part, double dx, double dy)
2498 {
2499    Edje *ed;
2500    Edje_Real_Part *rp;
2501
2502    ed = _edje_fetch(obj);
2503    if ((!ed) || (!part)) return EINA_FALSE;
2504    rp = _edje_real_part_recursive_get(ed, (char *)part);
2505    if (!rp) return EINA_FALSE;
2506    if (!rp->drag) return EINA_FALSE;
2507    if (dx < 0.0) dx = 0.0;
2508    else if (dx > 1.0) dx = 1.0;
2509    if (dy < 0.0) dy = 0.0;
2510    else if (dy > 1.0) dy = 1.0;
2511    rp->drag->step.x = FROM_DOUBLE(dx);
2512    rp->drag->step.y = FROM_DOUBLE(dy);
2513 #ifdef EDJE_CALC_CACHE
2514    rp->invalidate = 1;
2515 #endif
2516    return EINA_TRUE;
2517 }
2518
2519 EAPI Eina_Bool
2520 edje_object_part_drag_step_get(const Evas_Object *obj, const char *part, double *dx, double *dy)
2521 {
2522    Edje *ed;
2523    Edje_Real_Part *rp;
2524
2525    ed = _edje_fetch(obj);
2526    if ((!ed) || (!part))
2527      {
2528         if (dx) *dx = 0;
2529         if (dy) *dy = 0;
2530         return EINA_FALSE;
2531      }
2532
2533    /* Need to recalc before providing the object. */
2534    _edje_recalc_do(ed);
2535
2536    rp = _edje_real_part_recursive_get(ed, (char *)part);
2537    if (!rp || !rp->drag)
2538      {
2539         if (dx) *dx = 0;
2540         if (dy) *dy = 0;
2541         return EINA_FALSE;
2542      }
2543    if (dx) *dx = TO_DOUBLE(rp->drag->step.x);
2544    if (dy) *dy = TO_DOUBLE(rp->drag->step.y);
2545    return EINA_TRUE;
2546 }
2547
2548 EAPI Eina_Bool
2549 edje_object_part_drag_page_set(Evas_Object *obj, const char *part, double dx, double dy)
2550 {
2551    Edje *ed;
2552    Edje_Real_Part *rp;
2553
2554    ed = _edje_fetch(obj);
2555    if ((!ed) || (!part)) return EINA_FALSE;
2556    rp = _edje_real_part_recursive_get(ed, (char *)part);
2557    if (!rp) return EINA_FALSE;
2558    if (!rp->drag) return EINA_FALSE;
2559    if (dx < 0.0) dx = 0.0;
2560    else if (dx > 1.0) dx = 1.0;
2561    if (dy < 0.0) dy = 0.0;
2562    else if (dy > 1.0) dy = 1.0;
2563    rp->drag->page.x = FROM_DOUBLE(dx);
2564    rp->drag->page.y = FROM_DOUBLE(dy);
2565 #ifdef EDJE_CALC_CACHE
2566    rp->invalidate = 1;
2567 #endif
2568    return EINA_TRUE;
2569 }
2570
2571 EAPI Eina_Bool
2572 edje_object_part_drag_page_get(const Evas_Object *obj, const char *part, double *dx, double *dy)
2573 {
2574    Edje *ed;
2575    Edje_Real_Part *rp;
2576
2577    ed = _edje_fetch(obj);
2578    if ((!ed) || (!part))
2579      {
2580         if (dx) *dx = 0;
2581         if (dy) *dy = 0;
2582         return EINA_FALSE;
2583      }
2584
2585    /* Need to recalc before providing the object. */
2586    _edje_recalc_do(ed);
2587
2588    rp = _edje_real_part_recursive_get(ed, (char *)part);
2589    if (!rp || !rp->drag)
2590      {
2591         if (dx) *dx = 0;
2592         if (dy) *dy = 0;
2593         return EINA_FALSE;
2594      }
2595    if (dx) *dx = TO_DOUBLE(rp->drag->page.x);
2596    if (dy) *dy = TO_DOUBLE(rp->drag->page.y);
2597    return EINA_TRUE;
2598 }
2599
2600 EAPI Eina_Bool
2601 edje_object_part_drag_step(Evas_Object *obj, const char *part, double dx, double dy)
2602 {
2603    Edje *ed;
2604    Edje_Real_Part *rp;
2605    FLOAT_T px, py;
2606
2607    ed = _edje_fetch(obj);
2608    if ((!ed) || (!part)) return EINA_FALSE;
2609    rp = _edje_real_part_recursive_get(ed, (char *)part);
2610    if (!rp) return EINA_FALSE;
2611    if (!rp->drag) return EINA_FALSE;
2612    if (rp->drag->down.count > 0) return EINA_FALSE;
2613    px = rp->drag->val.x;
2614    py = rp->drag->val.y;
2615    rp->drag->val.x = ADD(px, MUL(FROM_DOUBLE(dx),
2616                                  MUL(rp->drag->step.x, rp->part->dragable.x)));
2617    rp->drag->val.y = ADD(py, MUL(FROM_DOUBLE(dy),
2618                                  MUL(rp->drag->step.y, rp->part->dragable.y)));
2619    rp->drag->val.x = CLAMP (rp->drag->val.x, ZERO, FROM_DOUBLE(1.0));
2620    rp->drag->val.y = CLAMP (rp->drag->val.y, ZERO, FROM_DOUBLE(1.0));
2621    if ((px == rp->drag->val.x) && (py == rp->drag->val.y)) return EINA_TRUE;
2622 #ifdef EDJE_CALC_CACHE
2623    rp->invalidate = 1;
2624 #endif
2625    _edje_dragable_pos_set(rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
2626    _edje_emit(rp->edje, "drag,step", rp->part->name);
2627    return EINA_TRUE;
2628 }
2629
2630 EAPI Eina_Bool
2631 edje_object_part_drag_page(Evas_Object *obj, const char *part, double dx, double dy)
2632 {
2633    Edje *ed;
2634    Edje_Real_Part *rp;
2635    FLOAT_T px, py;
2636
2637    ed = _edje_fetch(obj);
2638    if ((!ed) || (!part)) return EINA_FALSE;
2639    rp = _edje_real_part_recursive_get(ed, (char *)part);
2640    if (!rp) return EINA_FALSE;
2641    if (!rp->drag) return EINA_FALSE;
2642    if (rp->drag->down.count > 0) return EINA_FALSE;
2643    px = rp->drag->val.x;
2644    py = rp->drag->val.y;
2645    rp->drag->val.x = ADD(px, MUL(FROM_DOUBLE(dx), MUL(rp->drag->page.x, rp->part->dragable.x)));
2646    rp->drag->val.y = ADD(py, MUL(FROM_DOUBLE(dy), MUL(rp->drag->page.y, rp->part->dragable.y)));
2647    rp->drag->val.x = CLAMP (rp->drag->val.x, ZERO, FROM_DOUBLE(1.0));
2648    rp->drag->val.y = CLAMP (rp->drag->val.y, ZERO, FROM_DOUBLE(1.0));
2649    if ((px == rp->drag->val.x) && (py == rp->drag->val.y)) return EINA_TRUE;
2650 #ifdef EDJE_CALC_CACHE
2651    rp->invalidate = 1;
2652 #endif
2653    _edje_dragable_pos_set(rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
2654    _edje_emit(rp->edje, "drag,page", rp->part->name);
2655    return EINA_TRUE;
2656 }
2657
2658 void
2659 _edje_box_init(void)
2660 {
2661
2662 }
2663
2664 void
2665 _edje_box_shutdown(void)
2666 {
2667    if (!_edje_box_layout_registry)
2668      return;
2669
2670    eina_rbtree_delete
2671      (_edje_box_layout_registry, _edje_box_layout_external_free, NULL);
2672    _edje_box_layout_registry = NULL;
2673 }
2674
2675 EAPI Eina_Bool
2676 edje_object_part_box_append(Evas_Object *obj, const char *part, Evas_Object *child)
2677 {
2678    Edje *ed;
2679    Edje_Real_Part *rp;
2680
2681    ed = _edje_fetch(obj);
2682    if ((!ed) || (!part) || (!child)) return EINA_FALSE;
2683
2684    rp = _edje_real_part_recursive_get(ed, part);
2685    if (!rp) return EINA_FALSE;
2686    if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
2687
2688    return _edje_real_part_box_append(rp, child);
2689 }
2690
2691 EAPI Eina_Bool
2692 edje_object_part_box_prepend(Evas_Object *obj, const char *part, Evas_Object *child)
2693 {
2694    Edje *ed;
2695    Edje_Real_Part *rp;
2696
2697    ed = _edje_fetch(obj);
2698    if ((!ed) || (!part)) return EINA_FALSE;
2699
2700    rp = _edje_real_part_recursive_get(ed, part);
2701    if (!rp) return EINA_FALSE;
2702    if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
2703
2704    return _edje_real_part_box_prepend(rp, child);
2705 }
2706
2707 EAPI Eina_Bool
2708 edje_object_part_box_insert_before(Evas_Object *obj, const char *part, Evas_Object *child, const Evas_Object *reference)
2709 {
2710    Edje *ed;
2711    Edje_Real_Part *rp;
2712
2713    ed = _edje_fetch(obj);
2714    if ((!ed) || (!part)) return EINA_FALSE;
2715
2716    rp = _edje_real_part_recursive_get(ed, part);
2717    if (!rp) return EINA_FALSE;
2718    if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
2719
2720    return _edje_real_part_box_insert_before(rp, child, reference);
2721 }
2722
2723 EAPI Eina_Bool
2724 edje_object_part_box_insert_at(Evas_Object *obj, const char *part, Evas_Object *child, unsigned int pos)
2725 {
2726    Edje *ed;
2727    Edje_Real_Part *rp;
2728
2729    ed = _edje_fetch(obj);
2730    if ((!ed) || (!part)) return EINA_FALSE;
2731
2732    rp = _edje_real_part_recursive_get(ed, part);
2733    if (!rp) return EINA_FALSE;
2734    if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
2735
2736    return _edje_real_part_box_insert_at(rp, child, pos);
2737 }
2738
2739 EAPI Evas_Object *
2740 edje_object_part_box_remove(Evas_Object *obj, const char *part, Evas_Object *child)
2741 {
2742    Edje *ed;
2743    Edje_Real_Part *rp;
2744
2745    ed = _edje_fetch(obj);
2746    if ((!ed) || (!part)) return NULL;
2747
2748    rp = _edje_real_part_recursive_get(ed, part);
2749    if (!rp) return NULL;
2750    if (rp->part->type != EDJE_PART_TYPE_BOX) return NULL;
2751
2752    return _edje_real_part_box_remove(rp, child);
2753 }
2754
2755 EAPI Evas_Object *
2756 edje_object_part_box_remove_at(Evas_Object *obj, const char *part, unsigned int pos)
2757 {
2758    Edje *ed;
2759    Edje_Real_Part *rp;
2760
2761    ed = _edje_fetch(obj);
2762    if ((!ed) || (!part)) return NULL;
2763
2764    rp = _edje_real_part_recursive_get(ed, part);
2765    if (!rp) return NULL;
2766    if (rp->part->type != EDJE_PART_TYPE_BOX) return NULL;
2767
2768    return _edje_real_part_box_remove_at(rp, pos);
2769 }
2770
2771 EAPI Eina_Bool
2772 edje_object_part_box_remove_all(Evas_Object *obj, const char *part, Eina_Bool clear)
2773 {
2774    Edje *ed;
2775    Edje_Real_Part *rp;
2776
2777    ed = _edje_fetch(obj);
2778    if ((!ed) || (!part)) return EINA_FALSE;
2779
2780    rp = _edje_real_part_recursive_get(ed, part);
2781    if (!rp) return EINA_FALSE;
2782    if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
2783
2784    return _edje_real_part_box_remove_all(rp, clear);
2785
2786 }
2787
2788 static void
2789 _edje_box_child_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *child __UNUSED__, void *einfo __UNUSED__)
2790 {
2791    Edje_Real_Part *rp = data;
2792
2793    rp->edje->dirty = 1;
2794 #ifdef EDJE_CALC_CACHE
2795    rp->invalidate = 1;
2796 #endif
2797    _edje_recalc(rp->edje);
2798 }
2799
2800 static void
2801 _edje_box_child_add(Edje_Real_Part *rp, Evas_Object *child)
2802 {
2803    evas_object_event_callback_add
2804      (child, EVAS_CALLBACK_DEL, _edje_box_child_del_cb, rp);
2805
2806    rp->edje->dirty = 1;
2807 #ifdef EDJE_CALC_CACHE
2808    rp->invalidate = 1;
2809 #endif
2810    _edje_recalc(rp->edje);
2811 }
2812
2813 static void
2814 _edje_box_child_remove(Edje_Real_Part *rp, Evas_Object *child)
2815 {
2816    evas_object_event_callback_del_full
2817      (child, EVAS_CALLBACK_DEL, _edje_box_child_del_cb, rp);
2818
2819    rp->edje->dirty = 1;
2820 #ifdef EDJE_CALC_CACHE
2821    rp->invalidate = 1;
2822 #endif
2823    _edje_recalc(rp->edje);
2824 }
2825
2826 Eina_Bool
2827 _edje_real_part_box_append(Edje_Real_Part *rp, Evas_Object *child_obj)
2828 {
2829    Evas_Object_Box_Option *opt;
2830
2831    opt = evas_object_box_append(rp->object, child_obj);
2832    if (!opt) return EINA_FALSE;
2833
2834    if (!_edje_box_layout_add_child(rp, child_obj))
2835      {
2836         evas_object_box_remove(rp->object, child_obj);
2837         return EINA_FALSE;
2838      }
2839
2840    _edje_box_child_add(rp, child_obj);
2841
2842    return EINA_TRUE;
2843 }
2844
2845 Eina_Bool
2846 _edje_real_part_box_prepend(Edje_Real_Part *rp, Evas_Object *child_obj)
2847 {
2848    Evas_Object_Box_Option *opt;
2849
2850    opt = evas_object_box_prepend(rp->object, child_obj);
2851    if (!opt) return EINA_FALSE;
2852
2853    if (!_edje_box_layout_add_child(rp, child_obj))
2854      {
2855         evas_object_box_remove(rp->object, child_obj);
2856         return EINA_FALSE;
2857      }
2858
2859    _edje_box_child_add(rp, child_obj);
2860
2861    return EINA_TRUE;
2862 }
2863
2864 Eina_Bool
2865 _edje_real_part_box_insert_before(Edje_Real_Part *rp, Evas_Object *child_obj, const Evas_Object *ref)
2866 {
2867    Evas_Object_Box_Option *opt;
2868
2869    opt = evas_object_box_insert_before(rp->object, child_obj, ref);
2870    if (!opt) return EINA_FALSE;
2871
2872    if (!_edje_box_layout_add_child(rp, child_obj))
2873      {
2874         evas_object_box_remove(rp->object, child_obj);
2875         return EINA_FALSE;
2876      }
2877
2878    _edje_box_child_add(rp, child_obj);
2879
2880    return EINA_TRUE;
2881 }
2882
2883 Eina_Bool
2884 _edje_real_part_box_insert_at(Edje_Real_Part *rp, Evas_Object *child_obj, unsigned int pos)
2885 {
2886    Evas_Object_Box_Option *opt;
2887
2888    opt = evas_object_box_insert_at(rp->object, child_obj, pos);
2889    if (!opt) return EINA_FALSE;
2890
2891    if (!_edje_box_layout_add_child(rp, child_obj))
2892      {
2893         evas_object_box_remove(rp->object, child_obj);
2894         return EINA_FALSE;
2895      }
2896
2897    _edje_box_child_add(rp, child_obj);
2898
2899    return EINA_TRUE;
2900 }
2901
2902 Evas_Object *
2903 _edje_real_part_box_remove(Edje_Real_Part *rp, Evas_Object *child_obj)
2904 {
2905    if (evas_object_data_get(child_obj, "\377 edje.box_item")) return NULL;
2906    if (!evas_object_box_remove(rp->object, child_obj)) return NULL;
2907    _edje_box_layout_remove_child(rp, child_obj);
2908    _edje_box_child_remove(rp, child_obj);
2909    return child_obj;
2910 }
2911
2912 Evas_Object *
2913 _edje_real_part_box_remove_at(Edje_Real_Part *rp, unsigned int pos)
2914 {
2915    Evas_Object_Box_Option *opt;
2916    Evas_Object_Box_Data *priv;
2917    Evas_Object *child_obj;
2918
2919    priv = evas_object_smart_data_get(rp->object);
2920    opt = eina_list_nth(priv->children, pos);
2921    if (!opt) return NULL;
2922    child_obj = opt->obj;
2923    if (evas_object_data_get(child_obj, "\377 edje.box_item")) return NULL;
2924    if (!evas_object_box_remove_at(rp->object, pos)) return NULL;
2925    _edje_box_layout_remove_child(rp, child_obj);
2926    _edje_box_child_remove(rp, child_obj);
2927    return child_obj;
2928 }
2929
2930 Eina_Bool
2931 _edje_real_part_box_remove_all(Edje_Real_Part *rp, Eina_Bool clear)
2932 {
2933    Eina_List *children;
2934    int i = 0;
2935
2936    children = evas_object_box_children_get(rp->object);
2937    while (children)
2938      {
2939         Evas_Object *child_obj = children->data;
2940         if (evas_object_data_get(child_obj, "\377 edje.box_item"))
2941           i++;
2942         else
2943           {
2944              _edje_box_layout_remove_child(rp, child_obj);
2945              _edje_box_child_remove(rp, child_obj);
2946              if (!evas_object_box_remove_at(rp->object, i))
2947                return EINA_FALSE;
2948              if (clear)
2949                evas_object_del(child_obj);
2950           }
2951         children = eina_list_remove_list(children, children);
2952      }
2953    return EINA_TRUE;
2954 }
2955
2956 static void
2957 _edje_table_child_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *child __UNUSED__, void *einfo __UNUSED__)
2958 {
2959    Edje_Real_Part *rp = data;
2960
2961    rp->edje->dirty = 1;
2962 #ifdef EDJE_CALC_CACHE
2963    rp->invalidate = 1;
2964 #endif
2965    _edje_recalc(rp->edje);
2966 }
2967
2968 static void
2969 _edje_table_child_add(Edje_Real_Part *rp, Evas_Object *child)
2970 {
2971    evas_object_event_callback_add
2972      (child, EVAS_CALLBACK_DEL, _edje_table_child_del_cb, rp);
2973
2974    rp->edje->dirty = 1;
2975 #ifdef EDJE_CALC_CACHE
2976    rp->invalidate = 1;
2977 #endif
2978    _edje_recalc(rp->edje);
2979 }
2980
2981 static void
2982 _edje_table_child_remove(Edje_Real_Part *rp, Evas_Object *child)
2983 {
2984    evas_object_event_callback_del_full
2985      (child, EVAS_CALLBACK_DEL, _edje_table_child_del_cb, rp);
2986
2987    rp->edje->dirty = 1;
2988 #ifdef EDJE_CALC_CACHE
2989    rp->invalidate = 1;
2990 #endif
2991    _edje_recalc(rp->edje);
2992 }
2993
2994 EAPI Evas_Object *
2995 edje_object_part_table_child_get(Evas_Object *obj, const char *part, unsigned int col, unsigned int row)
2996 {
2997    Edje *ed;
2998    Edje_Real_Part *rp;
2999
3000    ed = _edje_fetch(obj);
3001    if ((!ed) || (!part)) return NULL;
3002
3003    rp = _edje_real_part_recursive_get(ed, part);
3004    if (!rp) return NULL;
3005    if (rp->part->type != EDJE_PART_TYPE_TABLE) return NULL;
3006
3007    return evas_object_table_child_get(rp->object, col, row);
3008 }
3009
3010 EAPI Eina_Bool
3011 edje_object_part_table_pack(Evas_Object *obj, const char *part, Evas_Object *child_obj, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
3012 {
3013    Edje *ed;
3014    Edje_Real_Part *rp;
3015
3016    ed = _edje_fetch(obj);
3017    if ((!ed) || (!part)) return EINA_FALSE;
3018
3019    rp = _edje_real_part_recursive_get(ed, part);
3020    if (!rp) return EINA_FALSE;
3021    if (rp->part->type != EDJE_PART_TYPE_TABLE) return EINA_FALSE;
3022
3023    return _edje_real_part_table_pack(rp, child_obj, col, row, colspan, rowspan);
3024 }
3025
3026 EAPI Eina_Bool
3027 edje_object_part_table_unpack(Evas_Object *obj, const char *part, Evas_Object *child_obj)
3028 {
3029    Edje *ed;
3030    Edje_Real_Part *rp;
3031
3032    ed = _edje_fetch(obj);
3033    if ((!ed) || (!part)) return EINA_FALSE;
3034
3035    rp = _edje_real_part_recursive_get(ed, part);
3036    if (!rp) return EINA_FALSE;
3037    if (rp->part->type != EDJE_PART_TYPE_TABLE) return EINA_FALSE;
3038
3039    return _edje_real_part_table_unpack(rp, child_obj);
3040 }
3041
3042 EAPI Eina_Bool
3043 edje_object_part_table_col_row_size_get(const Evas_Object *obj, const char *part, int *cols, int *rows)
3044 {
3045    Edje *ed;
3046    Edje_Real_Part *rp;
3047
3048    ed = _edje_fetch(obj);
3049    if ((!ed) || (!part)) return EINA_FALSE;
3050
3051    rp = _edje_real_part_recursive_get(ed, part);
3052    if (!rp) return EINA_FALSE;
3053    if (rp->part->type != EDJE_PART_TYPE_TABLE) return EINA_FALSE;
3054
3055    evas_object_table_col_row_size_get(rp->object, cols, rows);
3056    return EINA_TRUE;
3057 }
3058
3059 EAPI Eina_Bool
3060 edje_object_part_table_clear(Evas_Object *obj, const char *part, Eina_Bool clear)
3061 {
3062    Edje *ed;
3063    Edje_Real_Part *rp;
3064
3065    ed = _edje_fetch(obj);
3066    if ((!ed) || (!part)) return EINA_FALSE;
3067
3068    rp = _edje_real_part_recursive_get(ed, part);
3069    if (!rp) return EINA_FALSE;
3070    if (rp->part->type != EDJE_PART_TYPE_TABLE) return EINA_FALSE;
3071
3072    _edje_real_part_table_clear(rp, clear);
3073    return EINA_TRUE;
3074 }
3075
3076 static void
3077 _edje_perspective_obj_del(void *data, __UNUSED__ Evas *e, __UNUSED__ Evas_Object *obj, __UNUSED__ void *event_info)
3078 {
3079    Edje_Perspective *ps = data;
3080    Evas_Object *o;
3081
3082    EINA_LIST_FREE(ps->users, o)
3083      {
3084         Edje *ed;
3085
3086         ed = evas_object_smart_data_get(o);
3087         if (!ed) continue;
3088         ed->persp = NULL;
3089         ed->dirty = 1;
3090         _edje_recalc_do(ed);
3091      }
3092    free(ps);
3093 }
3094
3095 EAPI Edje_Perspective *
3096 edje_perspective_new(Evas *e)
3097 {
3098    Edje_Perspective *ps;
3099    Evas_Coord vx, vy, vw, vh;
3100
3101    if (!e) return NULL;
3102    ps = calloc(1, sizeof(Edje_Perspective));
3103    ps->obj = evas_object_rectangle_add(e);
3104    evas_object_data_set(ps->obj, "_edje_perspective", ps);
3105    evas_object_event_callback_add(ps->obj, EVAS_CALLBACK_DEL, _edje_perspective_obj_del, ps);
3106    evas_output_viewport_get(e, &vx, &vy, &vw, &vh);
3107    ps->e = e;
3108    ps->px = vx + (vw / 2);
3109    ps->py = vy + (vh / 2);
3110    ps->z0 = 0;
3111    ps->foc = 1000;
3112    return ps;
3113 }
3114
3115 EAPI void
3116 edje_perspective_free(Edje_Perspective *ps)
3117 {
3118    if (!ps) return;
3119    evas_object_del(ps->obj);
3120 }
3121
3122 EAPI void
3123 edje_perspective_set(Edje_Perspective *ps, Evas_Coord px, Evas_Coord py, Evas_Coord z0, Evas_Coord foc)
3124 {
3125    Eina_List *l;
3126    Evas_Object *o;
3127
3128    if (!ps) return;
3129    if ((ps->px == px) && (ps->py == py) && (ps->z0 == z0) && (ps->foc == foc)) return;
3130    ps->px = px;
3131    ps->py = py;
3132    ps->z0 = z0;
3133    ps->foc = foc;
3134    EINA_LIST_FOREACH(ps->users, l, o)
3135      {
3136         Edje *ed;
3137
3138         ed = evas_object_smart_data_get(o);
3139         if (!ed) continue;
3140         if (!ed->persp)
3141           {
3142              ed->dirty = 1;
3143              _edje_recalc_do(ed);
3144           }
3145      }
3146    if (ps->global)
3147      {
3148         EINA_LIST_FOREACH(_edje_edjes, l, o)
3149           {
3150              Edje *ed;
3151
3152              ed = evas_object_smart_data_get(o);
3153              if (!ed) continue;
3154              if (!ed->persp)
3155                {
3156                   ed->dirty = 1;
3157                   _edje_recalc_do(ed);
3158                }
3159           }
3160      }
3161 }
3162
3163 EAPI void
3164 edje_perspective_global_set(Edje_Perspective *ps, Eina_Bool global)
3165 {
3166    Evas_Object *o;
3167    Eina_List *l;
3168
3169    if (!ps) return;
3170    if (ps->global == global) return;
3171    if (global)
3172      {
3173         o = evas_object_name_find(evas_object_evas_get(ps->obj),
3174                                   "_edje_perspective");
3175         if (o) evas_object_name_set(o, NULL);
3176         evas_object_name_set(ps->obj, "_edje_perspective");
3177      }
3178    else
3179      evas_object_name_set(ps->obj, NULL);
3180    ps->global = global;
3181    EINA_LIST_FOREACH(_edje_edjes, l, o)
3182      {
3183         Edje *ed;
3184
3185         ed = evas_object_smart_data_get(o);
3186         if (!ed) continue;
3187         if (!ed->persp)
3188           {
3189              ed->dirty = 1;
3190              _edje_recalc_do(ed);
3191           }
3192      }
3193 }
3194
3195 EAPI Eina_Bool
3196 edje_perspective_global_get(const Edje_Perspective *ps)
3197 {
3198    if (!ps) return EINA_FALSE;
3199    return ps->global;
3200 }
3201
3202 EAPI const Edje_Perspective *
3203 edje_evas_global_perspective_get(const Evas *e)
3204 {
3205    Evas_Object *obj;
3206
3207    if (!e) return NULL;
3208    obj = evas_object_name_find(e, "_edje_perspective");
3209    if (!obj) return NULL;
3210    return evas_object_data_get(obj, "_edje_perspective");
3211 }
3212
3213 EAPI void
3214 edje_object_perspective_set(Evas_Object *obj, Edje_Perspective *ps)
3215 {
3216    Edje *ed;
3217
3218    ed = evas_object_smart_data_get(obj);
3219    if (!ed) return;
3220    if (ed->persp == ps) return;
3221    if (ed->persp != ps)
3222      {
3223         if (ed->persp)
3224           ed->persp->users = eina_list_remove(ed->persp->users, obj);
3225      }
3226    ed->persp = ps;
3227    if (ps) ps->users = eina_list_append(ps->users, obj);
3228    ed->dirty = 1;
3229    _edje_recalc_do(ed);
3230 }
3231
3232 EAPI const Edje_Perspective *
3233 edje_object_perspective_get(const Evas_Object *obj)
3234 {
3235    Edje *ed;
3236
3237    ed = evas_object_smart_data_get(obj);
3238    if (!ed) return NULL;
3239    return ed->persp;
3240 }
3241
3242 #define EDJE_PRELOAD_EMISSION "preload,done"
3243 #define EDJE_PRELOAD_SOURCE NULL
3244
3245 EAPI Eina_Bool
3246 edje_object_preload(Evas_Object *obj, Eina_Bool cancel)
3247 {
3248    Edje *ed;
3249    int count;
3250    unsigned int i;
3251
3252    ed = _edje_fetch(obj);
3253    if (!ed) return EINA_FALSE;
3254
3255    _edje_recalc_do(ed);
3256
3257    for (i = 0, count = 0; i < ed->table_parts_size; i++)
3258      {
3259         Edje_Real_Part *rp;
3260         Edje_Part *ep;
3261
3262         rp = ed->table_parts[i];
3263         ep = rp->part;
3264
3265         if (ep->type == EDJE_PART_TYPE_IMAGE ||
3266             (ep->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object))
3267           count++;
3268      }
3269
3270    ed->preload_count = count;
3271
3272    if (count > 0)
3273      {
3274         for (i = 0; i < ed->table_parts_size; i++)
3275           {
3276              Edje_Real_Part *rp;
3277              Edje_Part *ep;
3278
3279              rp = ed->table_parts[i];
3280              ep = rp->part;
3281
3282              if (ep->type == EDJE_PART_TYPE_IMAGE)
3283                {
3284                   const char *file = NULL;
3285                   const char *key = NULL;
3286
3287                   evas_object_event_callback_del_full(rp->object, EVAS_CALLBACK_IMAGE_PRELOADED, _edje_object_image_preload_cb, ed);
3288
3289                   evas_object_image_file_get(rp->object, &file, &key);
3290                   if (!file && !key)
3291                     {
3292                        ed->preload_count--;
3293                     }
3294                   else
3295                     {
3296                        evas_object_event_callback_add(rp->object, EVAS_CALLBACK_IMAGE_PRELOADED, _edje_object_image_preload_cb, ed);
3297                        evas_object_image_preload(rp->object, cancel);
3298                     }
3299                   count--;
3300                }
3301              else if (ep->type == EDJE_PART_TYPE_GROUP)
3302                {
3303                   if (rp->swallowed_object) {
3304                      edje_object_signal_callback_del(rp->swallowed_object, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE, _edje_object_signal_preload_cb);
3305                      edje_object_signal_callback_add(rp->swallowed_object, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE, _edje_object_signal_preload_cb, ed);
3306                      edje_object_preload(rp->swallowed_object, cancel);
3307
3308                      count--;
3309                   }
3310                }
3311           }
3312      }
3313    else
3314      {
3315         _edje_emit(ed, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE);
3316      }
3317
3318    return EINA_TRUE;
3319 }
3320
3321 Eina_Bool
3322 _edje_real_part_table_pack(Edje_Real_Part *rp, Evas_Object *child_obj, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
3323 {
3324    Eina_Bool ret =
3325      evas_object_table_pack(rp->object, child_obj, col, row, colspan, rowspan);
3326
3327    _edje_table_child_add(rp, child_obj);
3328
3329    return ret;
3330 }
3331
3332 Eina_Bool
3333 _edje_real_part_table_unpack(Edje_Real_Part *rp, Evas_Object *child_obj)
3334 {
3335    Eina_Bool ret = evas_object_table_unpack(rp->object, child_obj);
3336
3337    if (ret)
3338      _edje_table_child_remove(rp, child_obj);
3339
3340    return ret;
3341 }
3342
3343 void
3344 _edje_real_part_table_clear(Edje_Real_Part *rp, Eina_Bool clear)
3345 {
3346    Eina_List *children;
3347
3348    children = evas_object_table_children_get(rp->object);
3349    while (children)
3350      {
3351         Evas_Object *child_obj = children->data;
3352
3353         _edje_table_child_remove(rp, child_obj);
3354         if (!evas_object_data_get(child_obj, "\377 edje.table_item"))
3355           {
3356              evas_object_table_unpack(rp->object, child_obj);
3357              if (clear)
3358                evas_object_del(child_obj);
3359           }
3360         children = eina_list_remove_list(children, children);
3361      }
3362 }
3363
3364 Edje_Real_Part *
3365 _edje_real_part_recursive_get(const Edje *ed, const char *part)
3366 {
3367    Edje_Real_Part *rp;
3368    char **path;
3369
3370    path = eina_str_split(part, EDJE_PART_PATH_SEPARATOR_STRING, 0);
3371    if (!path) return NULL;
3372
3373    rp = _edje_real_part_recursive_get_helper(ed, path);
3374
3375    free(*path);
3376    free(path);
3377    return rp;
3378 }
3379
3380 Evas_Object *
3381 _edje_children_get(Edje_Real_Part *rp, const char *partid)
3382 {
3383    Evas_Object *child;
3384    Eina_List *l;
3385    long int v;
3386    char *p;
3387
3388    if (!partid) return NULL;
3389
3390    switch (rp->part->type)
3391      {
3392       case EDJE_PART_TYPE_EXTERNAL:
3393          return _edje_external_content_get(rp->swallowed_object, partid);
3394       case EDJE_PART_TYPE_BOX:
3395          l = evas_object_box_children_get(rp->object);
3396          break;
3397       case EDJE_PART_TYPE_TABLE:
3398          l = evas_object_table_children_get(rp->object);
3399          break;
3400       default:
3401          return NULL;
3402      }
3403
3404    v = strtol(partid, &p, 10);
3405    if ((*p == '\0') && (v >= 0))
3406      {
3407         child = eina_list_nth(l, v);
3408      }
3409    else
3410      {
3411         Evas_Object *cur;
3412         child = NULL;
3413         EINA_LIST_FREE(l, cur)
3414           {
3415              const char *name = evas_object_name_get(cur);
3416              if ((name) && (!strcmp(name, partid)))
3417                {
3418                   child = cur;
3419                   break;
3420                }
3421           }
3422      }
3423    eina_list_free(l);
3424
3425    return child;
3426 }
3427
3428 /* rebuild alternative path */
3429 char *
3430 _edje_merge_path(const char *alias, char * const *path)
3431 {
3432    char *tmp;
3433    unsigned int length = 1;
3434    unsigned int alias_length;
3435    unsigned int i;
3436
3437    if (!alias) return NULL;
3438
3439    alias_length = strlen(alias);
3440
3441    for (i = 0; path[i]; i++)
3442      length += strlen(path[i]) + 1;
3443
3444    tmp = malloc(sizeof (char) * (length + alias_length + 2));
3445    memcpy(tmp, alias, alias_length);
3446    tmp[alias_length] = '\0';
3447
3448    for (i = 0; path[i]; i++)
3449      {
3450         strcat(tmp, EDJE_PART_PATH_SEPARATOR_STRING);
3451         strcat(tmp, path[i]);
3452      }
3453
3454    return tmp;
3455 }
3456
3457
3458 Edje_Real_Part *
3459 _edje_real_part_recursive_get_helper(const Edje *ed, char **path)
3460 {
3461    Edje_Real_Part *rp;
3462    Evas_Object *child;
3463    char *idx = NULL;
3464
3465    if (!path[0])
3466      return NULL;
3467
3468    if (ed->collection && ed->collection->alias)
3469      {
3470         char *alias;
3471
3472         alias = _edje_merge_path(eina_hash_find(ed->collection->alias, path[0]), path + 1);
3473         if (alias) {
3474            rp = _edje_real_part_recursive_get(ed, alias);
3475            free(alias);
3476            return rp;
3477         }
3478      }
3479
3480    //printf("  lookup: %s on %s\n", path[0], ed->parent ? ed->parent : "-");
3481    idx = strchr(path[0], EDJE_PART_PATH_SEPARATOR_INDEXL);
3482    if (idx)
3483      {
3484         char *end;
3485
3486         end = strchr(idx + 1, EDJE_PART_PATH_SEPARATOR_INDEXR);
3487         if (end)
3488           {
3489              *end = '\0';
3490              *idx = '\0';
3491              idx++;
3492           }
3493      }
3494
3495    rp = _edje_real_part_get(ed, path[0]);
3496    if (!path[1] && !idx) return rp;
3497    if (!rp) return NULL;
3498
3499    switch (rp->part->type)
3500      {
3501       case EDJE_PART_TYPE_GROUP:
3502          if (!rp->swallowed_object) return NULL;
3503          ed = _edje_fetch(rp->swallowed_object);
3504          if (!ed) return NULL;
3505          path++;
3506          return _edje_real_part_recursive_get_helper(ed, path);
3507       case EDJE_PART_TYPE_BOX:
3508       case EDJE_PART_TYPE_TABLE:
3509       case EDJE_PART_TYPE_EXTERNAL:
3510          if (!idx) return rp;
3511          path++;
3512
3513          child = _edje_children_get(rp, idx);
3514
3515          ed = _edje_fetch(child);
3516
3517          if (!ed) return NULL;
3518          return _edje_real_part_recursive_get_helper(ed, path);
3519       default:
3520          return NULL;
3521      }
3522 }
3523
3524 /* Private Routines */
3525 Edje_Real_Part *
3526 _edje_real_part_get(const Edje *ed, const char *part)
3527 {
3528    unsigned int i;
3529
3530    if (!part) return NULL;
3531
3532    for (i = 0; i < ed->table_parts_size; i++)
3533      {
3534         Edje_Real_Part *rp;
3535
3536         rp = ed->table_parts[i];
3537         if ((rp->part->name) && (!strcmp(rp->part->name, part))) return rp;
3538      }
3539    return NULL;
3540 }
3541
3542 Edje_Color_Class *
3543 _edje_color_class_find(Edje *ed, const char *color_class)
3544 {
3545    Eina_List *l;
3546    Edje_Color_Class *cc = NULL;
3547
3548    if ((!ed) || (!color_class)) return NULL;
3549
3550    /* first look through the object scope */
3551    EINA_LIST_FOREACH(ed->color_classes, l, cc)
3552      if ((cc->name) && (!strcmp(color_class, cc->name))) return cc;
3553
3554    /* next look through the global scope */
3555    cc = eina_hash_find(_edje_color_class_hash, color_class);
3556    if (cc) return cc;
3557
3558    /* finally, look through the file scope */
3559    EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
3560      if ((cc->name) && (!strcmp(color_class, cc->name))) return cc;
3561
3562    return NULL;
3563 }
3564
3565 void
3566 _edje_color_class_member_add(Edje *ed, const char *color_class)
3567 {
3568    Eina_List *members;
3569
3570    if ((!ed) || (!color_class)) return;
3571    members = eina_hash_find(_edje_color_class_member_hash, color_class);
3572    if (members)
3573      eina_hash_del(_edje_color_class_member_hash, color_class, members);
3574
3575    members = eina_list_prepend(members, ed);
3576    if (!_edje_color_class_member_hash) _edje_color_class_member_hash = eina_hash_string_superfast_new(NULL);
3577    eina_hash_add(_edje_color_class_member_hash, color_class, members);
3578 }
3579
3580 void
3581 _edje_color_class_member_del(Edje *ed, const char *color_class)
3582 {
3583    Eina_List *members;
3584
3585    if ((!ed) || (!color_class)) return;
3586    members = eina_hash_find(_edje_color_class_member_hash, color_class);
3587    if (!members) return;
3588
3589    eina_hash_del(_edje_color_class_member_hash, color_class, members);
3590    members = eina_list_remove(members, ed);
3591    if (members)
3592      eina_hash_add(_edje_color_class_member_hash, color_class, members);
3593 }
3594
3595 /**
3596  * Used to free the member lists that are stored in the text_class and
3597  * color_class hashtables.
3598  */
3599 static Eina_Bool
3600 member_list_free(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
3601 {
3602    eina_list_free(data);
3603    return EINA_TRUE;
3604 }
3605
3606 void
3607 _edje_color_class_members_free(void)
3608 {
3609    if (!_edje_color_class_member_hash) return;
3610    eina_hash_foreach(_edje_color_class_member_hash, member_list_free, NULL);
3611    eina_hash_free(_edje_color_class_member_hash);
3612    _edje_color_class_member_hash = NULL;
3613 }
3614
3615 static Eina_Bool
3616 color_class_hash_list_free(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
3617 {
3618    Edje_Color_Class *cc;
3619
3620    cc = data;
3621    if (cc->name) eina_stringshare_del(cc->name);
3622    free(cc);
3623    return EINA_TRUE;
3624 }
3625
3626 void
3627 _edje_color_class_hash_free(void)
3628 {
3629    if (!_edje_color_class_hash) return;
3630    eina_hash_foreach(_edje_color_class_hash, color_class_hash_list_free, NULL);
3631    eina_hash_free(_edje_color_class_hash);
3632    _edje_color_class_hash = NULL;
3633 }
3634
3635 void
3636 _edje_color_class_on_del(Edje *ed, Edje_Part *ep)
3637 {
3638    unsigned int i;
3639
3640    if ((ep->default_desc) && (ep->default_desc->color_class))
3641      _edje_color_class_member_del(ed, ep->default_desc->color_class);
3642
3643    for (i = 0; i < ep->other.desc_count; ++i)
3644      if (ep->other.desc[i]->color_class)
3645        _edje_color_class_member_del(ed, ep->other.desc[i]->color_class);
3646 }
3647
3648 Edje_Text_Class *
3649 _edje_text_class_find(Edje *ed, const char *text_class)
3650 {
3651    Eina_List *l;
3652    Edje_Text_Class *tc;
3653
3654    if ((!ed) || (!text_class)) return NULL;
3655    EINA_LIST_FOREACH(ed->text_classes, l, tc)
3656      if ((tc->name) && (!strcmp(text_class, tc->name))) return tc;
3657    return eina_hash_find(_edje_text_class_hash, text_class);
3658 }
3659
3660 void
3661 _edje_text_class_member_add(Edje *ed, const char *text_class)
3662 {
3663    Eina_List *members;
3664
3665    if ((!ed) || (!text_class)) return;
3666
3667    /* Get members list */
3668    members = eina_hash_find(_edje_text_class_member_hash, text_class);
3669
3670    /* Remove members list */
3671    if (members)
3672      eina_hash_del(_edje_text_class_member_hash, text_class, members);
3673
3674    /* Update the member list */
3675    members = eina_list_prepend(members, ed);
3676
3677    /* Add the member list back */
3678    if (!_edje_text_class_member_hash)
3679      _edje_text_class_member_hash = eina_hash_string_superfast_new(NULL);
3680    eina_hash_add(_edje_text_class_member_hash, text_class, members);
3681 }
3682
3683 void
3684 _edje_text_class_member_del(Edje *ed, const char *text_class)
3685 {
3686    Eina_List *members;
3687
3688    if ((!ed) || (!text_class)) return;
3689    members = eina_hash_find(_edje_text_class_member_hash, text_class);
3690    if (!members) return;
3691
3692    eina_hash_del(_edje_text_class_member_hash, text_class, members);
3693
3694    members = eina_list_remove(members, ed);
3695    if (members)
3696      eina_hash_add(_edje_text_class_member_hash, text_class, members);
3697 }
3698
3699 void
3700 _edje_text_class_members_free(void)
3701 {
3702    if (!_edje_text_class_member_hash) return;
3703    eina_hash_foreach(_edje_text_class_member_hash, member_list_free, NULL);
3704    eina_hash_free(_edje_text_class_member_hash);
3705    _edje_text_class_member_hash = NULL;
3706 }
3707
3708 static Eina_Bool
3709 text_class_hash_list_free(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
3710 {
3711    Edje_Text_Class *tc;
3712
3713    tc = data;
3714    if (tc->name) eina_stringshare_del(tc->name);
3715    if (tc->font) eina_stringshare_del(tc->font);
3716    free(tc);
3717    return EINA_TRUE;
3718 }
3719
3720 void
3721 _edje_text_class_hash_free(void)
3722 {
3723    if (!_edje_text_class_hash) return;
3724    eina_hash_foreach(_edje_text_class_hash, text_class_hash_list_free, NULL);
3725    eina_hash_free(_edje_text_class_hash);
3726    _edje_text_class_hash = NULL;
3727 }
3728
3729 Edje *
3730 _edje_fetch(const Evas_Object *obj)
3731 {
3732    Edje *ed;
3733
3734    if (!evas_object_smart_type_check(obj, "edje"))
3735      return NULL;
3736    ed = evas_object_smart_data_get(obj);
3737    if ((ed) && (ed->delete_me)) return NULL;
3738    return ed;
3739 }
3740
3741 int
3742 _edje_freeze(Edje *ed)
3743 {
3744    ed->freeze++;
3745 //   printf("FREEZE %i\n", ed->freeze);
3746    return ed->freeze;
3747 }
3748
3749 int
3750 _edje_thaw(Edje *ed)
3751 {
3752    ed->freeze--;
3753    if (ed->freeze < 0)
3754      {
3755 //      printf("-------------########### OVER THAW\n");
3756         ed->freeze = 0;
3757      }
3758    if ((ed->freeze == 0) && (ed->recalc))
3759      {
3760 //      printf("thaw recalc\n");
3761         _edje_recalc(ed);
3762      }
3763    return ed->freeze;
3764 }
3765
3766 int
3767 _edje_block(Edje *ed)
3768 {
3769    _edje_ref(ed);
3770    ed->block++;
3771    return ed->block;
3772 }
3773
3774 int
3775 _edje_unblock(Edje *ed)
3776 {
3777    int ret = 0;
3778
3779    if (!ed) return ret;
3780
3781    ed->block--;
3782    if (ed->block == 0) ed->block_break = 0;
3783    ret = ed->block;
3784    _edje_unref(ed);
3785    return ret;
3786 }
3787
3788 int
3789 _edje_block_break(Edje *ed)
3790 {
3791    if (ed->block_break) return 1;
3792    return 0;
3793 }
3794
3795 void
3796 _edje_block_violate(Edje *ed)
3797 {
3798    if (ed->block > 0) ed->block_break = 1;
3799 }
3800
3801 void
3802 _edje_object_part_swallow_free_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
3803 {
3804    Evas_Object *edje_obj;
3805
3806    edje_obj = data;
3807    edje_object_part_unswallow(edje_obj, obj);
3808    return;
3809 }
3810
3811 static void
3812 _edje_real_part_swallow_hints_update(Edje_Real_Part *rp)
3813 {
3814    char *type;
3815
3816    type = (char *)evas_object_type_get(rp->swallowed_object);
3817
3818    rp->swallow_params.min.w = 0;
3819    rp->swallow_params.min.h = 0;
3820    rp->swallow_params.max.w = -1;
3821    rp->swallow_params.max.h = -1;
3822    if ((type) && (!strcmp(type, "edje")))
3823      {
3824         Evas_Coord w, h;
3825
3826         edje_object_size_min_get(rp->swallowed_object, &w, &h);
3827         rp->swallow_params.min.w = w;
3828         rp->swallow_params.min.h = h;
3829         edje_object_size_max_get(rp->swallowed_object, &w, &h);
3830         rp->swallow_params.max.w = w;
3831         rp->swallow_params.max.h = h;
3832      }
3833    else if ((type) && ((!strcmp(type, "text")) || (!strcmp(type, "polygon")) ||
3834                        (!strcmp(type, "line"))))
3835      {
3836         Evas_Coord w, h;
3837
3838         evas_object_geometry_get(rp->swallowed_object, NULL, NULL, &w, &h);
3839         rp->swallow_params.min.w = w;
3840         rp->swallow_params.min.h = h;
3841         rp->swallow_params.max.w = w;
3842         rp->swallow_params.max.h = h;
3843      }
3844      {
3845         Evas_Coord w1, h1, w2, h2, aw, ah;
3846         Evas_Aspect_Control am;
3847
3848         evas_object_size_hint_min_get(rp->swallowed_object, &w1, &h1);
3849         evas_object_size_hint_max_get(rp->swallowed_object, &w2, &h2);
3850         evas_object_size_hint_aspect_get(rp->swallowed_object, &am, &aw, &ah);
3851         rp->swallow_params.min.w = w1;
3852         rp->swallow_params.min.h = h1;
3853         if (w2 > 0) rp->swallow_params.max.w = w2;
3854         if (h2 > 0) rp->swallow_params.max.h = h2;
3855         switch (am)
3856           {
3857            case EVAS_ASPECT_CONTROL_NONE:
3858              rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_NONE;
3859              break;
3860            case EVAS_ASPECT_CONTROL_NEITHER:
3861              rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_NEITHER;
3862              break;
3863            case EVAS_ASPECT_CONTROL_HORIZONTAL:
3864              rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_HORIZONTAL;
3865              break;
3866            case EVAS_ASPECT_CONTROL_VERTICAL:
3867              rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_VERTICAL;
3868              break;
3869            case EVAS_ASPECT_CONTROL_BOTH:
3870              rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_BOTH;
3871              break;
3872            default:
3873              break;
3874           }
3875         rp->swallow_params.aspect.w = aw;
3876         rp->swallow_params.aspect.h = ah;
3877         evas_object_data_set(rp->swallowed_object, "\377 edje.swallowing_part", rp);
3878      }
3879
3880 #ifdef EDJE_CALC_CACHE
3881      rp->invalidate = 1;
3882 #endif
3883 }
3884
3885 void
3886 _edje_object_part_swallow_changed_hints_cb(void *data, __UNUSED__ Evas *e, __UNUSED__ Evas_Object *obj, __UNUSED__ void *event_info)
3887 {
3888    Edje_Real_Part *rp;
3889
3890    rp = data;
3891    _edje_real_part_swallow_hints_update(rp);
3892    rp->edje->dirty = 1;
3893    _edje_recalc(rp->edje);
3894    return;
3895 }
3896
3897 void
3898 _edje_real_part_swallow(Edje_Real_Part *rp, Evas_Object *obj_swallow)
3899 {
3900    if (rp->swallowed_object)
3901      {
3902         if (rp->swallowed_object != obj_swallow)
3903           {
3904              _edje_real_part_swallow_clear(rp);
3905              rp->swallowed_object = NULL;
3906           }
3907         else
3908           {
3909              _edje_real_part_swallow_hints_update(rp);
3910              rp->edje->dirty = 1;
3911              _edje_recalc(rp->edje);
3912              return;
3913           }
3914      }
3915 #ifdef EDJE_CALC_CACHE
3916    rp->invalidate = 1;
3917 #endif
3918    if (!obj_swallow) return;
3919    rp->swallowed_object = obj_swallow;
3920    evas_object_smart_member_add(rp->swallowed_object, rp->edje->obj);
3921    if (rp->clip_to)
3922      evas_object_clip_set(rp->swallowed_object, rp->clip_to->object);
3923    else evas_object_clip_set(rp->swallowed_object, rp->edje->base.clipper);
3924    evas_object_stack_above(rp->swallowed_object, rp->object);
3925    evas_object_event_callback_add(rp->swallowed_object,
3926                                   EVAS_CALLBACK_FREE,
3927                                   _edje_object_part_swallow_free_cb,
3928                                   rp->edje->obj);
3929    evas_object_event_callback_add(rp->swallowed_object,
3930                                   EVAS_CALLBACK_CHANGED_SIZE_HINTS,
3931                                   _edje_object_part_swallow_changed_hints_cb,
3932                                   rp);
3933
3934    _edje_real_part_swallow_hints_update(rp);
3935
3936    if (rp->part->mouse_events)
3937      {
3938         _edje_callbacks_add(obj_swallow, rp->edje, rp);
3939         if (rp->part->repeat_events)
3940            evas_object_repeat_events_set(obj_swallow, 1);
3941         if (rp->part->pointer_mode != EVAS_OBJECT_POINTER_MODE_AUTOGRAB)
3942           evas_object_pointer_mode_set(obj_swallow, rp->part->pointer_mode);
3943         evas_object_pass_events_set(obj_swallow, 0);
3944      }
3945    else
3946      evas_object_pass_events_set(obj_swallow, 1);
3947    _edje_callbacks_focus_add(rp->swallowed_object, rp->edje, rp);
3948
3949    if (rp->part->precise_is_inside)
3950      evas_object_precise_is_inside_set(obj_swallow, 1);
3951
3952    rp->edje->dirty = 1;
3953    _edje_recalc(rp->edje);
3954 }
3955
3956 void
3957 _edje_real_part_swallow_clear(Edje_Real_Part *rp)
3958 {
3959    evas_object_smart_member_del(rp->swallowed_object);
3960    evas_object_event_callback_del_full(rp->swallowed_object,
3961                                        EVAS_CALLBACK_FREE,
3962                                        _edje_object_part_swallow_free_cb,
3963                                        rp->edje->obj);
3964    evas_object_event_callback_del_full(rp->swallowed_object,
3965                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
3966                                        _edje_object_part_swallow_changed_hints_cb,
3967                                        rp);
3968    evas_object_clip_unset(rp->swallowed_object);
3969    evas_object_data_del(rp->swallowed_object, "\377 edje.swallowing_part");
3970    if (rp->part->mouse_events)
3971      _edje_callbacks_del(rp->swallowed_object, rp->edje);
3972    _edje_callbacks_focus_del(rp->swallowed_object, rp->edje);
3973 }
3974
3975 static void
3976 _edje_object_preload(Edje *ed)
3977 {
3978    ed->preload_count--;
3979    if (!ed->preload_count)
3980      _edje_emit(ed, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE);
3981 }
3982
3983 static void
3984 _edje_object_image_preload_cb(void *data, __UNUSED__ Evas *e, Evas_Object *obj, __UNUSED__ void *event_info)
3985 {
3986    Edje *ed = data;
3987
3988    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_IMAGE_PRELOADED, _edje_object_image_preload_cb, ed);
3989    _edje_object_preload(ed);
3990 }
3991
3992 static void
3993 _edje_object_signal_preload_cb(void *data, Evas_Object *obj, __UNUSED__ const char *emission, __UNUSED__ const char *source)
3994 {
3995    Edje *ed = data;
3996
3997    edje_object_signal_callback_del(obj, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE, _edje_object_signal_preload_cb);
3998    _edje_object_preload(ed);
3999 }
4000
4001 /**
4002  * @internal
4003  * 
4004  * for edje_cc
4005  */
4006 EAPI void
4007 _edje_program_remove(Edje_Part_Collection *edc, Edje_Program *p)
4008 {
4009    Edje_Program ***array;
4010    unsigned int *count;
4011    unsigned int i;
4012
4013    if (!p->signal && !p->source)
4014      {
4015         array = &edc->programs.nocmp;
4016         count = &edc->programs.nocmp_count;
4017      }
4018    else if (p->signal && !strpbrk(p->signal, "*?[\\")
4019             && p->source && !strpbrk(p->source, "*?[\\"))
4020      {
4021         array = &edc->programs.strcmp;
4022         count = &edc->programs.strcmp_count;
4023      }
4024    else if (p->signal && edje_program_is_strncmp(p->signal)
4025             && p->source && edje_program_is_strncmp(p->source))
4026      {
4027         array = &edc->programs.strncmp;
4028         count = &edc->programs.strncmp_count;
4029      }
4030    else if (p->signal && edje_program_is_strrncmp(p->signal)
4031             && p->source && edje_program_is_strrncmp(p->source))
4032      {
4033         array = &edc->programs.strrncmp;
4034         count = &edc->programs.strrncmp_count;
4035      }
4036    else
4037      {
4038         array = &edc->programs.fnmatch;
4039         count = &edc->programs.fnmatch_count;
4040      }
4041
4042    for (i = 0; i < *count; ++i)
4043      if ((*array)[i] == p)
4044        {
4045           memmove(*array + i, *array + i + 1, sizeof (Edje_Program *) * (*count - i -1));
4046           (*count)--;
4047           break;
4048        }
4049 }
4050
4051 /**
4052  * @internal
4053  * 
4054  * for edje_cc
4055  */
4056 EAPI void
4057 _edje_program_insert(Edje_Part_Collection *edc, Edje_Program *p)
4058 {
4059    Edje_Program ***array;
4060    unsigned int *count;
4061
4062    if (!p->signal && !p->source)
4063      {
4064         array = &edc->programs.nocmp;
4065         count = &edc->programs.nocmp_count;
4066      }
4067    else if (p->signal && !strpbrk(p->signal, "*?[\\")
4068             && p->source && !strpbrk(p->source, "*?[\\"))
4069      {
4070         array = &edc->programs.strcmp;
4071         count = &edc->programs.strcmp_count;
4072      }
4073    else if (p->signal && edje_program_is_strncmp(p->signal)
4074             && p->source && edje_program_is_strncmp(p->source))
4075      {
4076         array = &edc->programs.strncmp;
4077         count = &edc->programs.strncmp_count;
4078      }
4079    else if (p->signal && edje_program_is_strrncmp(p->signal)
4080             && p->source && edje_program_is_strrncmp(p->source))
4081      {
4082         array = &edc->programs.strrncmp;
4083         count = &edc->programs.strrncmp_count;
4084      }
4085    else
4086      {
4087         array = &edc->programs.fnmatch;
4088         count = &edc->programs.fnmatch_count;
4089      }
4090
4091    *array = realloc(*array, sizeof (Edje_Program *) * (*count + 1));
4092    (*array)[(*count)++] = p;
4093 }
4094
4095 const char *
4096 edje_string_get(const Edje_String *es)
4097 {
4098    /* FIXME: Handle localization here */
4099    if (!es) return NULL;
4100    return es->str;
4101 }
4102
4103 const char *
4104 edje_string_id_get(const Edje_String *es)
4105 {
4106    /* FIXME: Handle localization here */
4107    if (!es) return NULL;
4108    return es->str;
4109 }
4110
4111
4112 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/