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);
203 for ( ; i < uc2 ; i++)
205 c2 = evas_string_char_next_get(text, c2, NULL);
211 while (((c1 >= 0) || (c2 >= 0)) && (tw > sw))
219 if ((c1 >= 0) && (c2 >= 0))
224 c1 = evas_string_char_next_get(text, c1, NULL);
230 c2 = evas_string_char_prev_get(text, c2, NULL);
242 c1 = evas_string_char_next_get(text, c1, NULL);
245 c2 = evas_string_char_prev_get(text, c2, NULL);
253 if ((c1 >= 0) && (c2 >= 0))
261 else if ((c1 > 0 && (size_t) c1 >= orig_len) || c2 == 0)
269 _edje_text_fit_set(buf, text, c1, c2);
271 evas_object_text_text_set(ep->object, buf);
272 part_get_geometry(ep, &tw, &th);
281 _edje_text_font_get(const char *base, const char *new, char **free_later)
283 const char *base_style, *new_style, *aux;
284 size_t font_len, style_len;
291 base_style = strstr(base, ":style=");
295 new_style = strstr(new, ":style=");
299 font_len = strlen(new);
300 aux = strchr(base_style, ',');
301 style_len = (aux) ? (size_t)(aux - base_style) : strlen(base_style);
303 *free_later = malloc(font_len + style_len + 1);
304 memcpy(*free_later, new, font_len);
305 memcpy(*free_later + font_len, base_style, style_len);
306 (*free_later)[font_len + style_len] = '\0';
312 _edje_text_class_font_get(Edje *ed, Edje_Part_Description_Text *chosen_desc, int *size, char **free_later)
315 const char *text_class_name, *font;
317 font = edje_string_get(&chosen_desc->text.font);
318 *size = chosen_desc->text.size;
320 text_class_name = chosen_desc->text.text_class;
321 if ((!text_class_name) || (!text_class_name[0]))
324 tc = _edje_text_class_find(ed, text_class_name);
328 font = _edje_text_font_get(edje_string_get(&chosen_desc->text.font), tc->font, free_later);
329 *size = _edje_text_size_calc(*size, tc);
335 _edje_text_recalc_apply(Edje *ed, Edje_Real_Part *ep,
336 Edje_Calc_Params *params,
337 Edje_Part_Description_Text *chosen_desc)
339 const char *text = NULL;
346 int inlined_font = 0, free_text = 0;
347 Eina_Bool same_text = EINA_FALSE;
351 if (sc == 0.0) sc = _edje_scale;
352 text = edje_string_get(&chosen_desc->text.text);
353 font = _edje_text_class_font_get(ed, chosen_desc, &size, &sfont);
355 if (ep->text.text) text = ep->text.text;
356 if (ep->text.font) font = ep->text.font;
357 if (ep->text.size > 0) size = ep->text.size;
359 if (ep->text.text_source)
361 text = edje_string_get(&(((Edje_Part_Description_Text *)ep->text.text_source->chosen_description)->text.text));
362 if (ep->text.text_source->text.text) text = ep->text.text_source->text.text;
366 font = edje_string_get(&(((Edje_Part_Description_Text *)ep->text.source->chosen_description)->text.font));
367 size = ((Edje_Part_Description_Text *)ep->text.source->chosen_description)->text.size;
368 if (ep->text.source->text.font) font = ep->text.source->text.font;
369 if (ep->text.source->text.size > 0) size = ep->text.source->text.size;
372 if (!text) text = "";
373 if (!font) font = "";
375 /* check if the font is embedded in the .eet */
378 Edje_Font_Directory_Entry *fnt = eina_hash_find(ed->file->fonts, font);
382 size_t len = strlen(font) + sizeof("edje/fonts/") + 1;
384 sprintf(font2, "edje/fonts/%s", font);
391 if ((_edje_fontset_append) && (font))
393 font2 = malloc(strlen(font) + 1 + strlen(_edje_fontset_append) + 1);
398 strcat(font2, _edje_fontset_append);
405 evas_object_text_style_pad_get(ep->object, &l, &r, &t, &b);
410 size = params->type.text.size;
411 if (!text) text = "";
413 if ((text == ep->text.cache.in_str)
414 || (text && ep->text.cache.in_str && !strcmp(ep->text.cache.in_str, text)))
416 text = ep->text.cache.in_str;
417 same_text = EINA_TRUE;
420 if ((ep->text.cache.in_size == size) &&
421 (ep->text.cache.in_w == sw) &&
422 (ep->text.cache.in_h == sh) &&
423 (ep->text.cache.in_str) &&
425 (ep->text.cache.align_x == params->type.text.align.x) &&
426 (ep->text.cache.align_y == params->type.text.align.y) &&
427 (ep->text.cache.elipsis == params->type.text.elipsis) &&
428 (ep->text.cache.fit_x == chosen_desc->text.fit_x) &&
429 (ep->text.cache.fit_y == chosen_desc->text.fit_y))
431 text = ep->text.cache.out_str;
432 size = ep->text.cache.out_size;
438 eina_stringshare_replace(&ep->text.cache.in_str, text);
440 ep->text.cache.in_size = size;
441 if (chosen_desc->text.fit_x && (ep->text.cache.in_str && eina_stringshare_strlen(ep->text.cache.in_str) > 0))
443 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
444 else evas_object_text_font_source_set(ep->object, NULL);
446 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
447 evas_object_text_font_set(ep->object, font, size);
448 evas_object_text_text_set(ep->object, text);
449 part_get_geometry(ep, &tw, &th);
450 /* Find the wanted font size */
451 if ((tw != sw) && (size > 0) && (tw != 0))
453 size = (size * sw) / tw;
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);
463 /* FIXME: This should possibly be replaced by more proper handling,
464 * but it's still way better than what was here before. */
467 if (chosen_desc->text.fit_y && (ep->text.cache.in_str && eina_stringshare_strlen(ep->text.cache.in_str) > 0))
469 /* if we fit in the x axis, too, size already has a somewhat
470 * meaningful value, so don't overwrite it with the starting
473 if (!chosen_desc->text.fit_x) size = sh;
475 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
476 else evas_object_text_font_source_set(ep->object, NULL);
478 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
479 evas_object_text_font_set(ep->object, font, size);
480 evas_object_text_text_set(ep->object, text);
481 part_get_geometry(ep, &tw, &th);
483 /* only grow the font size if we didn't already reach the max size
486 if (!chosen_desc->text.fit_x && th < sh)
491 if (dif < 1) dif = 1;
492 while ((th < sh) && (sw > 0))
495 if (size <= 0) break;
496 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
497 else evas_object_text_font_source_set(ep->object, NULL);
499 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
500 evas_object_text_font_set(ep->object, font, size);
501 part_get_geometry(ep, &tw, &th);
502 if ((size > 0) && (th == 0)) break;
510 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
511 evas_object_text_font_set(ep->object, font, 10);
512 part_get_geometry(ep, &tw, &th);
520 if (th < sh) bottom = 10;
521 else if (th > sh) bottom = 1;
522 else bottom = 0; /* XXX shut up GCC, th == sh is handled before! */
525 /* search one that fits (binary search) */
528 current = (top + bottom) / 2;
530 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
531 evas_object_text_font_set(ep->object, font, current);
532 part_get_geometry(ep, &tw, &th);
534 if (th < sh) bottom = current + 1;
535 else if (th > sh) top = current - 1;
536 } while ((bottom < top) && (th != sh));
539 /* search the larger one that fits (linear search) */
544 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
545 evas_object_text_font_set(ep->object, font, current);
546 part_get_geometry(ep, &tw, &th);
552 /* Make sure the size is in range */
555 else if ((size > chosen_desc->text.size_range_max) &&
556 (chosen_desc->text.size_range_max > 0))
557 size = chosen_desc->text.size_range_max;
558 else if (size < chosen_desc->text.size_range_min)
559 size = chosen_desc->text.size_range_min;
561 /* Handle ellipsis */
562 if (!chosen_desc->text.min_x)
564 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
565 else evas_object_text_font_source_set(ep->object, NULL);
567 text = _edje_text_fit_x(ed, ep, params, text, font, size, sw, &free_text);
570 eina_stringshare_replace(&ep->text.cache.out_str, text);
571 ep->text.cache.in_w = sw;
572 ep->text.cache.in_h = sh;
573 ep->text.cache.out_size = size;
574 ep->text.cache.align_x = params->type.text.align.x;
575 ep->text.cache.align_y = params->type.text.align.y;
576 ep->text.cache.elipsis = params->type.text.elipsis;
577 ep->text.cache.fit_x = chosen_desc->text.fit_x;
578 ep->text.cache.fit_y = chosen_desc->text.fit_y;
581 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
582 else evas_object_text_font_source_set(ep->object, NULL);
584 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
585 evas_object_text_font_set(ep->object, font, size);
586 evas_object_text_text_set(ep->object, text);
587 part_get_geometry(ep, &tw, &th);
588 /* Handle alignment */
591 if (params->type.text.align.x < FROM_INT(0))
593 if (evas_object_text_direction_get(ep->object) ==
594 EVAS_BIDI_DIRECTION_RTL)
596 align_x = FROM_INT(1);
600 align_x = FROM_INT(0);
605 align_x = params->type.text.align.x;
607 ep->text.offset.x = TO_INT(SCALE(align_x, (sw - tw)));
608 ep->text.offset.y = TO_INT(SCALE(params->type.text.align.y, (sh - th)));
611 evas_object_move(ep->object,
612 ed->x + params->x + ep->text.offset.x,
613 ed->y + params->y + ep->text.offset.y);
615 if (params->visible) evas_object_show(ep->object);
616 else evas_object_hide(ep->object);
618 Evas_Text_Style_Type style;
619 Edje_Text_Effect effect;
621 style = EVAS_TEXT_STYLE_PLAIN;
623 evas_object_color_set(ep->object,
624 (params->color.r * params->color.a) / 255,
625 (params->color.g * params->color.a) / 255,
626 (params->color.b * params->color.a) / 255,
628 effect = ep->part->effect;
629 switch (effect & EDJE_TEXT_EFFECT_MASK_BASIC)
631 case EDJE_TEXT_EFFECT_NONE:
632 case EDJE_TEXT_EFFECT_PLAIN:
633 style = EVAS_TEXT_STYLE_PLAIN;
635 case EDJE_TEXT_EFFECT_OUTLINE:
636 style = EVAS_TEXT_STYLE_OUTLINE;
637 evas_object_text_outline_color_set(ep->object,
638 (params->type.text.color2.r * params->type.text.color2.a) / 255,
639 (params->type.text.color2.g * params->type.text.color2.a) / 255,
640 (params->type.text.color2.b * params->type.text.color2.a) / 255,
641 params->type.text.color2.a);
643 case EDJE_TEXT_EFFECT_SOFT_OUTLINE:
644 style = EVAS_TEXT_STYLE_SOFT_OUTLINE;
645 evas_object_text_outline_color_set(ep->object,
646 (params->type.text.color2.r * params->type.text.color2.a) / 255,
647 (params->type.text.color2.g * params->type.text.color2.a) / 255,
648 (params->type.text.color2.b * params->type.text.color2.a) / 255,
649 params->type.text.color2.a);
651 case EDJE_TEXT_EFFECT_SHADOW:
652 style = EVAS_TEXT_STYLE_SHADOW;
653 evas_object_text_shadow_color_set(ep->object,
654 (params->type.text.color3.r * params->type.text.color3.a) / 255,
655 (params->type.text.color3.g * params->type.text.color3.a) / 255,
656 (params->type.text.color3.b * params->type.text.color3.a) / 255,
657 params->type.text.color3.a);
659 case EDJE_TEXT_EFFECT_SOFT_SHADOW:
660 style = EVAS_TEXT_STYLE_SOFT_SHADOW;
661 evas_object_text_shadow_color_set(ep->object,
662 (params->type.text.color3.r * params->type.text.color3.a) / 255,
663 (params->type.text.color3.g * params->type.text.color3.a) / 255,
664 (params->type.text.color3.b * params->type.text.color3.a) / 255,
665 params->type.text.color3.a);
667 case EDJE_TEXT_EFFECT_OUTLINE_SHADOW:
668 style = EVAS_TEXT_STYLE_OUTLINE_SHADOW;
669 evas_object_text_outline_color_set(ep->object,
670 (params->type.text.color2.r * params->type.text.color2.a) / 255,
671 (params->type.text.color2.g * params->type.text.color2.a) / 255,
672 (params->type.text.color2.b * params->type.text.color2.a) / 255,
673 params->type.text.color2.a);
674 evas_object_text_shadow_color_set(ep->object,
675 (params->type.text.color3.r * params->type.text.color3.a) / 255,
676 (params->type.text.color3.g * params->type.text.color3.a) / 255,
677 (params->type.text.color3.b * params->type.text.color3.a) / 255,
678 params->type.text.color3.a);
680 case EDJE_TEXT_EFFECT_OUTLINE_SOFT_SHADOW:
681 style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW;
682 evas_object_text_outline_color_set(ep->object,
683 (params->type.text.color2.r * params->type.text.color2.a) / 255,
684 (params->type.text.color2.g * params->type.text.color2.a) / 255,
685 (params->type.text.color2.b * params->type.text.color2.a) / 255,
686 params->type.text.color2.a);
687 evas_object_text_shadow_color_set(ep->object,
688 (params->type.text.color3.r * params->type.text.color3.a) / 255,
689 (params->type.text.color3.g * params->type.text.color3.a) / 255,
690 (params->type.text.color3.b * params->type.text.color3.a) / 255,
691 params->type.text.color3.a);
693 case EDJE_TEXT_EFFECT_FAR_SHADOW:
694 style = EVAS_TEXT_STYLE_FAR_SHADOW;
695 evas_object_text_shadow_color_set(ep->object,
696 (params->type.text.color3.r * params->type.text.color3.a) / 255,
697 (params->type.text.color3.g * params->type.text.color3.a) / 255,
698 (params->type.text.color3.b * params->type.text.color3.a) / 255,
699 params->type.text.color3.a);
701 case EDJE_TEXT_EFFECT_FAR_SOFT_SHADOW:
702 style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW;
703 evas_object_text_shadow_color_set(ep->object,
704 (params->type.text.color3.r * params->type.text.color3.a) / 255,
705 (params->type.text.color3.g * params->type.text.color3.a) / 255,
706 (params->type.text.color3.b * params->type.text.color3.a) / 255,
707 params->type.text.color3.a);
709 case EDJE_TEXT_EFFECT_GLOW:
710 style = EVAS_TEXT_STYLE_GLOW;
711 evas_object_text_glow_color_set(ep->object,
712 (params->type.text.color2.r * params->type.text.color2.a) / 255,
713 (params->type.text.color2.g * params->type.text.color2.a) / 255,
714 (params->type.text.color2.b * params->type.text.color2.a) / 255,
715 params->type.text.color2.a);
716 evas_object_text_glow2_color_set(ep->object,
717 (params->type.text.color3.r * params->type.text.color3.a) / 255,
718 (params->type.text.color3.g * params->type.text.color3.a) / 255,
719 (params->type.text.color3.b * params->type.text.color3.a) / 255,
720 params->type.text.color3.a);
723 style = EVAS_TEXT_STYLE_PLAIN;
727 switch (effect & EDJE_TEXT_EFFECT_MASK_SHADOW_DIRECTION)
729 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_BOTTOM_RIGHT:
730 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
731 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT);
733 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_BOTTOM:
734 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
735 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM);
737 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_BOTTOM_LEFT:
738 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
739 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT);
741 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_LEFT:
742 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
743 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT);
745 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_TOP_LEFT:
746 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
747 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT);
749 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_TOP:
750 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
751 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP);
753 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_TOP_RIGHT:
754 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
755 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT);
757 case EDJE_TEXT_EFFECT_SHADOW_DIRECTION_RIGHT:
758 EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET
759 (style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT);
764 evas_object_text_style_set(ep->object, style);
767 if (free_text) free((char *)text);
768 if (font2) free(font2);
769 if (sfont) free(sfont);
773 _edje_text_size_calc(Evas_Font_Size size, Edje_Text_Class *tc)
781 else if (tc->size > 0.0)
787 val = (size * -tc->size) / 100;