Enlightenment CVS committal Author : moom Project : e17 Module : proto
Dir : e17/proto/etk/src/lib Modified Files: etk_textblock.c etk_textblock.h Log Message: * The textblock can now render. Still a lot of knows issues though!! =================================================================== RCS file: /cvs/e/e17/proto/etk/src/lib/etk_textblock.c,v retrieving revision 1.13 retrieving revision 1.14 diff -u -3 -r1.13 -r1.14 --- etk_textblock.c 2 Jul 2006 16:45:17 -0000 1.13 +++ etk_textblock.c 3 Jul 2006 05:06:26 -0000 1.14 @@ -3,6 +3,7 @@ #include "etk_textblock.h" #include <stdlib.h> #include <string.h> +#include <Ecore_Job.h> #include "etk_string.h" #include "etk_utils.h" @@ -17,19 +18,26 @@ Etk_Textblock *tb; Etk_Textblock_Wrap wrap; + Evas_Textblock_Style *style; - Evas_List *paragraphs; + Evas_List *lines; Evas_Object *cursor_object; + + Ecore_Job *update_job; } Etk_Textblock_Object_SD; -/* A paragraph */ -typedef struct Etk_Textblock_Object_Paragraph +/* A line for a textblock object is text terminated by '\n', <br> or </p>. + * It can actually fill several "visual" lines because of wrapping */ +typedef struct Etk_Textblock_Object_Line { + Etk_Textblock_Node *node; + Etk_Geometry geometry; Evas_Object *object; + Etk_Bool need_geometry_update; Etk_Bool need_content_update; -} Etk_Textblock_Object_Paragraph; +} Etk_Textblock_Object_Line; static void _etk_tb_constructor(Etk_Textblock *tb); static void _etk_tb_destructor(Etk_Textblock *tb); @@ -48,6 +56,7 @@ static void _etk_textblock_node_text_get(Etk_Textblock_Node *node, Etk_Bool markup, Etk_String *text); static void _etk_textblock_node_copy(Etk_Textblock_Node *dest, const Etk_Textblock_Node *src, Etk_Bool copy_text); +static int _etk_textblock_node_compare(Etk_Textblock_Node *node1, Etk_Textblock_Node *node2); static Etk_Textblock_Node *_etk_textblock_node_split(Etk_Textblock *tb, Etk_Textblock_Node *node, int index, int pos); static Etk_Bool _etk_textblock_node_close(Etk_Textblock_Iter *iter, Etk_Textblock_Node_Type node_type, Etk_Textblock_Tag_Type tag_type, Etk_Textblock_Node *replace_node); @@ -59,6 +68,13 @@ static void _etk_textblock_color_parse(const char *color_string, int length, Etk_Color *color); static int _etk_textblock_hex_string_get(char ch); +static void _etk_textblock_object_line_add(Evas_Object *tbo, Etk_Textblock_Node *line_node); +static void _etk_textblock_object_line_update_queue(Evas_Object *tbo, Etk_Textblock_Object_Line *line, Etk_Bool content_update, Etk_Bool geometry_update); +static void _etk_textblock_object_line_update(Evas_Object *tbo, Etk_Textblock_Object_Line *line, int y); +static void _etk_textblock_object_line_fill(Evas_Textblock_Cursor *cur, Etk_Textblock_Node *node); +static void _etk_textblock_object_update(Evas_Object *tbo); +static void _etk_textblock_object_update_job(void *data); + static void _etk_tb_object_smart_add(Evas_Object *obj); static void _etk_tb_object_smart_del(Evas_Object *obj); static void _etk_tb_object_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y); @@ -177,7 +193,9 @@ /* Adds an empty node */ node = _etk_textblock_node_new(&tb->root, NULL, ETK_TEXTBLOCK_NODE_PARAGRAPH, ETK_TEXTBLOCK_TAG_P); - _etk_textblock_node_new(node, NULL, ETK_TEXTBLOCK_NODE_LINE, ETK_TEXTBLOCK_TAG_DEFAULT); + node = _etk_textblock_node_new(node, NULL, ETK_TEXTBLOCK_NODE_LINE, ETK_TEXTBLOCK_TAG_DEFAULT); + for (l = tb->evas_objects; l; l = l->next) + _etk_textblock_object_line_add(l->data, node); for (l = tb->iters; l; l = l->next) etk_textblock_iter_backward_start(l->data); @@ -505,9 +523,7 @@ */ int etk_textblock_iter_compare(Etk_Textblock_Iter *iter1, Etk_Textblock_Iter *iter2) { - Etk_Textblock_Node *p1, *p2; - Etk_Textblock_Node *c1, *c2; - Etk_Textblock_Node *children = NULL, *n; + int node_compare; if (!iter1 || !iter2 || !iter1->tb) return -1; @@ -516,45 +532,17 @@ if (iter1 == iter2) return 0; - /* We search the common parent node */ - c1 = iter1->node; - c2 = iter2->node; - for (p1 = iter1->node->parent; p1; p1 = p1->parent) - { - for (p2 = iter2->node->parent; p2; p2 = p2->parent) - { - if (p1 == p2) - { - children = p1->children; - break; - } - c2 = p2; - } - - if (children) - break; - c1 = p1; - } - - /* Then we compare the positions of the two iterators in the list of children of the common parent */ - for (n = children; n; n = n->next) + if ((node_compare = _etk_textblock_node_compare(iter1->node, iter2->node)) != 0) + return node_compare; + else { - if (n == c1 && n != c2) + if (iter1->pos < iter2->pos) return -1; - else if (n != c1 && n == c2) + else if (iter1->pos > iter2->pos) return 1; - else if (n == c1 && n == c2) - { - if (iter1->pos < iter2->pos) - return -1; - else if (iter1->pos > iter2->pos) - return 1; - else - return 0; - } + else + return 0; } - - return -1; } /************************** @@ -573,6 +561,7 @@ { Evas_Object *obj; Etk_Textblock_Object_SD *tbo_sd; + Etk_Textblock_Node *paragraph, *line; if (!tb || !evas) return NULL; @@ -601,7 +590,13 @@ obj = evas_object_smart_add(evas, _etk_tb_object_smart); tbo_sd = evas_object_smart_data_get(obj); tbo_sd->tb= tb; - /* TODO: build the paragraph objects */ + + /* We creates the lines */ + for (paragraph = tb->root.children; paragraph; paragraph = paragraph->next) + { + for (line = paragraph->children; line; line = line->next) + _etk_textblock_object_line_add(obj, line); + } tb->evas_objects = evas_list_append(tb->evas_objects, obj); @@ -702,7 +697,6 @@ tb->iters = NULL; tb->evas_objects = NULL; - tb->update_job = NULL; } /* Destroys the textblock */ @@ -711,9 +705,6 @@ if (!tb) return; - if (tb->update_job) - ecore_job_del(tb->update_job); - while (tb->evas_objects) evas_object_del(tb->evas_objects->data); @@ -939,7 +930,7 @@ if (format->font_size < 0) format->font_size = n->tag.params.font.size; if (format->font_color.r < 0) - format->font_color.r = n->tag.params.font.color.r; + format->font_color = n->tag.params.font.color; break; default: break; @@ -963,7 +954,7 @@ n->children = _etk_textblock_nodes_clean(tb, n->children); delete_node = ETK_FALSE; - if (!n->children && etk_string_length_get(n->text) <= 0) + if (n->type == ETK_TEXTBLOCK_NODE_NORMAL && !n->children && etk_string_length_get(n->text) <= 0) { delete_node = ETK_TRUE; for (l = tb->iters; l; l = l->next) @@ -1294,6 +1285,7 @@ static Etk_Textblock_Node *_etk_textblock_line_add(Etk_Textblock *tb, Etk_Textblock_Iter *iter) { Etk_Textblock_Node *new_line; + Evas_List *l; if (!tb || !iter || !_etk_textblock_iter_is_valid(tb, iter)) return NULL; @@ -1306,6 +1298,9 @@ return NULL; } + for (l = tb->evas_objects; l; l = l->next) + _etk_textblock_object_line_add(l->data, new_line); + return new_line; } @@ -1465,6 +1460,52 @@ dest->tag.params.font.face = strdup(dest->tag.params.font.face); } +/* Compares the two nodes. */ +static int _etk_textblock_node_compare(Etk_Textblock_Node *node1, Etk_Textblock_Node *node2) +{ + Etk_Textblock_Node *p1, *p2; + Etk_Textblock_Node *c1, *c2; + Etk_Textblock_Node *children = NULL, *n; + + if (!node1 || !node2) + return -1; + if (node1 == node2) + return 0; + + /* We search the common parent node */ + c1 = node1; + c2 = node2; + for (p1 = node1->parent; p1; p1 = p1->parent) + { + for (p2 = node2->parent; p2; p2 = p2->parent) + { + if (p1 == p2) + { + children = p1->children; + break; + } + c2 = p2; + } + + if (children) + break; + c1 = p1; + } + + /* Then we compare the positions of the nodes in the list of children of the common parent */ + for (n = children; n; n = n->next) + { + if (n == c1 && n != c2) + return -1; + else if (n != c1 && n == c2) + return 1; + else if (n == c1 && n == c2) + return 0; + } + + return -1; +} + /* Splits the node at "index". It returns the right node (the left node being "node") * "pos" is the unicode position where to split the node, it *has* to be in accord with "index". * If you don't know the unicode position, use -1 */ @@ -1772,6 +1813,242 @@ * **************************/ +/* Adds a new line to a the textblock object, associated to a line node */ +static void _etk_textblock_object_line_add(Evas_Object *tbo, Etk_Textblock_Node *line_node) +{ + Etk_Textblock_Object_SD *tbo_sd; + Etk_Textblock_Object_Line *line, *new_line; + + if (!tbo || !(tbo_sd = evas_object_smart_data_get(tbo))) + return; + + new_line = malloc(sizeof(Etk_Textblock_Object_Line)); + new_line->node = line_node; + new_line->object = NULL; + new_line->geometry.w = 0; + new_line->geometry.h = 0; + + if (!tbo_sd->lines) + tbo_sd->lines = evas_list_append(tbo_sd->lines, new_line); + else + { + line = tbo_sd->lines->data; + if (_etk_textblock_node_compare(line_node, line->node) <= 0) + tbo_sd->lines = evas_list_prepend(tbo_sd->lines, new_line); + else + { + line = evas_list_last(tbo_sd->lines)->data; + if (_etk_textblock_node_compare(line_node, line->node) >= 0) + tbo_sd->lines = evas_list_append(tbo_sd->lines, new_line); + else + { + /* TODO: We need to optimize that (and to actually do it!!)! */ + tbo_sd->lines = evas_list_append(tbo_sd->lines, new_line); + } + } + } + + _etk_textblock_object_line_update_queue(tbo, new_line, ETK_TRUE, ETK_TRUE); +} + +/* Queues an update for a line of the textblock object */ +static void _etk_textblock_object_line_update_queue(Evas_Object *tbo, Etk_Textblock_Object_Line *line, Etk_Bool content_update, Etk_Bool geometry_update) +{ + Etk_Textblock_Object_SD *tbo_sd; + + if (!tbo || !line || !(tbo_sd = evas_object_smart_data_get(tbo))) + return; + + line->need_geometry_update |= geometry_update; + line->need_content_update |= content_update; + + if (!tbo_sd->update_job) + tbo_sd->update_job = ecore_job_add(_etk_textblock_object_update_job, tbo); +} + +/* Updates the line of the textblock object */ +static void _etk_textblock_object_line_update(Evas_Object *tbo, Etk_Textblock_Object_Line *line, int y) +{ + Etk_Textblock_Object_SD *tbo_sd; + Evas *evas; + int ox, oy, ow, oh; + + if (!tbo || !line || !(tbo_sd = evas_object_smart_data_get(tbo))) + return; + if (!(evas = evas_object_evas_get(tbo))) + return; + if (!line->need_content_update && !line->need_geometry_update) + return; + + evas_object_geometry_get(tbo, &ox, &oy, &ow, &oh); + + if (!line->object) + { + line->object = evas_object_textblock_add(evas); + evas_object_textblock_style_set(line->object, tbo_sd->style); + evas_object_show(line->object); + } + + if (line->need_content_update) + { + Evas_Textblock_Cursor *cur; + + evas_object_textblock_clear(line->object); + cur = evas_object_textblock_cursor_new(line->object); + evas_textblock_cursor_node_first(cur); + _etk_textblock_object_line_fill(cur, line->node); + evas_textblock_cursor_free(cur); + + line->need_content_update = ETK_FALSE; + } + + if (line->need_geometry_update) + { + line->geometry.x = 0; + line->geometry.y = y; + evas_object_resize(line->object, ow, 300); + evas_object_textblock_size_formatted_get(line->object, &line->geometry.w, &line->geometry.h); + /* TODO: re-align if line->geometry.w != ow */ + + evas_object_move(line->object, ox + line->geometry.x, oy + line->geometry.y); + evas_object_resize(line->object, ow, line->geometry.h); + + line->need_geometry_update = ETK_FALSE; + } +} + +/* Fills recursively the line of the textblock object with the content of a node */ +static void _etk_textblock_object_line_fill(Evas_Textblock_Cursor *cur, Etk_Textblock_Node *node) +{ + Etk_String *fmt_str = NULL; + Etk_Textblock_Node *n; + int opened_nodes = 0, i; + + if (!cur || !node) + return; + + /* A line node */ + if (node->type == ETK_TEXTBLOCK_NODE_LINE) + { + Etk_Textblock_Node *paragraph; + + if ((paragraph = node->parent) && paragraph->type == ETK_TEXTBLOCK_NODE_PARAGRAPH) + { + /* Alignment */ + if (paragraph->tag.params.p.align == 0.5) + { + evas_textblock_cursor_format_append(cur, "+ align=center"); + opened_nodes++; + } + else if (paragraph->tag.params.p.align == 1.0) + { + evas_textblock_cursor_format_append(cur, "+ align=right"); + opened_nodes++; + } + /* TODO: Does Evas' textblock support float alignments? */ + + /* Margins */ + if (paragraph->tag.params.p.left_margin > 0) + { + fmt_str = etk_string_set_printf(fmt_str, "+ left_margin=+%d", paragraph->tag.params.p.left_margin); + evas_textblock_cursor_format_append(cur, etk_string_get(fmt_str)); + opened_nodes++; + } + if (paragraph->tag.params.p.right_margin > 0) + { + fmt_str = etk_string_set_printf(fmt_str, "+ right_margin=+%d", paragraph->tag.params.p.right_margin); + evas_textblock_cursor_format_append(cur, etk_string_get(fmt_str)); + opened_nodes++; + } + } + } + /* A normal node */ + else if (node->type == ETK_TEXTBLOCK_NODE_NORMAL && etk_string_length_get(node->text) > 0) + { + Etk_Textblock_Format format; + + /* We add the format nodes */ + /* TODO: we need to make the font changeable */ + _etk_textblock_node_format_get(node, &format); + + opened_nodes++; + if (format.bold && !format.italic) + evas_textblock_cursor_format_append(cur, "+ font=Vera-Bold"); + else if (!format.bold && format.italic) + evas_textblock_cursor_format_append(cur, "+ font=Vera-Italic"); + else if (format.bold && format.italic) + evas_textblock_cursor_format_append(cur, "+ font=Vera-Bold-Italic"); + else + opened_nodes--; + + if (format.font_size >= 0) + { + fmt_str = etk_string_set_printf(fmt_str, "+ font_size=%d", format.font_size); + evas_textblock_cursor_format_append(cur, etk_string_get(fmt_str)); + opened_nodes++; + } + if (format.font_color.r >= 0) + { + fmt_str = etk_string_set_printf(fmt_str, "+ color=#%.2X%.2X%.2X%.2X", format.font_color.r, + format.font_color.g, format.font_color.b, format.font_color.a); + evas_textblock_cursor_format_append(cur, etk_string_get(fmt_str)); + opened_nodes++; + } + } + + /* Then, we insert the text */ + if (etk_string_length_get(node->text) > 0) + evas_textblock_cursor_text_append(cur, etk_string_get(node->text)); + + /* Finally, we close the format nodes that we have opened */ + for (i = 0; i < opened_nodes; i++) + { + evas_textblock_cursor_format_append(cur, "-"); + if (node->type == ETK_TEXTBLOCK_NODE_LINE) + evas_textblock_cursor_node_prev(cur); + } + + + etk_object_destroy(ETK_OBJECT(fmt_str)); + + /* Fills with the children */ + for (n = node->children; n; n = n->next) + _etk_textblock_object_line_fill(cur, n); +} + +/* Updates the textblock object */ +static void _etk_textblock_object_update(Evas_Object *tbo) +{ + Etk_Textblock_Object_SD *tbo_sd; + Etk_Textblock_Object_Line *line; + Evas_List *l; + int y; + + if (!tbo || !(tbo_sd = evas_object_smart_data_get(tbo))) + return; + + y = 0; + for (l = tbo_sd->lines; l; l = l->next) + { + line = l->data; + _etk_textblock_object_line_update(tbo, line, y); + y = line->geometry.y + line->geometry.h; + } +} + +/* The job used to update the textblock object */ +static void _etk_textblock_object_update_job(void *data) +{ + Evas_Object *tbo; + Etk_Textblock_Object_SD *tbo_sd; + + if (!(tbo = data) || !(tbo_sd = evas_object_smart_data_get(tbo))) + return; + + _etk_textblock_object_update(tbo); + tbo_sd->update_job = NULL; +} + /************************** * * Textblock object's smart object @@ -1791,7 +2068,12 @@ tbo_sd->tb = NULL; tbo_sd->wrap = ETK_TEXTBLOCK_WRAP_WORD; tbo_sd->cursor_object = NULL; - tbo_sd->paragraphs = NULL; + tbo_sd->lines = NULL; + tbo_sd->update_job = NULL; + + tbo_sd->style = evas_textblock_style_new(); + evas_textblock_style_set(tbo_sd->style, "DEFAULT='font=Vera font_size=10 align=left color=#000000 wrap=word'"); + evas_object_smart_data_set(obj, tbo_sd); } @@ -1799,22 +2081,26 @@ static void _etk_tb_object_smart_del(Evas_Object *obj) { Etk_Textblock_Object_SD *tbo_sd; - Etk_Textblock_Object_Paragraph *p; + Etk_Textblock_Object_Line *line; if (!obj || !(tbo_sd = evas_object_smart_data_get(obj))) return; - while (tbo_sd->paragraphs) + if (tbo_sd->update_job) + ecore_job_del(tbo_sd->update_job); + + while (tbo_sd->lines) { - p = tbo_sd->paragraphs->data; + line = tbo_sd->lines->data; - if (p->object) - evas_object_del(p->object); - free(p); + if (line->object) + evas_object_del(line->object); + free(line); - tbo_sd->paragraphs = evas_list_remove_list(tbo_sd->paragraphs, tbo_sd->paragraphs); + tbo_sd->lines = evas_list_remove_list(tbo_sd->lines, tbo_sd->lines); } evas_object_del(tbo_sd->cursor_object); + evas_textblock_style_free(tbo_sd->style); tbo_sd->tb->evas_objects = evas_list_remove(tbo_sd->tb->evas_objects, obj); free(tbo_sd); @@ -1833,19 +2119,19 @@ Etk_Textblock_Object_SD *tbo_sd; Evas_Coord prev_x, prev_y; Evas_List *l; - Etk_Textblock_Object_Paragraph *p; + Etk_Textblock_Object_Line *line; if (!obj || !(tbo_sd = evas_object_smart_data_get(obj))) return; evas_object_geometry_get(obj, &prev_x, &prev_y, NULL, NULL); - for (l = tbo_sd->paragraphs; l; l = l->next) + for (l = tbo_sd->lines; l; l = l->next) { - p = l->data; - p->geometry.x += x - prev_x; - p->geometry.y += y - prev_y; - if (p->object) - evas_object_move(p->object, p->geometry.x, p->geometry.y); + line = l->data; + line->geometry.x += x - prev_x; + line->geometry.y += y - prev_y; + if (line->object) + evas_object_move(line->object, line->geometry.x, line->geometry.y); } } @@ -1853,13 +2139,22 @@ static void _etk_tb_object_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) { Etk_Textblock_Object_SD *tbo_sd; - Evas_Coord x, y; if (!obj || !(tbo_sd = evas_object_smart_data_get(obj))) return; - evas_object_geometry_get(obj, &x, &y, NULL, NULL); - /* TODO: _etk_tb_object_smart_resize(): re-render!! */ + /* TODO: _etk_tb_object_smart_resize: optimize if the text is not wrapped? */ + /*if (tbo_sd->wrap == ETK_TEXTBLOCK_WRAP_NONE) + { + + } + else*/ + { + Evas_List *l; + + for (l = tbo_sd->lines; l; l = l->next) + _etk_textblock_object_line_update_queue(obj, l->data, ETK_FALSE, ETK_TRUE); + } } /* Shows the textblock object */ =================================================================== RCS file: /cvs/e/e17/proto/etk/src/lib/etk_textblock.h,v retrieving revision 1.8 retrieving revision 1.9 diff -u -3 -r1.8 -r1.9 --- etk_textblock.h 2 Jul 2006 04:01:19 -0000 1.8 +++ etk_textblock.h 3 Jul 2006 05:06:26 -0000 1.9 @@ -4,7 +4,6 @@ #include "etk_object.h" #include <Evas.h> -#include <Ecore_Job.h> #include "etk_types.h" /** @@ -179,7 +178,6 @@ Evas_List *iters; Evas_List *evas_objects; - Ecore_Job *update_job; }; /* Textblock's funcs */ Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs