1 #include "edje_private.h"
2 #define _ELLIP_STR "\xE2\x80\xA6"
4 /* returns with and height for this part.
6 * depending on the value of the use_alternate_font_metrics flag, it will
7 * either use evas_object_geometry_get() or the _advance_get() functions.
9 * The latter is useful if you want to make sure that width and height
10 * are the same value for the same number of characters in the text.
11 * This usually only makes sense for monospaced fonts.
13 * In future changes to this file, you probably should use this wrapper
14 * function everywhere instead of calling evas_object_geometry_get()
18 part_get_geometry(Edje_Real_Part *rp, Evas_Coord *w, Evas_Coord *h)
20 if (!rp->part->use_alternate_font_metrics)
21 evas_object_geometry_get(rp->object, NULL, NULL, w, h);
24 if (w) *w = evas_object_text_horiz_advance_get(rp->object);
25 if (h) *h = evas_object_text_vert_advance_get(rp->object);
35 _edje_text_part_on_add(Edje *ed, Edje_Real_Part *ep)
37 Edje_Part *pt = ep->part;
38 Edje_Part_Description_Text *desc;
41 if (ep->part->type != EDJE_PART_TYPE_TEXT) return;
43 /* if text class exists for this part, add the edje to the tc member list */
44 desc = (Edje_Part_Description_Text *) pt->default_desc;
45 if ((pt->default_desc) && (desc->text.text_class))
46 _edje_text_class_member_add(ed, desc->text.text_class);
48 /* If any other classes exist add them */
49 for (i = 0; i < pt->other.desc_count; ++i)
51 desc = (Edje_Part_Description_Text *) pt->other.desc[i];
52 if ((desc) && (desc->text.text_class))
53 _edje_text_class_member_add(ed, desc->text.text_class);
58 _edje_text_part_on_del(Edje *ed, Edje_Part *pt)
60 Edje_Part_Description_Text *desc;
63 if (pt->type != EDJE_PART_TYPE_TEXT
64 && pt->type != EDJE_PART_TYPE_TEXTBLOCK)
67 desc = (Edje_Part_Description_Text *) pt->default_desc;
68 if ((pt->default_desc) && (desc->text.text_class))
69 _edje_text_class_member_del(ed, desc->text.text_class);
71 for (i = 0; i < pt->other.desc_count; ++i)
73 desc = (Edje_Part_Description_Text *) pt->other.desc[i];
74 if (desc->text.text_class)
75 _edje_text_class_member_del(ed, desc->text.text_class);
80 _edje_text_fit_set(char *buf, const char *text, int c1, int c2)
82 /* helper function called from _edje_text_fit_x().
83 * note that we can use strcpy()/strcat() safely, the buffer lengths
84 * are checked in the caller.
89 strcpy(buf, _ELLIP_STR);
93 strncat(buf, text + c1, c2 - c1);
94 strcat(buf, _ELLIP_STR);
97 strcat(buf, text + c1);
103 strncpy(buf, text, c2);
105 strcat(buf, _ELLIP_STR);
113 _edje_text_fit_x(Edje *ed, Edje_Real_Part *ep,
114 Edje_Calc_Params *params,
115 const char *text, const char *font, int size,
116 Evas_Coord sw, int *free_text)
118 Evas_Coord tw = 0, th = 0, p;
122 int uc1 = -1, uc2 = -1, c1 = -1, c2 = -1;
128 if (sc == ZERO) sc = _edje_scale;
131 if (sw <= 1) return "";
133 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
134 evas_object_text_font_set(ep->object, font, size);
135 evas_object_text_text_set(ep->object, text);
137 part_get_geometry(ep, &tw, &th);
138 evas_object_text_style_pad_get(ep->object, &l, &r, NULL, NULL);
140 p = ((sw - tw) * params->type.text.elipsis);
145 if (params->type.text.elipsis != 0.0)
146 /* should be the last in text! not the rightmost */
147 uc1 = evas_object_text_last_up_to_pos(ep->object,
149 if (params->type.text.elipsis != 1.0)
150 /* should be the last in text! not the rightmost */
151 uc2 = evas_object_text_last_up_to_pos(ep->object,
152 -p + sw - r, th / 2);
153 if ((uc1 < 0) && (uc2 < 0))
160 if (!(((uc1 >= 0) || (uc2 >= 0)) && (tw > sw)))
163 if ((uc1 == 0) && (uc2 == 0))
166 orig_len = strlen(text);
168 /* don't overflow orig_len by adding extra
169 * FIXME: we might want to set a max string length somewhere...
171 extra = 1 + 3 + 3; /* terminator, leading and trailing ellipsis */
172 orig_len = MIN(orig_len, ((size_t) 8192 - extra));
174 if (!(buf = malloc(orig_len + extra)))
177 /* Convert uc1, uc2 -> c1, c2 */
182 for ( ; i < uc1 ; i++)
184 c1 = evas_string_char_next_get(text, c1, NULL);
190 for ( ; i < uc2 ; i++)
192 c2 = evas_string_char_next_get(text, c2, NULL);
198 while (((c1 >= 0) || (c2 >= 0)) && (tw > sw))
206 if ((c1 >= 0) && (c2 >= 0))
211 c1 = evas_string_char_next_get(text, c1, NULL);
217 c2 = evas_string_char_prev_get(text, c2, NULL);
229 c1 = evas_string_char_next_get(text, c1, NULL);
232 c2 = evas_string_char_prev_get(text, c2, NULL);
240 if ((c1 >= 0) && (c2 >= 0))
248 else if ((c1 > 0 && (size_t) c1 >= orig_len) || c2 == 0)
256 _edje_text_fit_set(buf, text, c1, c2);
258 evas_object_text_text_set(ep->object, buf);
259 part_get_geometry(ep, &tw, &th);
268 _edje_text_font_get(const char *base, const char *new, char **free_later)
270 const char *base_style, *new_style, *aux;
271 size_t font_len, style_len;
278 base_style = strstr(base, ":style=");
282 new_style = strstr(new, ":style=");
286 font_len = strlen(new);
287 aux = strchr(base_style, ',');
288 style_len = (aux) ? (size_t)(aux - base_style) : strlen(base_style);
290 *free_later = malloc(font_len + style_len + 1);
291 memcpy(*free_later, new, font_len);
292 memcpy(*free_later + font_len, base_style, style_len);
293 (*free_later)[font_len + style_len] = '\0';
299 _edje_text_class_font_get(Edje *ed, Edje_Part_Description_Text *chosen_desc, int *size, char **free_later)
302 const char *text_class_name, *font;
304 font = edje_string_get(&chosen_desc->text.font);
305 *size = chosen_desc->text.size;
307 text_class_name = chosen_desc->text.text_class;
308 if ((!text_class_name) || (!text_class_name[0]))
311 tc = _edje_text_class_find(ed, text_class_name);
315 font = _edje_text_font_get(edje_string_get(&chosen_desc->text.font), tc->font, free_later);
316 *size = _edje_text_size_calc(*size, tc);
322 _edje_text_recalc_apply(Edje *ed, Edje_Real_Part *ep,
323 Edje_Calc_Params *params,
324 Edje_Part_Description_Text *chosen_desc)
326 const char *text = NULL;
334 int inlined_font = 0, free_text = 0;
338 if (sc == 0.0) sc = _edje_scale;
339 text = edje_string_get(&chosen_desc->text.text);
340 font = _edje_text_class_font_get(ed, chosen_desc, &size, &sfont);
342 if (ep->text.text) text = (char *) ep->text.text;
343 if (ep->text.font) font = ep->text.font;
344 if (ep->text.size > 0) size = ep->text.size;
346 if (ep->text.text_source)
348 text = edje_string_get(&(((Edje_Part_Description_Text *)ep->text.text_source->chosen_description)->text.text));
349 if (ep->text.text_source->text.text) text = ep->text.text_source->text.text;
353 font = edje_string_get(&(((Edje_Part_Description_Text *)ep->text.source->chosen_description)->text.font));
354 size = ((Edje_Part_Description_Text *)ep->text.source->chosen_description)->text.size;
355 if (ep->text.source->text.font) font = ep->text.source->text.font;
356 if (ep->text.source->text.size > 0) size = ep->text.source->text.size;
359 if (!text) text = "";
360 if (!font) font = "";
362 /* check if the font is embedded in the .eet */
365 Edje_Font_Directory_Entry *fnt = eina_hash_find(ed->file->fonts, font);
371 size_t len = strlen(font) + sizeof("edje/fonts/") + 1;
373 sprintf(font2, "edje/fonts/%s", font);
379 if ((_edje_fontset_append) && (font))
381 font2 = malloc(strlen(font) + 1 + strlen(_edje_fontset_append) + 1);
386 strcat(font2, _edje_fontset_append);
393 evas_object_text_style_pad_get(ep->object, &l, &r, &t, &b);
398 size = params->type.text.size;
400 if ((ep->text.cache.in_size == size) &&
401 (ep->text.cache.in_w == sw) &&
402 (ep->text.cache.in_h == sh) &&
403 (ep->text.cache.in_str) &&
405 (!strcmp(ep->text.cache.in_str, text)) &&
406 (ep->text.cache.align_x == params->type.text.align.x) &&
407 (ep->text.cache.align_y == params->type.text.align.y) &&
408 (ep->text.cache.elipsis == params->type.text.elipsis) &&
409 (ep->text.cache.fit_x == chosen_desc->text.fit_x) &&
410 (ep->text.cache.fit_y == chosen_desc->text.fit_y))
412 text = (char *)ep->text.cache.out_str;
413 size = ep->text.cache.out_size;
415 if (!text) text = "";
419 if (ep->text.cache.in_str) eina_stringshare_del(ep->text.cache.in_str);
420 ep->text.cache.in_str = eina_stringshare_add(text);
421 ep->text.cache.in_size = size;
422 if (chosen_desc->text.fit_x && (ep->text.cache.in_str && eina_stringshare_strlen(ep->text.cache.in_str) > 0))
424 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
425 else evas_object_text_font_source_set(ep->object, NULL);
427 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
428 evas_object_text_font_set(ep->object, font, size);
429 evas_object_text_text_set(ep->object, text);
430 part_get_geometry(ep, &tw, &th);
433 while ((tw > sw) && (size > 0) && (tw != 0))
436 size = (size * sw) / tw;
437 if ((psize - size) <= 0) size = psize - 1;
438 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
439 else evas_object_text_font_source_set(ep->object, NULL);
441 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
442 evas_object_text_font_set(ep->object, font, size);
443 part_get_geometry(ep, &tw, &th);
444 if ((size > 0) && (tw == 0)) break;
449 while ((tw < sw) && (size > 0) && (tw != 0))
452 size = (size * sw) / tw;
453 /* fprintf(stderr, "size = %i (%i, %i)\n", size, sw, tw); */
454 if ((psize - size) >= 0) size = psize + 1;
455 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
456 else evas_object_text_font_source_set(ep->object, NULL);
458 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
459 evas_object_text_font_set(ep->object, font, size);
460 part_get_geometry(ep, &tw, &th);
461 if ((size > 0) && (tw == 0)) break;
465 if (chosen_desc->text.fit_y && (ep->text.cache.in_str && eina_stringshare_strlen(ep->text.cache.in_str) > 0))
467 /* if we fit in the x axis, too, size already has a somewhat
468 * meaningful value, so don't overwrite it with the starting
471 if (!chosen_desc->text.fit_x) size = sh;
473 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
474 else evas_object_text_font_source_set(ep->object, NULL);
476 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
477 evas_object_text_font_set(ep->object, font, size);
478 evas_object_text_text_set(ep->object, text);
479 part_get_geometry(ep, &tw, &th);
481 /* only grow the font size if we didn't already reach the max size
484 if (!chosen_desc->text.fit_x && th < sh)
489 if (dif < 1) dif = 1;
490 while ((th < sh) && (sw > 0))
493 if (size <= 0) break;
494 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
495 else evas_object_text_font_source_set(ep->object, NULL);
497 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
498 evas_object_text_font_set(ep->object, font, size);
499 part_get_geometry(ep, &tw, &th);
500 if ((size > 0) && (th == 0)) break;
508 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
509 evas_object_text_font_set(ep->object, font, 10);
510 part_get_geometry(ep, &tw, &th);
518 if (th < sh) bottom = 10;
519 else if (th > sh) bottom = 1;
520 else bottom = 0; /* XXX shut up GCC, th == sh is handled before! */
523 /* search one that fits (binary search) */
526 current = (top + bottom) / 2;
528 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
529 evas_object_text_font_set(ep->object, font, current);
530 part_get_geometry(ep, &tw, &th);
532 if (th < sh) bottom = current + 1;
533 else if (th > sh) top = current - 1;
534 } while ((bottom < top) && (th != sh));
537 /* search the larger one that fits (linear search) */
542 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
543 evas_object_text_font_set(ep->object, font, current);
544 part_get_geometry(ep, &tw, &th);
549 if (size < 1) size = 1;
551 if (!chosen_desc->text.fit_x)
553 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
554 else evas_object_text_font_source_set(ep->object, NULL);
556 text = _edje_text_fit_x(ed, ep, params, text, font, size, sw, &free_text);
559 str = eina_stringshare_add(text);
560 if (ep->text.cache.out_str) eina_stringshare_del(ep->text.cache.out_str);
561 ep->text.cache.out_str = str;
562 ep->text.cache.in_w = sw;
563 ep->text.cache.in_h = sh;
564 ep->text.cache.out_size = size;
565 ep->text.cache.align_x = params->type.text.align.x;
566 ep->text.cache.align_y = params->type.text.align.y;
567 ep->text.cache.elipsis = params->type.text.elipsis;
568 ep->text.cache.fit_x = chosen_desc->text.fit_x;
569 ep->text.cache.fit_y = chosen_desc->text.fit_y;
572 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
573 else evas_object_text_font_source_set(ep->object, NULL);
575 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
576 evas_object_text_font_set(ep->object, font, size);
577 evas_object_text_text_set(ep->object, text);
578 part_get_geometry(ep, &tw, &th);
579 /* Handle alignment */
582 if (params->type.text.align.x < 0.0)
584 if (evas_object_text_direction_get(ep->object) ==
585 EVAS_BIDI_DIRECTION_RTL)
596 align_x = params->type.text.align.x;
598 ep->text.offset.x = TO_INT(SCALE(align_x, (sw - tw)));
599 ep->text.offset.y = TO_INT(SCALE(params->type.text.align.y, (sh - th)));
602 evas_object_move(ep->object,
603 ed->x + params->x + ep->text.offset.x,
604 ed->y + params->y + ep->text.offset.y);
606 if (params->visible) evas_object_show(ep->object);
607 else evas_object_hide(ep->object);
609 Evas_Text_Style_Type style;
611 style = EVAS_TEXT_STYLE_PLAIN;
613 evas_object_color_set(ep->object,
614 (params->color.r * params->color.a) / 255,
615 (params->color.g * params->color.a) / 255,
616 (params->color.b * params->color.a) / 255,
619 if ((ep->part->effect == EDJE_TEXT_EFFECT_NONE) ||
620 (ep->part->effect == EDJE_TEXT_EFFECT_PLAIN))
622 style = EVAS_TEXT_STYLE_PLAIN;
624 else if (ep->part->effect == EDJE_TEXT_EFFECT_OUTLINE)
626 style = EVAS_TEXT_STYLE_OUTLINE;
627 evas_object_text_outline_color_set(ep->object,
628 (params->type.text.color2.r * params->type.text.color2.a) / 255,
629 (params->type.text.color2.g * params->type.text.color2.a) / 255,
630 (params->type.text.color2.b * params->type.text.color2.a) / 255,
631 params->type.text.color2.a);
633 else if (ep->part->effect == EDJE_TEXT_EFFECT_SOFT_OUTLINE)
635 style = EVAS_TEXT_STYLE_SOFT_OUTLINE;
636 evas_object_text_outline_color_set(ep->object,
637 (params->type.text.color2.r * params->type.text.color2.a) / 255,
638 (params->type.text.color2.g * params->type.text.color2.a) / 255,
639 (params->type.text.color2.b * params->type.text.color2.a) / 255,
640 params->type.text.color2.a);
642 else if (ep->part->effect == EDJE_TEXT_EFFECT_SHADOW)
644 style = EVAS_TEXT_STYLE_SHADOW;
645 evas_object_text_shadow_color_set(ep->object,
646 (params->type.text.color3.r * params->type.text.color3.a) / 255,
647 (params->type.text.color3.g * params->type.text.color3.a) / 255,
648 (params->type.text.color3.b * params->type.text.color3.a) / 255,
649 params->type.text.color3.a);
651 else if (ep->part->effect == EDJE_TEXT_EFFECT_SOFT_SHADOW)
653 style = EVAS_TEXT_STYLE_SOFT_SHADOW;
654 evas_object_text_shadow_color_set(ep->object,
655 (params->type.text.color3.r * params->type.text.color3.a) / 255,
656 (params->type.text.color3.g * params->type.text.color3.a) / 255,
657 (params->type.text.color3.b * params->type.text.color3.a) / 255,
658 params->type.text.color3.a);
660 else if (ep->part->effect == EDJE_TEXT_EFFECT_OUTLINE_SHADOW)
662 style = EVAS_TEXT_STYLE_OUTLINE_SHADOW;
663 evas_object_text_outline_color_set(ep->object,
664 (params->type.text.color2.r * params->type.text.color2.a) / 255,
665 (params->type.text.color2.g * params->type.text.color2.a) / 255,
666 (params->type.text.color2.b * params->type.text.color2.a) / 255,
667 params->type.text.color2.a);
668 evas_object_text_shadow_color_set(ep->object,
669 (params->type.text.color3.r * params->type.text.color3.a) / 255,
670 (params->type.text.color3.g * params->type.text.color3.a) / 255,
671 (params->type.text.color3.b * params->type.text.color3.a) / 255,
672 params->type.text.color3.a);
674 else if (ep->part->effect == EDJE_TEXT_EFFECT_OUTLINE_SOFT_SHADOW)
676 style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW;
677 evas_object_text_outline_color_set(ep->object,
678 (params->type.text.color2.r * params->type.text.color2.a) / 255,
679 (params->type.text.color2.g * params->type.text.color2.a) / 255,
680 (params->type.text.color2.b * params->type.text.color2.a) / 255,
681 params->type.text.color2.a);
682 evas_object_text_shadow_color_set(ep->object,
683 (params->type.text.color3.r * params->type.text.color3.a) / 255,
684 (params->type.text.color3.g * params->type.text.color3.a) / 255,
685 (params->type.text.color3.b * params->type.text.color3.a) / 255,
686 params->type.text.color3.a);
688 else if (ep->part->effect == EDJE_TEXT_EFFECT_FAR_SHADOW)
690 style = EVAS_TEXT_STYLE_FAR_SHADOW;
691 evas_object_text_shadow_color_set(ep->object,
692 (params->type.text.color3.r * params->type.text.color3.a) / 255,
693 (params->type.text.color3.g * params->type.text.color3.a) / 255,
694 (params->type.text.color3.b * params->type.text.color3.a) / 255,
695 params->type.text.color3.a);
697 else if (ep->part->effect == EDJE_TEXT_EFFECT_FAR_SOFT_SHADOW)
699 style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW;
700 evas_object_text_shadow_color_set(ep->object,
701 (params->type.text.color3.r * params->type.text.color3.a) / 255,
702 (params->type.text.color3.g * params->type.text.color3.a) / 255,
703 (params->type.text.color3.b * params->type.text.color3.a) / 255,
704 params->type.text.color3.a);
706 else if (ep->part->effect == EDJE_TEXT_EFFECT_GLOW)
708 style = EVAS_TEXT_STYLE_GLOW;
709 evas_object_text_glow_color_set(ep->object,
710 (params->type.text.color2.r * params->type.text.color2.a) / 255,
711 (params->type.text.color2.g * params->type.text.color2.a) / 255,
712 (params->type.text.color2.b * params->type.text.color2.a) / 255,
713 params->type.text.color2.a);
714 evas_object_text_glow2_color_set(ep->object,
715 (params->type.text.color3.r * params->type.text.color3.a) / 255,
716 (params->type.text.color3.g * params->type.text.color3.a) / 255,
717 (params->type.text.color3.b * params->type.text.color3.a) / 255,
718 params->type.text.color3.a);
720 evas_object_text_style_set(ep->object, style);
732 _edje_text_size_calc(Evas_Font_Size size, Edje_Text_Class *tc)
740 else if (tc->size > 0.0)
746 val = (size * -tc->size) / 100;