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;
64 if (pt->type != EDJE_PART_TYPE_TEXT
65 && pt->type != EDJE_PART_TYPE_TEXTBLOCK)
68 desc = (Edje_Part_Description_Text *) pt->default_desc;
69 if ((pt->default_desc) && (desc->text.text_class))
70 _edje_text_class_member_del(ed, desc->text.text_class);
72 for (i = 0; i < pt->other.desc_count; ++i)
74 desc = (Edje_Part_Description_Text *) pt->other.desc[i];
75 if (desc->text.text_class)
76 _edje_text_class_member_del(ed, desc->text.text_class);
81 _edje_text_fit_set(char *buf, const char *text, int c1, int c2)
83 /* helper function called from _edje_text_fit_x().
84 * note that we can use strcpy()/strcat() safely, the buffer lengths
85 * are checked in the caller.
90 strcpy(buf, _ELLIP_STR);
94 strncat(buf, text + c1, c2 - c1);
95 strcat(buf, _ELLIP_STR);
98 strcat(buf, text + c1);
104 strncpy(buf, text, c2);
106 strcat(buf, _ELLIP_STR);
114 _edje_text_fit_x(Edje *ed, Edje_Real_Part *ep,
115 Edje_Calc_Params *params,
116 const char *text, const char *font, int size,
117 Evas_Coord sw, int *free_text)
119 Evas_Coord tw = 0, th = 0, p;
123 int uc1 = -1, uc2 = -1, c1 = -1, c2 = -1;
129 if (sc == ZERO) sc = _edje_scale;
132 if (sw <= 1) return "";
134 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
135 evas_object_text_font_set(ep->object, font, size);
136 evas_object_text_text_set(ep->object, text);
138 part_get_geometry(ep, &tw, &th);
139 evas_object_text_style_pad_get(ep->object, &l, &r, NULL, NULL);
141 p = ((sw - tw) * params->type.text.elipsis);
146 if (params->type.text.elipsis != 0.0)
147 /* should be the last in text! not the rightmost */
148 uc1 = evas_object_text_last_up_to_pos(ep->object,
150 if (params->type.text.elipsis != 1.0)
152 /* should be the last in text! not the rightmost */
153 if ((-p + sw -r) < 0)
154 uc2 = evas_object_text_last_up_to_pos(ep->object, 0, th / 2);
156 uc2 = evas_object_text_last_up_to_pos(ep->object,
157 -p + sw - r, th / 2);
159 if ((uc1 < 0) && (uc2 < 0))
166 if (!(((uc1 >= 0) || (uc2 >= 0)) && (tw > sw)))
169 if ((uc1 == 0) && (uc2 == 0))
172 orig_len = strlen(text);
174 /* don't overflow orig_len by adding extra
175 * FIXME: we might want to set a max string length somewhere...
177 extra = 1 + 3 + 3; /* terminator, leading and trailing ellipsis */
178 orig_len = MIN(orig_len, ((size_t) 8192 - extra));
180 if (!(buf = malloc(orig_len + extra)))
183 /* Convert uc1, uc2 -> c1, c2 */
188 for ( ; i < uc1 ; i++)
190 c1 = evas_string_char_next_get(text, c1, NULL);
196 for ( ; i < uc2 ; i++)
198 c2 = evas_string_char_next_get(text, c2, NULL);
204 while (((c1 >= 0) || (c2 >= 0)) && (tw > sw))
212 if ((c1 >= 0) && (c2 >= 0))
217 c1 = evas_string_char_next_get(text, c1, NULL);
223 c2 = evas_string_char_prev_get(text, c2, NULL);
235 c1 = evas_string_char_next_get(text, c1, NULL);
238 c2 = evas_string_char_prev_get(text, c2, NULL);
246 if ((c1 >= 0) && (c2 >= 0))
254 else if ((c1 > 0 && (size_t) c1 >= orig_len) || c2 == 0)
262 _edje_text_fit_set(buf, text, c1, c2);
264 evas_object_text_text_set(ep->object, buf);
265 part_get_geometry(ep, &tw, &th);
274 _edje_text_font_get(const char *base, const char *new, char **free_later)
276 const char *base_style, *new_style, *aux;
277 size_t font_len, style_len;
284 base_style = strstr(base, ":style=");
288 new_style = strstr(new, ":style=");
292 font_len = strlen(new);
293 aux = strchr(base_style, ',');
294 style_len = (aux) ? (size_t)(aux - base_style) : strlen(base_style);
296 *free_later = malloc(font_len + style_len + 1);
297 memcpy(*free_later, new, font_len);
298 memcpy(*free_later + font_len, base_style, style_len);
299 (*free_later)[font_len + style_len] = '\0';
305 _edje_text_class_font_get(Edje *ed, Edje_Part_Description_Text *chosen_desc, int *size, char **free_later)
308 const char *text_class_name, *font;
310 font = edje_string_get(&chosen_desc->text.font);
311 *size = chosen_desc->text.size;
313 text_class_name = chosen_desc->text.text_class;
314 if ((!text_class_name) || (!text_class_name[0]))
317 tc = _edje_text_class_find(ed, text_class_name);
321 font = _edje_text_font_get(edje_string_get(&chosen_desc->text.font), tc->font, free_later);
322 *size = _edje_text_size_calc(*size, tc);
328 _edje_text_recalc_apply(Edje *ed, Edje_Real_Part *ep,
329 Edje_Calc_Params *params,
330 Edje_Part_Description_Text *chosen_desc)
332 const char *text = NULL;
340 int inlined_font = 0, free_text = 0;
344 if (sc == 0.0) sc = _edje_scale;
345 text = edje_string_get(&chosen_desc->text.text);
346 font = _edje_text_class_font_get(ed, chosen_desc, &size, &sfont);
348 if (ep->text.text) text = (char *) ep->text.text;
349 if (ep->text.font) font = ep->text.font;
350 if (ep->text.size > 0) size = ep->text.size;
352 if (ep->text.text_source)
354 text = edje_string_get(&(((Edje_Part_Description_Text *)ep->text.text_source->chosen_description)->text.text));
355 if (ep->text.text_source->text.text) text = ep->text.text_source->text.text;
359 font = edje_string_get(&(((Edje_Part_Description_Text *)ep->text.source->chosen_description)->text.font));
360 size = ((Edje_Part_Description_Text *)ep->text.source->chosen_description)->text.size;
361 if (ep->text.source->text.font) font = ep->text.source->text.font;
362 if (ep->text.source->text.size > 0) size = ep->text.source->text.size;
365 if (!text) text = "";
366 if (!font) font = "";
368 /* check if the font is embedded in the .eet */
371 Edje_Font_Directory_Entry *fnt = eina_hash_find(ed->file->fonts, font);
377 size_t len = strlen(font) + sizeof("edje/fonts/") + 1;
379 sprintf(font2, "edje/fonts/%s", font);
385 if ((_edje_fontset_append) && (font))
387 font2 = malloc(strlen(font) + 1 + strlen(_edje_fontset_append) + 1);
392 strcat(font2, _edje_fontset_append);
399 evas_object_text_style_pad_get(ep->object, &l, &r, &t, &b);
404 size = params->type.text.size;
406 if ((ep->text.cache.in_size == size) &&
407 (ep->text.cache.in_w == sw) &&
408 (ep->text.cache.in_h == sh) &&
409 (ep->text.cache.in_str) &&
411 (!strcmp(ep->text.cache.in_str, text)) &&
412 (ep->text.cache.align_x == params->type.text.align.x) &&
413 (ep->text.cache.align_y == params->type.text.align.y) &&
414 (ep->text.cache.elipsis == params->type.text.elipsis) &&
415 (ep->text.cache.fit_x == chosen_desc->text.fit_x) &&
416 (ep->text.cache.fit_y == chosen_desc->text.fit_y))
418 text = (char *)ep->text.cache.out_str;
419 size = ep->text.cache.out_size;
421 if (!text) text = "";
425 if (ep->text.cache.in_str) eina_stringshare_del(ep->text.cache.in_str);
426 ep->text.cache.in_str = eina_stringshare_add(text);
427 ep->text.cache.in_size = size;
428 if (chosen_desc->text.fit_x && (ep->text.cache.in_str && eina_stringshare_strlen(ep->text.cache.in_str) > 0))
430 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
431 else evas_object_text_font_source_set(ep->object, NULL);
433 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
434 evas_object_text_font_set(ep->object, font, size);
435 evas_object_text_text_set(ep->object, text);
436 part_get_geometry(ep, &tw, &th);
437 /* Find the wanted font size */
438 if ((tw > sw) && (size > 0) && (tw != 0))
440 size = (size * sw) / tw;
442 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
443 else evas_object_text_font_source_set(ep->object, NULL);
445 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
446 evas_object_text_font_set(ep->object, font, size);
447 part_get_geometry(ep, &tw, &th);
449 else if ((tw < sw) && (size > 0) && (tw != 0))
451 size = (size * sw) / tw;
453 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
454 else evas_object_text_font_source_set(ep->object, NULL);
456 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
457 evas_object_text_font_set(ep->object, font, size);
458 part_get_geometry(ep, &tw, &th);
460 /* FIXME: This should possibly be replaced by more proper handling,
461 * but it's still way better than what was here before. */
464 if (chosen_desc->text.fit_y && (ep->text.cache.in_str && eina_stringshare_strlen(ep->text.cache.in_str) > 0))
466 /* if we fit in the x axis, too, size already has a somewhat
467 * meaningful value, so don't overwrite it with the starting
470 if (!chosen_desc->text.fit_x) size = sh;
472 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
473 else evas_object_text_font_source_set(ep->object, NULL);
475 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
476 evas_object_text_font_set(ep->object, font, size);
477 evas_object_text_text_set(ep->object, text);
478 part_get_geometry(ep, &tw, &th);
480 /* only grow the font size if we didn't already reach the max size
483 if (!chosen_desc->text.fit_x && th < sh)
488 if (dif < 1) dif = 1;
489 while ((th < sh) && (sw > 0))
492 if (size <= 0) break;
493 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
494 else evas_object_text_font_source_set(ep->object, NULL);
496 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
497 evas_object_text_font_set(ep->object, font, size);
498 part_get_geometry(ep, &tw, &th);
499 if ((size > 0) && (th == 0)) break;
507 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
508 evas_object_text_font_set(ep->object, font, 10);
509 part_get_geometry(ep, &tw, &th);
517 if (th < sh) bottom = 10;
518 else if (th > sh) bottom = 1;
519 else bottom = 0; /* XXX shut up GCC, th == sh is handled before! */
522 /* search one that fits (binary search) */
525 current = (top + bottom) / 2;
527 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
528 evas_object_text_font_set(ep->object, font, current);
529 part_get_geometry(ep, &tw, &th);
531 if (th < sh) bottom = current + 1;
532 else if (th > sh) top = current - 1;
533 } while ((bottom < top) && (th != sh));
536 /* search the larger one that fits (linear search) */
541 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
542 evas_object_text_font_set(ep->object, font, current);
543 part_get_geometry(ep, &tw, &th);
549 /* Make sure the size is in range */
552 else if ((size > chosen_desc->text.size_range_max) &&
553 (chosen_desc->text.size_range_max > 0))
554 size = chosen_desc->text.size_range_max;
555 else if (size < chosen_desc->text.size_range_min)
556 size = chosen_desc->text.size_range_min;
558 /* Handle ellipsis */
560 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
561 else evas_object_text_font_source_set(ep->object, NULL);
563 text = _edje_text_fit_x(ed, ep, params, text, font, size, sw, &free_text);
566 str = eina_stringshare_add(text);
567 if (ep->text.cache.out_str) eina_stringshare_del(ep->text.cache.out_str);
568 ep->text.cache.out_str = str;
569 ep->text.cache.in_w = sw;
570 ep->text.cache.in_h = sh;
571 ep->text.cache.out_size = size;
572 ep->text.cache.align_x = params->type.text.align.x;
573 ep->text.cache.align_y = params->type.text.align.y;
574 ep->text.cache.elipsis = params->type.text.elipsis;
575 ep->text.cache.fit_x = chosen_desc->text.fit_x;
576 ep->text.cache.fit_y = chosen_desc->text.fit_y;
579 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
580 else evas_object_text_font_source_set(ep->object, NULL);
582 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
583 evas_object_text_font_set(ep->object, font, size);
584 evas_object_text_text_set(ep->object, text);
585 part_get_geometry(ep, &tw, &th);
586 /* Handle alignment */
589 if (params->type.text.align.x < 0.0)
591 if (evas_object_text_direction_get(ep->object) ==
592 EVAS_BIDI_DIRECTION_RTL)
603 align_x = params->type.text.align.x;
605 ep->text.offset.x = TO_INT(SCALE(align_x, (sw - tw)));
606 ep->text.offset.y = TO_INT(SCALE(params->type.text.align.y, (sh - th)));
609 evas_object_move(ep->object,
610 ed->x + params->x + ep->text.offset.x,
611 ed->y + params->y + ep->text.offset.y);
613 if (params->visible) evas_object_show(ep->object);
614 else evas_object_hide(ep->object);
616 Evas_Text_Style_Type style;
617 Edje_Text_Effect effect;
619 style = EVAS_TEXT_STYLE_PLAIN;
621 evas_object_color_set(ep->object,
622 (params->color.r * params->color.a) / 255,
623 (params->color.g * params->color.a) / 255,
624 (params->color.b * params->color.a) / 255,
626 effect = ep->part->effect;
627 switch (effect & EDJE_TEXT_EFFECT_MASK_BASIC)
629 case EDJE_TEXT_EFFECT_NONE:
630 case EDJE_TEXT_EFFECT_PLAIN:
631 style = EVAS_TEXT_STYLE_PLAIN;
633 case EDJE_TEXT_EFFECT_OUTLINE:
634 style = EVAS_TEXT_STYLE_OUTLINE;
635 evas_object_text_outline_color_set(ep->object,
636 (params->type.text.color2.r * params->type.text.color2.a) / 255,
637 (params->type.text.color2.g * params->type.text.color2.a) / 255,
638 (params->type.text.color2.b * params->type.text.color2.a) / 255,
639 params->type.text.color2.a);
641 case EDJE_TEXT_EFFECT_SOFT_OUTLINE:
642 style = EVAS_TEXT_STYLE_SOFT_OUTLINE;
643 evas_object_text_outline_color_set(ep->object,
644 (params->type.text.color2.r * params->type.text.color2.a) / 255,
645 (params->type.text.color2.g * params->type.text.color2.a) / 255,
646 (params->type.text.color2.b * params->type.text.color2.a) / 255,
647 params->type.text.color2.a);
649 case EDJE_TEXT_EFFECT_SHADOW:
650 style = EVAS_TEXT_STYLE_SHADOW;
651 evas_object_text_shadow_color_set(ep->object,
652 (params->type.text.color3.r * params->type.text.color3.a) / 255,
653 (params->type.text.color3.g * params->type.text.color3.a) / 255,
654 (params->type.text.color3.b * params->type.text.color3.a) / 255,
655 params->type.text.color3.a);
657 case EDJE_TEXT_EFFECT_SOFT_SHADOW:
658 style = EVAS_TEXT_STYLE_SOFT_SHADOW;
659 evas_object_text_shadow_color_set(ep->object,
660 (params->type.text.color3.r * params->type.text.color3.a) / 255,
661 (params->type.text.color3.g * params->type.text.color3.a) / 255,
662 (params->type.text.color3.b * params->type.text.color3.a) / 255,
663 params->type.text.color3.a);
665 case EDJE_TEXT_EFFECT_OUTLINE_SHADOW:
666 style = EVAS_TEXT_STYLE_OUTLINE_SHADOW;
667 evas_object_text_outline_color_set(ep->object,
668 (params->type.text.color2.r * params->type.text.color2.a) / 255,
669 (params->type.text.color2.g * params->type.text.color2.a) / 255,
670 (params->type.text.color2.b * params->type.text.color2.a) / 255,
671 params->type.text.color2.a);
672 evas_object_text_shadow_color_set(ep->object,
673 (params->type.text.color3.r * params->type.text.color3.a) / 255,
674 (params->type.text.color3.g * params->type.text.color3.a) / 255,
675 (params->type.text.color3.b * params->type.text.color3.a) / 255,
676 params->type.text.color3.a);
678 case EDJE_TEXT_EFFECT_OUTLINE_SOFT_SHADOW:
679 style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW;
680 evas_object_text_outline_color_set(ep->object,
681 (params->type.text.color2.r * params->type.text.color2.a) / 255,
682 (params->type.text.color2.g * params->type.text.color2.a) / 255,
683 (params->type.text.color2.b * params->type.text.color2.a) / 255,
684 params->type.text.color2.a);
685 evas_object_text_shadow_color_set(ep->object,
686 (params->type.text.color3.r * params->type.text.color3.a) / 255,
687 (params->type.text.color3.g * params->type.text.color3.a) / 255,
688 (params->type.text.color3.b * params->type.text.color3.a) / 255,
689 params->type.text.color3.a);
691 case EDJE_TEXT_EFFECT_FAR_SHADOW:
692 style = EVAS_TEXT_STYLE_FAR_SHADOW;
693 evas_object_text_shadow_color_set(ep->object,
694 (params->type.text.color3.r * params->type.text.color3.a) / 255,
695 (params->type.text.color3.g * params->type.text.color3.a) / 255,
696 (params->type.text.color3.b * params->type.text.color3.a) / 255,
697 params->type.text.color3.a);
699 case EDJE_TEXT_EFFECT_FAR_SOFT_SHADOW:
700 style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW;
701 evas_object_text_shadow_color_set(ep->object,
702 (params->type.text.color3.r * params->type.text.color3.a) / 255,
703 (params->type.text.color3.g * params->type.text.color3.a) / 255,
704 (params->type.text.color3.b * params->type.text.color3.a) / 255,
705 params->type.text.color3.a);
707 case 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);
721 style = EVAS_TEXT_STYLE_PLAIN;
725 switch (effect & EDJE_TEXT_EFFECT_MASK_SHADOW_DIRECTION)
727 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_BOTTOM_RIGHT:
728 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
729 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT);
731 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_BOTTOM:
732 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
733 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM);
735 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_BOTTOM_LEFT:
736 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
737 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT);
739 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_LEFT:
740 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
741 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT);
743 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_TOP_LEFT:
744 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
745 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT);
747 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_TOP:
748 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
749 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP);
751 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_TOP_RIGHT:
752 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
753 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT);
755 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_RIGHT:
756 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
757 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT);
762 evas_object_text_style_set(ep->object, style);
765 if (free_text) free((char *)text);
766 if (font2) free(font2);
767 if (sfont) free(sfont);
771 _edje_text_size_calc(Evas_Font_Size size, Edje_Text_Class *tc)
779 else if (tc->size > 0.0)
785 val = (size * -tc->size) / 100;