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