Enlightenment CVS committal Author : raster Project : e17 Module : libs/evas
Dir : e17/libs/evas/src/lib/canvas Modified Files: evas_object_textblock.c Log Message: working on tb2 =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/evas/src/lib/canvas/evas_object_textblock.c,v retrieving revision 1.66 retrieving revision 1.67 diff -u -3 -r1.66 -r1.67 --- evas_object_textblock.c 8 Aug 2005 15:41:38 -0000 1.66 +++ evas_object_textblock.c 11 Aug 2005 13:50:37 -0000 1.67 @@ -48,7 +48,7 @@ struct _Evas_Object_Textblock_Line { Evas_Object_List _list_data; Evas_Object_Textblock_Item *items; - double align; +// double align; int x, y, w, h; int baseline; int line_no; @@ -215,12 +215,13 @@ // popped // tags starting with / (ie </blah>) will ALWAYS pop UNLESS provided // with an override here in the style (like /p) - "DEFAULT='font=Vera font_size=10 align=left color=#000000'" - "center='+ align=middle'" + "DEFAULT='font=Vera font_size=8 align=left color=#000000 wrap=char'" + "center='+ align=center'" + "/center='- \n \n'" "h1='+ font_size=20'" "red='+ color=#ff0000'" - "p='+ font=Vera font_size=12 align=left'" - "/p='- \n \n'" // you can define end tags - override default pop on /... + "p='+ font=Vera font_size=10 align=left'" + "/p='- \n \n'" "br='\n'" ); evas_object_textblock2_style_set(obj, ts); // tell object to use this style @@ -873,7 +874,18 @@ if (ttag[0] == '/') evas_textblock2_cursor_format_append(o->cursor, "-"); else - evas_textblock2_cursor_format_append(o->cursor, ttag); + { + char *ttag2; + + ttag2 = malloc(strlen(ttag) + 2 + 1); + if (ttag2) + { + strcpy(ttag2, "+ "); + strcat(ttag2, ttag); + evas_textblock2_cursor_format_append(o->cursor, ttag2); + free(ttag2); + } + } } free(ttag); } @@ -1545,345 +1557,452 @@ return fmt2; } -static void -_layout(Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_ret) + + + + + + + + + +typedef struct _Ctxt Ctxt; + +struct _Ctxt { + Evas_Object *obj; Evas_Object_Textblock *o; - Evas_Object_List *l, *ll; - Evas_Object_Textblock_Line *lines = NULL, *ln = NULL; - int x, y, wmax, hmax, ascent, descent, maxascent, maxdescent, advance, - maxadvance, maxh, line_no; - Evas_List *format_stack = NULL; - Evas_Object_Textblock_Item *it = NULL; - Evas_Object_Textblock_Format *fmt = NULL; - - /* this is formatting context */ - x = 0; - y = 0; - wmax = 0; - hmax = 0; - - ascent = 0; - descent = 0; - maxascent = 0; - maxdescent = 0; - maxh = 0; - line_no = 0; - o = (Evas_Object_Textblock *)(obj->object_data); - if ((o->style) && (o->style->default_tag)) + Evas_Object_Textblock_Line *lines; + Evas_Object_Textblock_Line *ln; + + Evas_List *format_stack; + + int x, y; + int w, h; + int wmax, hmax; + int maxascent, maxdescent; + int marginl, marginr; + int line_no; + double align; +}; + +static void +_layout_format_ascent_descent_adjust(Ctxt *c, Evas_Object_Textblock_Format *fmt) +{ + int ascent, descent; + + ascent = c->ENFN->font_max_ascent_get(c->ENDT, fmt->font.font); + descent = c->ENFN->font_max_descent_get(c->ENDT, fmt->font.font); + if (c->maxascent < ascent) c->maxascent = ascent; + if (c->maxdescent < descent) c->maxdescent = descent; +} + +static void +_layout_line_new(Ctxt *c, Evas_Object_Textblock_Format *fmt) +{ + c->ln = calloc(1, sizeof(Evas_Object_Textblock_Line)); + c->align = fmt->halign; + c->lines = evas_object_list_append(c->lines, c->ln); + c->x = 0; + c->maxascent = c->maxdescent = 0; + _layout_format_ascent_descent_adjust(c, fmt); +} + +static Evas_Object_Textblock_Format * +_layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt) +{ + if (fmt) + { + fmt = _format_dup(c->obj, fmt); + c->format_stack = evas_list_prepend(c->format_stack, fmt); + } + else { fmt = calloc(1, sizeof(Evas_Object_Textblock_Format)); - fmt->ref = 1; - format_stack = evas_list_prepend(format_stack, fmt); - _format_fill(obj, fmt, o->style->default_tag); + c->format_stack = evas_list_prepend(c->format_stack, fmt); } - for (l = (Evas_Object_List *)o->nodes; l; l = l->next) + return fmt; +} + +static Evas_Object_Textblock_Format * +_layout_format_pop(Ctxt *c, Evas_Object_Textblock_Format *fmt) +{ + if ((c->format_stack) && (c->format_stack->next)) { - Evas_Object_Textblock_Node *n; + _format_free(c->obj, fmt); + c->format_stack = evas_list_remove_list(c->format_stack, c->format_stack); + fmt = c->format_stack->data; + } + return fmt; +} + +static void +_layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, char *item) +{ + char *key = NULL, *val = NULL; + + _format_param_parse(item, &key, &val); + if ((key) && (val)) _format_command(c->obj, fmt, key, val); + if (key) free(key); + if (val) free(val); + c->align = fmt->halign; +} + +static void +_layout_line_advance(Ctxt *c, Evas_Object_Textblock_Format *fmt) +{ + Evas_Object_Textblock_Item *it; + Evas_Object_List *l; + + c->maxascent = c->maxdescent = 0; + if (!c->ln->items) + _layout_format_ascent_descent_adjust(c, fmt); + for (l = (Evas_Object_List *)c->ln->items; l; l = l->next) + { + int endx; - n = (Evas_Object_Textblock_Node *)l; - if (!ln) - { - ln = calloc(1, sizeof(Evas_Object_Textblock_Line)); - ln->align = fmt->halign; - lines = evas_object_list_append(lines, ln); - x = 0; - maxascent = 0; - maxdescent = 0; - ascent = ENFN->font_max_ascent_get(ENDT, fmt->font.font); - descent = ENFN->font_max_descent_get(ENDT, fmt->font.font); - if (maxascent < ascent) maxascent = ascent; - if (maxdescent < descent) maxdescent = descent; + it = (Evas_Object_Textblock_Item *)l; + _layout_format_ascent_descent_adjust(c, it->format); + endx = it->x + it->w; + if (endx > c->ln->w) c->ln->w = endx; + } + if (c->ln->w > c->wmax) c->wmax = c->ln->w; + c->ln->y = c->y; + c->ln->h = c->maxascent + c->maxdescent; + c->ln->baseline = c->maxascent; + c->ln->line_no = c->line_no; + c->line_no++; + c->y += c->maxascent + c->maxdescent; + c->ln->x = c->marginl + ((c->w - c->ln->w - c->marginl - c->marginr) * c->align); + _layout_line_new(c, fmt); +} + +static Evas_Object_Textblock_Item * +_layout_item_new(Ctxt *c, Evas_Object_Textblock_Format *fmt, char *str) +{ + Evas_Object_Textblock_Item *it; + + it = calloc(1, sizeof(Evas_Object_Textblock_Item)); + it->format = fmt; + it->format->ref++; + it->text = strdup(str); + return it; +} + +static int +_layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Item *it) +{ + int cx, cy, cw, ch; + + return c->ENFN->font_char_at_coords_get(c->ENDT, fmt->font.font, it->text, + c->w - c->marginl - c->marginr - c->x, + 0, &cx, &cy, &cw, &ch); +} + +static void +_layout_item_text_cutoff(Ctxt *c, Evas_Object_Textblock_Item *it, int cut) +{ + char *ts; + + ts = it->text; + ts[cut] = 0; + it->text = strdup(ts); + free(ts); +} + +static int +_layout_word_start(char *str, int start) +{ + int p, tp, chr = 0; + + tp = 0; + p = start; + while (p >= 0) + { + chr = evas_common_font_utf8_get_prev((unsigned char *)(str), &p); + if (_is_white(chr)) break; + tp = p; + } + p = tp; + if ((p >= 0) && (_is_white(chr))) + evas_common_font_utf8_get_next((unsigned char *)(str), &p); + return p; +} + +static int +_layout_ends_with_space(char *str) +{ + int p, chr; + + p = evas_common_font_utf8_get_last((unsigned char *)(str), strlen(str)); + chr = evas_common_font_utf8_get_next((unsigned char *)(str), &p); + return _is_white(chr); +} + +static void +_layout_strip_trailing_whitespace(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Item *it) +{ + int p, tp, chr, adv, tw, th; + + p = evas_common_font_utf8_get_last((unsigned char *)(it->text), strlen(it->text)); + tp = p; + while (p >= 0) + { + chr = evas_common_font_utf8_get_prev((unsigned char *)(it->text), &p); + if (!_is_white(chr)) + { + evas_common_font_utf8_get_next((unsigned char *)(it->text), &tp); + _layout_item_text_cutoff(c, it, tp); + adv = c->ENFN->font_h_advance_get(c->ENDT, it->format->font.font, it->text); + c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &tw, &th); + it->w = tw; + it->h = th; + c->x = it->x + adv; + return; } - if ((n->type == NODE_FORMAT) && (n->text)) + tp = p; + } +} + +static void +_layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Node *n) +{ + int adv, inset, tw, th, new_line, empty_item; + char *str; + Evas_Object_Textblock_Item *it, *tit; + + str = n->text; + new_line = 0; + empty_item = 0; + while (str) + { + it = _layout_item_new(c, fmt, str); + c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &tw, &th); + if (((fmt->wrap_word) || (fmt->wrap_char)) && ((c->x + tw) > (c->w - c->marginl - c->marginr))) { - char *s; - char *item; + int wrap, twrap, ch; -// printf("F: %s\n", n->text); - s = n->text; - if (s[0] == '+') - { - if (fmt) - { - fmt = _format_dup(obj, fmt); - format_stack = evas_list_prepend(format_stack, fmt); - } - else - { - fmt = calloc(1, sizeof(Evas_Object_Textblock_Format)); - format_stack = evas_list_prepend(format_stack, fmt); - } - s++; - } - else if (s[0] == '-') - { - if ((format_stack) && (format_stack->next)) - { - _format_free(obj, fmt); - format_stack = evas_list_remove_list(format_stack, format_stack); - fmt = format_stack->data; - } - s++; - } - while ((item = _format_parse(&s))) + wrap = _layout_text_cutoff_get(c, fmt, it); + if (wrap > 0) { -// printf("ITEM %s\n", item); - if (_format_is_param(item)) - { - char *key = NULL, *val = NULL; - - _format_param_parse(item, &key, &val); - _format_command(obj, fmt, key, val); - free(key); - free(val); - ln->align = fmt->halign; - } - else + printf("WRAP %s [%i]\n", str, wrap); + if (fmt->wrap_word) { -// printf("IMM: ->%s<-\n", item); - /* immediate */ - if (!strcmp(item, "\n")) + wrap = _layout_word_start(str, wrap); + /* wrap now is the index of the word START */ + if (wrap == 0) { - /* finish line */ - maxascent = 0; - maxdescent = 0; - for (ll = (Evas_Object_List *)ln->items; ll; ll = ll->next) - { - it = (Evas_Object_Textblock_Item *)ll; - - ascent = ENFN->font_max_ascent_get(ENDT, it->format->font.font); - descent = ENFN->font_max_descent_get(ENDT, it->format->font.font); - if (maxascent < ascent) maxascent = ascent; - if (maxdescent < descent) maxdescent = descent; - } - if (ln->w > wmax) wmax = ln->w; - ln->y = y; - ln->h = maxascent + maxdescent; - ln->baseline = maxascent; - ln->line_no = line_no; - line_no++; - x = 0; - y += maxascent + maxdescent; - ln->x = (w - ln->w) * ln->align; - - ln = calloc(1, sizeof(Evas_Object_Textblock_Line)); - ln->align = fmt->halign; - lines = evas_object_list_append(lines, ln); + /* we are at the start of the node - maybe the + * word is spread over previous nodes too? we + * now need to walk back over previous items and + * check + */ } - else if (!strcmp(item, "\t")) - { - /* jump to next tabstop */ - } - } - free(item); - } - } - else if ((n->type == NODE_TEXT) && (n->text)) - { - int adv, inset, tw, th, x2; - char *str, new_line, empty_item; - - str = n->text; - new_line = 0; - empty_item = 0; - while (str) - { - it = calloc(1, sizeof(Evas_Object_Textblock_Item)); - fmt->ref++; - it->format = fmt; - it->text = strdup(str); - inset = ENFN->font_inset_get(ENDT, fmt->font.font, it->text); -// if (ln->items == NULL) x = inset; - ENFN->font_string_size_get(ENDT, fmt->font.font, - it->text, &tw, &th); - if (((fmt->wrap_word) || (fmt->wrap_char)) && - ((x + tw) > w)) - { - int wrap, twrap, cx, cy, cw, ch; - char *ts; - - wrap = ENFN->font_char_at_coords_get(ENDT, - fmt->font.font, - it->text, w - x, 0, - &cx, &cy, - &cw, &ch); + /* cut of pointless whitespace at end of previous line */ if (wrap > 0) { - /* FIXME: handle wrap */ - if (fmt->wrap_word) + twrap = wrap; + evas_common_font_utf8_get_prev((unsigned char *)str, &twrap); + ch = evas_common_font_utf8_get_prev((unsigned char *)str, &twrap); + while (_is_white(ch) && (twrap >= 0)) + ch = evas_common_font_utf8_get_prev((unsigned char *)str, &twrap); + if (!_is_white(ch)) { - /* walk pack to start of word */ - while ((wrap >= 0) && - (!_is_white(str[wrap]))) wrap--; - wrap++; - /* wrap now is the index of the word START */ - /* cut of pointless whitespace at end of - * previous line - */ - if (wrap > 0) - { - twrap = wrap - 1; - while ((twrap > 0) && - _is_white(str[twrap])) twrap--; - ts = it->text; - while (!_is_white(str[twrap])) twrap++; - ts[twrap] = 0; - it->text = strdup(ts); - free(ts); - str = str + wrap; - } - else + evas_common_font_utf8_get_next((unsigned char *)str, &twrap); + evas_common_font_utf8_get_next((unsigned char *)str, &twrap); + } + else + twrap = 0; + if (twrap == 0) + { + int ptwrap; + + empty_item = 1; + if (it->text) free(it->text); + _format_free(c->obj, it->format); + free(it); + ptwrap = twrap; + for (;;) { - if (ln->items != NULL) - { - empty_item = 1; - if (it->text) free(it->text); - _format_free(obj, it->format); - free(it); - if (ln->items) - { - it = (Evas_Object_Textblock_Item *)((Evas_Object_List *)ln->items)->last; - twrap = strlen(it->text) - 1; - while ((twrap > 0) && - (_is_white(it->text[twrap]))) - twrap--; - if ((twrap > 0) && - (_is_white(it->text[twrap]))) - it->text[twrap] = 0; - ENFN->font_string_size_get(ENDT, fmt->font.font, - it->text, &tw, &th); - ln->w -= it->w - tw; - it->w = tw; - it->h = th; - } - str = str + wrap; - } - /* this is the last word on a line. - * no choice. just put it on anyway */ - else + ch = evas_common_font_utf8_get_next((unsigned char *)str, &twrap); + if (twrap < 0) { - str = str + 1; - if (*str == 0) str = NULL; - else - { - ts = it->text; - ts[1] = 0; - it->text = strdup(ts); - free(ts); - } + ptwrap = twrap; + break; } + if (!_is_white(ch)) break; + ptwrap = twrap; } + str = str + ptwrap; } - else if (fmt->wrap_char) + else { - ts = it->text; - ts[wrap] = 0; - it->text = strdup(ts); - free(ts); + _layout_item_text_cutoff(c, it, twrap); str = str + wrap; } - new_line = 1; } else { - if (ln->items != NULL) + if (c->ln->items != NULL) { empty_item = 1; if (it->text) free(it->text); - _format_free(obj, it->format); + _format_free(c->obj, it->format); free(it); - if (ln->items) + if (c->ln->items) { - it = (Evas_Object_Textblock_Item *)((Evas_Object_List *)ln->items)->last; - twrap = strlen(it->text) - 1; - while ((twrap > 0) && - (_is_white(it->text[twrap]))) - twrap--; - if ((twrap > 0) && - (_is_white(it->text[twrap]))) - it->text[twrap] = 0; - ENFN->font_string_size_get(ENDT, fmt->font.font, - it->text, &tw, &th); - ln->w -= it->w - tw; - it->w = tw; - it->h = th; + it = (Evas_Object_Textblock_Item *)((Evas_Object_List *)c->ln->items)->last; + _layout_strip_trailing_whitespace(c, fmt, it); } - new_line = 1; } + /* this is the last word on a line. no choice. + * just put it on anyway */ else { str = str + 1; if (*str == 0) str = NULL; else - { - ts = it->text; - ts[1] = 0; - it->text = strdup(ts); - free(ts); - } + _layout_item_text_cutoff(c, it, 1); } } - if (!empty_item) - ENFN->font_string_size_get(ENDT, fmt->font.font, - it->text, &tw, &th); } - else - str = NULL; - if (empty_item) + else if (fmt->wrap_char) { - empty_item = 0; + _layout_item_text_cutoff(c, it, wrap); + str = str + wrap; + } + new_line = 1; + } + else + { + if (c->ln->items != NULL) + { + empty_item = 1; + if (it->text) free(it->text); + _format_free(c->obj, it->format); + free(it); + if (c->ln->items) + { + it = (Evas_Object_Textblock_Item *)((Evas_Object_List *)c->ln->items)->last; + _layout_strip_trailing_whitespace(c, fmt, it); + } + new_line = 1; } else { - it->w = tw; - it->h = th; - it->inset = inset; - it->x = x; - adv = ENFN->font_h_advance_get(ENDT, fmt->font.font, - it->text); - x2 = x + tw; - x += adv; - if (x2 > ln->w) ln->w = x2; - ln->items = evas_object_list_append(ln->items, it); + str = str + 1; + if (*str == 0) str = NULL; + else + _layout_item_text_cutoff(c, it, 1); } - if (new_line) + } + if (!empty_item) + c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &tw, &th); + } + else + str = NULL; + if (empty_item) empty_item = 0; + else + { + it->w = tw; + it->h = th; + inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font, it->text); + it->inset = inset; + it->x = c->x; + adv = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font, it->text); + c->x += adv; + c->ln->items = evas_object_list_append(c->ln->items, it); + } + if (new_line) + { + new_line = 0; + _layout_line_advance(c, fmt); + } + } +} + +static void +_layout(Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_ret) +{ + Ctxt ctxt, *c; + Evas_Object_List *l, *ll; + Evas_Object_Textblock_Format *fmt = NULL; /* current format */ + + /* setup context */ + c = &ctxt; + c->obj =obj; + c->o = (Evas_Object_Textblock *)(obj->object_data); + c->lines = c->ln = NULL; + c->format_stack = NULL; + c->x = c->y = 0; + c->w = w; + c->h = h; + c->wmax = c->hmax = 0; + c->maxascent = c->maxdescent = 0; + c->marginl = c->marginr = 0; + c->line_no = 0; + c->align = 0.0; + + /* setup default base style */ + if ((c->o->style) && (c->o->style->default_tag)) + { + fmt = calloc(1, sizeof(Evas_Object_Textblock_Format)); + fmt->ref = 1; + c->format_stack = evas_list_prepend(c->format_stack, fmt); + _format_fill(c->obj, fmt, c->o->style->default_tag); + } + /* run thru all text and format nodes generating lines */ + for (l = (Evas_Object_List *)c->o->nodes; l; l = l->next) + { + Evas_Object_Textblock_Node *n; + + n = (Evas_Object_Textblock_Node *)l; + if (!c->ln) _layout_line_new(c, fmt); + if ((n->type == NODE_FORMAT) && (n->text)) + { + char *s; + char *item; + + s = n->text; + if (s[0] == '+') + { + fmt = _layout_format_push(c, fmt); + s++; + } + else if (s[0] == '-') + { + fmt = _layout_format_pop(c, fmt); + s++; + } + while ((item = _format_parse(&s))) + { + if (_format_is_param(item)) + _layout_format_value_handle(c, fmt, item); + else { - new_line = 0; - /* finish line */ - maxascent = 0; - maxdescent = 0; - for (ll = (Evas_Object_List *)ln->items; ll; ll = ll->next) - { - it = (Evas_Object_Textblock_Item *)ll; - - ascent = ENFN->font_max_ascent_get(ENDT, it->format->font.font); - descent = ENFN->font_max_descent_get(ENDT, it->format->font.font); - if (maxascent < ascent) maxascent = ascent; - if (maxdescent < descent) maxdescent = descent; + if (!strcmp(item, "\n")) + _layout_line_advance(c, fmt); + else if (!strcmp(item, "\t")) + { /* jump to next tabstop */ } - if (ln->w > wmax) wmax = ln->w; - ln->y = y; - ln->h = maxascent + maxdescent; - ln->baseline = maxascent; - ln->line_no = line_no; - line_no++; - x = 0; - y += maxascent + maxdescent; - ln->x = (w - ln->w) * ln->align; - - ln = calloc(1, sizeof(Evas_Object_Textblock_Line)); - ln->align = fmt->halign; - lines = evas_object_list_append(lines, ln); } + free(item); } } + else if ((n->type == NODE_TEXT) && (n->text)) + _layout_text_append(c, fmt, n); + } + while (c->format_stack) + { + fmt = c->format_stack->data; + c->format_stack = evas_list_remove_list(c->format_stack, c->format_stack); + _format_free(c->obj, fmt); } - hmax = y; + c->hmax = c->y; if (!calc_only) { - o->lines = lines; + c->o->lines = c->lines; } else { ------------------------------------------------------- SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs