Enlightenment CVS committal

Author  : moom
Project : e17
Module  : proto

Dir     : e17/proto/etk/src/lib


Modified Files:
        etk_progress_bar.c etk_textblock.c etk_textblock.h 


Log Message:
* [Progress Bar] Fix a mem leak
* [Textblock] More work: the whole structure has been changed again, it's still 
a bit buggy... No rendering yet!


===================================================================
RCS file: /cvs/e/e17/proto/etk/src/lib/etk_progress_bar.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -3 -r1.11 -r1.12
--- etk_progress_bar.c  23 Jun 2006 18:14:50 -0000      1.11
+++ etk_progress_bar.c  2 Jul 2006 04:01:19 -0000       1.12
@@ -21,6 +21,7 @@
 };
 
 static void _etk_progress_bar_constructor(Etk_Progress_Bar *progress_bar);
+static void _etk_progress_bar_destructor(Etk_Progress_Bar *progress_bar);
 static void _etk_progress_bar_property_set(Etk_Object *object, int 
property_id, Etk_Property_Value *value);
 static void _etk_progress_bar_property_get(Etk_Object *object, int 
property_id, Etk_Property_Value *value);
 static void _etk_progress_bar_update(Etk_Progress_Bar *progress_bar);
@@ -43,7 +44,7 @@
    if (!progress_bar_type)
    {
       progress_bar_type = etk_type_new("Etk_Progress_Bar", ETK_WIDGET_TYPE, 
sizeof(Etk_Progress_Bar),
-         ETK_CONSTRUCTOR(_etk_progress_bar_constructor), NULL);
+         ETK_CONSTRUCTOR(_etk_progress_bar_constructor), 
ETK_DESTRUCTOR(_etk_progress_bar_destructor));
 
       etk_type_property_add(progress_bar_type, "text", 
ETK_PROGRESS_BAR_TEXT_PROPERTY,
          ETK_PROPERTY_STRING, ETK_PROPERTY_READABLE_WRITABLE, 
etk_property_value_string(NULL));
@@ -261,6 +262,15 @@
    progress_bar->is_pulsing = ETK_FALSE;
    
    etk_signal_connect("realize", ETK_OBJECT(progress_bar), 
ETK_CALLBACK(_etk_progress_bar_realize_cb), NULL);
+}
+
+/* Destroys the progress bar */
+static void _etk_progress_bar_destructor(Etk_Progress_Bar *progress_bar)
+{
+   if (!progress_bar)
+      return;
+   
+   free(progress_bar->text);
 }
 
 /* Sets the property whose id is "property_id" to the value "value" */
===================================================================
RCS file: /cvs/e/e17/proto/etk/src/lib/etk_textblock.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -3 -r1.10 -r1.11
--- etk_textblock.c     17 Jun 2006 12:01:26 -0000      1.10
+++ etk_textblock.c     2 Jul 2006 04:01:19 -0000       1.11
@@ -6,34 +6,11 @@
 #include "etk_string.h"
 #include "etk_utils.h"
 
-//#define TB_DEBUG 1
-#define ETK_TB_MAX_SEGMENT_CHARS 100
-
 /**
  * @addtogroup Etk_Textblock
  * @{
  */
 
-/* TODOC */
-typedef struct Etk_Textblock_Object_Paragraph
-{
-   Etk_Geometry geometry;
-   Evas_List *lines;
-} Etk_Textblock_Object_Paragraph;
-
-/* TODOC */
-typedef struct Etk_Textblock_Object_Line
-{
-   Etk_Geometry geometry;
-   Evas_List *segments;
-} Etk_Textblock_Object_Line;
-
-/* TODOC */
-typedef struct Etk_Textblock_Object_Segment
-{
-   Etk_Geometry geometry;
-} Etk_Textblock_Object_Segment;
-
 /* The smart data of a textblock object */
 typedef struct Etk_Textblock_Object_SD
 {
@@ -41,38 +18,47 @@
    
    Etk_Textblock_Wrap wrap;
    
-   Evas_Object *cursor_object;
-   Evas_List *text_objects;
-   
    Evas_List *paragraphs;
+   Evas_Object *cursor_object;
 } Etk_Textblock_Object_SD;
 
+/* A paragraph  */
+typedef struct Etk_Textblock_Object_Paragraph
+{
+   Etk_Geometry geometry;
+   Evas_Object *object;
+   Etk_Bool need_geometry_update;
+   Etk_Bool need_content_update;
+} Etk_Textblock_Object_Paragraph;
+
 static void _etk_tb_constructor(Etk_Textblock *tb);
 static void _etk_tb_destructor(Etk_Textblock *tb);
-static void _etk_tb_iter_constructor(Etk_Textblock_Iter *tbi);
-static void _etk_tb_iter_destructor(Etk_Textblock_Iter *tbi);
 
 static void _etk_textblock_node_printf(Etk_Textblock_Node *node, int n_tabs);
-static Etk_Textblock_Node *_etk_textblock_node_new(Etk_Textblock_Node *parent, 
Etk_Textblock_Node *prev, Etk_Textblock_Tag_Type tag_type);
+static Etk_Textblock_Node *_etk_textblock_node_new(Etk_Textblock_Node *parent, 
Etk_Textblock_Node *prev, Etk_Textblock_Node_Type node_type, 
Etk_Textblock_Tag_Type tag_type);
 static Etk_Textblock_Node *_etk_textblock_node_free(Etk_Textblock_Node *node);
-static void _etk_textblock_node_type_set(Etk_Textblock_Node *node, 
Etk_Textblock_Tag_Type tag_type);
+static void _etk_textblock_node_type_set(Etk_Textblock_Node *node, 
Etk_Textblock_Node_Type node_type, Etk_Textblock_Tag_Type tag_type);
 static void _etk_textblock_node_attach(Etk_Textblock_Node *node, 
Etk_Textblock_Node *parent, Etk_Textblock_Node *prev);
 static void _etk_textblock_node_format_get(Etk_Textblock_Node *node, 
Etk_Textblock_Format *format);
 
-static Etk_Textblock_Node *_etk_texblock_nodes_clean(Etk_Textblock_Node 
*nodes);
+static Etk_Textblock_Node *_etk_textblock_nodes_clean(Etk_Textblock *tb, 
Etk_Textblock_Node *nodes);
 static void _etk_textblock_tag_insert(Etk_Textblock *tb, Etk_Textblock_Iter 
*iter, const char *tag, int length);
+static void _etk_textblock_paragraph_add(Etk_Textblock *tb, Etk_Textblock_Iter 
*iter);
+static void _etk_textblock_line_add(Etk_Textblock *tb, Etk_Textblock_Iter 
*iter);
 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 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);
+
 static Etk_Bool _etk_textblock_iter_is_valid(Etk_Textblock *tb, 
Etk_Textblock_Iter *iter);
+static Etk_Bool _etk_textblock_node_is_default_paragraph(Etk_Textblock_Node 
*node);
 
 static int _etk_textblock_int_parse(const char *int_string, int length, int 
error_value);
 static float _etk_textblock_float_parse(const char *float_string, int length, 
float error_value);
 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_tb_object_render(Evas_Object *tbo, int x, int y, int w, int 
h);
-static void _etk_tb_object_render_node(Evas_Object *tbo, Etk_Geometry og, 
Etk_Textblock_Node *node, int x, int y, int *next_x, int *next_y);
-static int _etk_tb_object_render_segment(Evas_Object *tbo, const char *text, 
int len, Etk_Textblock_Format format, int sx, int sy, int sw, int *rw, int *rh);
-
 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);
@@ -93,7 +79,11 @@
  * Implementation
  *
  **************************/
-
+ 
+/**************************
+ * Textblock's funcs
+ **************************/
+ 
 /**
  * @brief Gets the type of an Etk_Textblock
  * @return Returns the type of an Etk_Textblock
@@ -112,23 +102,6 @@
 }
 
 /**
- * @brief Gets the type of an Etk_Textblock_Iter
- * @return Returns the type of an Etk_Textblock_Iter
- */
-Etk_Type *etk_textblock_iter_type_get()
-{
-   static Etk_Type *textblock_iter_type = NULL;
-
-   if (!textblock_iter_type)
-   {
-      textblock_iter_type = etk_type_new("Etk_Textblock_Iter", 
ETK_OBJECT_TYPE, sizeof(Etk_Textblock_Iter),
-         ETK_CONSTRUCTOR(_etk_tb_iter_constructor), 
ETK_DESTRUCTOR(_etk_tb_iter_destructor));
-   }
-
-   return textblock_iter_type;
-}
-
-/**
  * @brief Creates a new textblock
  * @return Returns the new textblock
  */
@@ -138,31 +111,13 @@
 }
 
 /**
- * @brief Creates a new iterator for the textblock
- * @param tb a textblock
- * @return Returns the new iterator, placed at the start of the first node of 
the textblock
- */
-Etk_Textblock_Iter *etk_textblock_iter_new(Etk_Textblock *tb)
-{
-   Etk_Textblock_Iter *iter;
-   
-   if (!tb)
-      return NULL;
-   
-   iter = ETK_TEXTBLOCK_ITER(etk_object_new(ETK_TEXTBLOCK_ITER_TYPE, NULL));
-   
-   iter->tb = tb;
-   tb->iters = evas_list_append(tb->iters, iter);
-   etk_textblock_iter_backward_start(iter);
-   
-   return iter;
-}
-
-/**
  * @brief Sets the text of the textblock. The current text will be replaced by 
@a text
  * @param tb a textblock
  * @param text the text to set
- * @param markup TODOC
+ * @param markup whether or not you want to apply markup and styling on the 
text.
+ * If @a markup is ETK_TRUE, you can use tags to format the text.
+ * @note After that, the iterators with right gravity will be at the end of 
the textblock,
+ * and iterators with left gravity will be at the start of the textblock
  */
 void etk_textblock_text_set(Etk_Textblock *tb, const char *text, Etk_Bool 
markup)
 {
@@ -181,14 +136,14 @@
       etk_textblock_text_insert(tb, iter, text, -1);
    else
       etk_textblock_text_insert_markup(tb, iter, text, -1);
-   etk_object_destroy(ETK_OBJECT(iter));
+   etk_textblock_iter_free(iter);
 }
 
 /**
  * @brief Gets the text of the textblock
  * @param tb a textblock
- * @param markup TODOC
- * @return Returns a string containing the text of the markup.
+ * @param markup whether or not you want to have tags in the returned text
+ * @return Returns a string containing the text of the textblock.
  * Once you no longer need the returned string, you should destroy it with 
etk_object_destroy()
  */
 Etk_String *etk_textblock_text_get(Etk_Textblock *tb, Etk_Bool markup)
@@ -199,7 +154,7 @@
       return NULL;
    
    text = etk_string_new(NULL);
-   /* TODO: use iters or, better, pos */
+   /* TODO: use etk_textblock_text_get_range() or something like that */
    _etk_textblock_node_text_get(&tb->root, markup, text);
    
    return text;
@@ -212,90 +167,139 @@
 void etk_textblock_clear(Etk_Textblock *tb)
 {
    Evas_List *l;
+   Etk_Textblock_Node *node;
    
    if (!tb)
       return;
    
    while (tb->root.children)
       tb->root.children = _etk_textblock_node_free(tb->root.children);
+   
+   /* 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);
+   
    for (l = tb->iters; l; l = l->next)
-      etk_textblock_iter_backward_start(ETK_TEXTBLOCK_ITER(l->data));
+      etk_textblock_iter_backward_start(l->data);
+   
+   /* TODO: update the objects */
 }
 
 /**
- * @brief Inserts @a length bytes of @a text at @a iter in the textblock
+ * @brief Inserts @a length bytes of @a text at @a iter in the textblock.
+ * If you want to use tags to format the text to insert, use 
etk_textblock_text_insert_markup() instead.
  * @param tb a textblock
- * @param iter the iterator where to insert the text (TODOC: gravity)
+ * @param iter the iterator where to insert the text. @n
+ * If the gravity of @a iter is left, the iter will be placed before the 
inserted text.
+ * Otherwise, the iterator will placed after the inserted text.
  * @param text the unicode-encoded text to insert
  * @param length the number of bytes to insert. If @a length is negative, the 
text will be entirely inserted
  */
 void etk_textblock_text_insert(Etk_Textblock *tb, Etk_Textblock_Iter *iter, 
const char *text, int length)
 {
    Evas_List *l;
-   Etk_Textblock_Iter *it;
+   Etk_Textblock_Iter *it, *it2;
    int unicode_length, char_length;
    int pos, index;
-   int i;
+   int i, node_start, node_end;
+   Etk_Bool done, new_line;
    
    if (!tb || !iter || !text)
       return;
    if (!_etk_textblock_iter_is_valid(tb, iter))
       return;
    
-   /* Calculates the length in bytes (char_length) and the length in unicode 
characters (unicode_length)
-    * of the string to insert */
-   if (length < 0)
+   if (iter->gravity == ETK_TEXTBLOCK_GRAVITY_LEFT)
    {
-      unicode_length = etk_textblock_unicode_length_get(text);
-      char_length = strlen(text);
+      it = etk_textblock_iter_new(tb);
+      etk_textblock_iter_copy(it, iter);
+      it->gravity = ETK_TEXTBLOCK_GRAVITY_RIGHT;
    }
    else
-   {
-      unicode_length = 0;
-      char_length = -1;
-      for (i = 0; i <= length; i = evas_string_char_next_get(text, i, NULL))
+      it = iter;
+   
+   index = -1;
+   node_start = -1;
+   node_end = -1;
+   new_line = ETK_FALSE;
+   unicode_length = 0;
+   for (i = 0, done = ETK_FALSE; !done; i = evas_string_char_next_get(text, i, 
NULL))
+   {
+      /* Have we finished? */
+      if (index == i || (length >= 0 && i >= length))
+      {
+         node_end = index;
+         done = ETK_TRUE;
+         unicode_length--;
+      }
+      
+      /* Detects the ends of line */
+      if (text[i] == '\n' || text[i] == '\r')
       {
-         if (char_length == i )
-            break;
+         node_end = i - 1;
+         new_line = ETK_TRUE;
+         unicode_length--;
          
-         unicode_length++;
-         char_length = i;
+         if ((length < 0 || i < length) && text[i] == '\r' && text[i + 1] == 
'\n')
+            i++;
       }
-   }
-   
-   /* The root node can't have text, so we create a new node */
-   if (iter->node->tag.type == ETK_TEXTBLOCK_TAG_ROOT)
-   {
-      _etk_textblock_node_new(&tb->root, NULL, ETK_TEXTBLOCK_TAG_DEFAULT);
-      for (l = tb->iters; l; l = l->next)
-         etk_textblock_iter_backward_start(ETK_TEXTBLOCK_ITER(l->data));
-   }
-   
-   /* Sets the text of the node */
-   iter->node->text = etk_string_insert_sized(iter->node->text, iter->index, 
text, char_length);
-   iter->node->unicode_length += unicode_length;
-   
-   /* Updates the iterators */
-   pos = iter->pos;
-   index = iter->index;
-   for (l = tb->iters; l; l = l->next)
-   {
-      it = ETK_TEXTBLOCK_ITER(l->data);
-      if (it->node == iter->node)
+      
+      if (node_start < 0)
+         node_start = i;
+      unicode_length++;
+      
+      /* If we have parsed a full node or a "end of line" sequence, we insert 
the text or create a "end of line" node */
+      if ((node_start >= 0 && node_end >= 0) || new_line)
       {
-         if (it->pos > pos || (it->pos == pos && it->gravity == 
ETK_TEXTBLOCK_GRAVITY_RIGHT))
+         char_length = node_end - node_start + 1;
+         
+         /* We insert the text */
+         if (char_length > 0)
          {
-            it->pos += unicode_length;
-            it->index += char_length;
+            /* Sets the text of the node */
+            it->node->text = etk_string_insert_sized(it->node->text, 
it->index, &text[node_start], char_length);
+            it->node->unicode_length += unicode_length;
+            
+            /* Updates the iterators */
+            pos = it->pos;
+            index = it->index;
+            for (l = tb->iters; l; l = l->next)
+            {
+               it2 = l->data;
+               if (it2->node == it->node)
+               {
+                  if (it2->pos > pos || (it2->pos == pos && it2->gravity == 
ETK_TEXTBLOCK_GRAVITY_RIGHT))
+                  {
+                     it2->pos += unicode_length;
+                     it2->index += char_length;
+                  }
+               }
+            }
          }
+         
+         /* We create a new "end of line" node */ 
+         if (new_line)
+            _etk_textblock_line_add(tb, it);
+         
+         node_start = -1;
+         node_end = - 1;
+         new_line = ETK_FALSE;
+         unicode_length = 0;
       }
+      
+      index = i;
    }
+   
+   if (it->gravity == ETK_TEXTBLOCK_GRAVITY_LEFT)
+      etk_textblock_iter_free(it);
 }
 
 /**
- * @brief Inserts @a length bytes of @a text at @a iter in the textblock. 
(markup: TODOC)
+ * @brief Inserts @a length bytes of @a text at @a iter in the textblock. You 
can use tags to format the text to insert.
  * @param tb a textblock
- * @param iter the iterator where to insert the text (TODOC: gravity)
+ * @param iter the iterator where to insert the text. @n
+ * If the gravity of @a iter is left, the iter will be placed before the 
inserted text.
+ * Otherwise, the iterator will placed after the inserted text.
  * @param text the unicode-encoded markup text to insert
  * @param length the number of bytes to insert. If @a length is negative, the 
text will be entirely inserted
  */
@@ -319,7 +323,6 @@
    }
    else
       it = iter;
-   it = iter;
    
    for (t = markup_text; *t != '\0'; t++)
    {
@@ -333,7 +336,6 @@
       
       if (text_start)
       {
-         /* TODO: unicode potential bug if '<' is a part of a unicode code? */
          if (*(t + 1) == '<' || *(t + 1) == '\0')
          {
             etk_textblock_text_insert(tb, it, text_start, t - text_start + 1);
@@ -350,9 +352,10 @@
       }
    }
    
-   tb->root.children = _etk_texblock_nodes_clean(tb->root.children);
+   /* TODO: optimize (only clean the modified nodes)? */
+   tb->root.children = _etk_textblock_nodes_clean(tb, tb->root.children);
    if (iter->gravity == ETK_TEXTBLOCK_GRAVITY_LEFT)
-      etk_object_destroy(ETK_OBJECT(it));
+      etk_textblock_iter_free(it);
 }
 
 /**
@@ -370,6 +373,73 @@
    printf("----------------\n\n");
 }
 
+/**************************
+ * Textblock Iter's funcs
+ **************************/
+
+/**
+ * @brief Creates a new iterator for the textblock
+ * @param tb a textblock
+ * @return Returns the new iterator, placed at the start of the first node of 
the textblock
+ */
+Etk_Textblock_Iter *etk_textblock_iter_new(Etk_Textblock *tb)
+{
+   Etk_Textblock_Iter *iter;
+   
+   if (!tb)
+      return NULL;
+   
+   iter = malloc(sizeof(Etk_Textblock_Iter));
+   iter->tb = tb;
+   iter->node = &tb->root;
+   iter->gravity = ETK_TEXTBLOCK_GRAVITY_RIGHT;
+   iter->pos = 0;
+   iter->index = 0;
+   
+   tb->iters = evas_list_append(tb->iters, iter);
+   etk_textblock_iter_backward_start(iter);
+   
+   return iter;
+}
+
+/**
+ * @brief Destroys an iterator of the textblock
+ * @param iter the iterator to destroy
+ */
+void etk_textblock_iter_free(Etk_Textblock_Iter *iter)
+{
+   if (!iter)
+      return;
+   
+   if (iter->tb)
+      iter->tb->iters = evas_list_remove(iter->tb->iters, iter);
+   free(iter);
+}
+
+/**
+ * @brief Sets the gravity of the iterator (TODOC: gravity)
+ * @param iter an iterator
+ * @param gravity the gravity to set to the iterator
+ */
+void etk_textblock_iter_gravity_set(Etk_Textblock_Iter *iter, 
Etk_Textblock_Gravity gravity)
+{
+   if (!iter)
+      return;
+   iter->gravity = gravity;
+}
+
+/**
+ * @brief Gets the gravity of the iterator
+ * @param iter an iterator
+ * @return Returns the gravity of the iterator (ETK_TEXTBLOCK_GRAVITY_RIGHT by 
default)
+ */
+Etk_Textblock_Gravity etk_textblock_iter_gravity_get(Etk_Textblock_Iter *iter)
+{
+   if (!iter)
+      return ETK_TEXTBLOCK_GRAVITY_RIGHT;
+   return iter->gravity;
+}
+
 /**
  * @brief Moves the iterator to the start of the textblock
  * @param iter an iterator
@@ -487,6 +557,10 @@
    return -1;
 }
 
+/**************************
+ * Textblock Object's funcs
+ **************************/
+
 /**
  * @brief Creates a new evas object that will display the content of the 
textblock. @n
  * A textblock can have several evas objects which display its content. All 
the evas objects are automatically updated
@@ -527,6 +601,7 @@
    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 */
    
    tb->evas_objects = evas_list_append(tb->evas_objects, obj);
    
@@ -547,6 +622,7 @@
    
    if (tbo_sd->wrap != wrap)
       tbo_sd->wrap = wrap;
+   /* TODO: update the object */
 }
 
 /**
@@ -564,8 +640,10 @@
 }
 
 /**
- * @brief Gets the length of the unicode-encoded string.
- * It's not always the number of bytes of the string since a character can be 
encoded on several bytes in unicode.
+ * @brief Gets the length of a unicode-encoded string.
+ * It's not always the number of bytes of the string since a character can be 
encoded with several bytes in unicode.
+ * @param unicode_string a unicode-encoded string
+ * @return Returns the unicode length of @a unicode_string
  */
 int etk_textblock_unicode_length_get(const char *unicode_string)
 {
@@ -604,10 +682,13 @@
 /* Initializes the textblock */
 static void _etk_tb_constructor(Etk_Textblock *tb)
 {
+   Etk_Textblock_Node *node;
+   
    if (!tb)
       return;
    
-   tb->root.tag.type = ETK_TEXTBLOCK_TAG_ROOT;
+   tb->root.type = ETK_TEXTBLOCK_NODE_ROOT;
+   tb->root.tag.type = ETK_TEXTBLOCK_TAG_DEFAULT;
    tb->root.text = NULL;
    tb->root.unicode_length = 0;   
    tb->root.parent = NULL;
@@ -615,9 +696,13 @@
    tb->root.next = NULL;
    tb->root.children = NULL;
    
+   /* Adds an empty line */
+   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_NORMAL, 
ETK_TEXTBLOCK_TAG_DEFAULT);
+   
    tb->iters = NULL;
-   tb->line_iters = NULL;
    tb->evas_objects = NULL;
+   tb->update_job = NULL;
 }
 
 /* Destroys the textblock */
@@ -626,39 +711,19 @@
    if (!tb)
       return;
    
+   if (tb->update_job)
+      ecore_job_del(tb->update_job);
+   
    while (tb->evas_objects)
       evas_object_del(tb->evas_objects->data);
    
    while (tb->iters)
-      etk_object_destroy(ETK_OBJECT(tb->iters->data));
+      etk_textblock_iter_free(tb->iters->data);
    
    while (tb->root.children)
       tb->root.children = _etk_textblock_node_free(tb->root.children);
 }
 
-/* Initializes the textblock iterator */
-static void _etk_tb_iter_constructor(Etk_Textblock_Iter *tbi)
-{
-   if (!tbi)
-      return;
-   
-   tbi->tb = NULL;
-   tbi->node = NULL;
-   tbi->gravity = ETK_TEXTBLOCK_GRAVITY_RIGHT;
-   tbi->pos = 0;
-   tbi->index = 0;
-}
-
-/* Destroys the textblock iterator */
-static void _etk_tb_iter_destructor(Etk_Textblock_Iter *tbi)
-{
-   if (!tbi)
-      return;
-   
-   if (tbi->tb)
-      tbi->tb->iters = evas_list_remove(tbi->tb->iters, tbi);
-}
-
 /**************************
  *
  * Private functions
@@ -676,7 +741,7 @@
    
    for (i = 0; i < n_tabs; i++)
       printf("\t");
-   printf("NODE TAG: %d\n", node->tag.type);
+   printf("NODE TAG: %d %d\n", node->type, node->tag.type);
    for (i = 0; i < n_tabs; i++)
       printf("\t");
    printf("NODE TEXT: %s\n", etk_string_get(node->text) ? 
etk_string_get(node->text) : "NULL");
@@ -688,11 +753,12 @@
 
 /* Creates a new node, and attachs it to the "parent" node, after the "prev" 
node */
 /* If "prev" == NULL, the new node is prepended to the list of nodes of the 
"parent" */
-static Etk_Textblock_Node *_etk_textblock_node_new(Etk_Textblock_Node *parent, 
Etk_Textblock_Node *prev, Etk_Textblock_Tag_Type tag_type)
+static Etk_Textblock_Node *_etk_textblock_node_new(Etk_Textblock_Node *parent, 
Etk_Textblock_Node *prev, Etk_Textblock_Node_Type node_type, 
Etk_Textblock_Tag_Type tag_type)
 {
    Etk_Textblock_Node *node;
    
    node = malloc(sizeof(Etk_Textblock_Node));
+   node->type = ETK_TEXTBLOCK_NODE_NORMAL;
    node->tag.type = ETK_TEXTBLOCK_TAG_DEFAULT;
    node->text = NULL;
    node->unicode_length = 0;
@@ -701,7 +767,7 @@
    node->next = NULL;
    node->children = NULL;
    
-   _etk_textblock_node_type_set(node, tag_type);
+   _etk_textblock_node_type_set(node, node_type, tag_type);
    _etk_textblock_node_attach(node, parent, prev);
    
    return node;
@@ -737,7 +803,7 @@
 }
 
 /* Sets the type of the node */
-static void _etk_textblock_node_type_set(Etk_Textblock_Node *node, 
Etk_Textblock_Tag_Type tag_type)
+static void _etk_textblock_node_type_set(Etk_Textblock_Node *node, 
Etk_Textblock_Node_Type node_type, Etk_Textblock_Tag_Type tag_type)
 {
    if (!node)
       return;
@@ -745,6 +811,7 @@
    if (node->tag.type == ETK_TEXTBLOCK_TAG_FONT)
       free(node->tag.params.font.face);
    
+   node->type = node_type;
    node->tag.type = tag_type;
    switch (tag_type)
    {
@@ -780,6 +847,7 @@
    if (!node || (node->parent == parent && node->prev == prev))
       return;
    
+   /* First, we detach the node */
    if (node->parent)
    {
       if (node->parent->children == node)
@@ -790,15 +858,15 @@
          node->next->prev = node->prev;
    }
    
-   node->parent = parent;
-   node->children = NULL;
-   
+   /* Then we re-attach it */
    if (!prev || prev->parent != parent)
    {
       node->prev = NULL;
       if (parent)
       {
          node->next = parent->children;
+         if (node->next)
+            node->next->prev = node;
          parent->children = node;
       }
       else
@@ -808,8 +876,12 @@
    {
       node->prev = prev;
       node->next = prev->next;
+      if (node->next)
+         node->next->prev = node;
       prev->next = node;
    }
+   
+   node->parent = parent;
 }
 
 /* Gets the format of the node and store it in "format" */
@@ -876,20 +948,36 @@
 }
 
 /* Removes the empty nodes in the list of 'nodes' */
-/* TODO: _etk_texblock_nodes_clean(): updates the iterators? */
-/* TODO: Deeper clean? */
-static Etk_Textblock_Node *_etk_texblock_nodes_clean(Etk_Textblock_Node *nodes)
+static Etk_Textblock_Node *_etk_textblock_nodes_clean(Etk_Textblock *tb, 
Etk_Textblock_Node *nodes)
 {
    Etk_Textblock_Node *n, *res = NULL;
+   Etk_Textblock_Iter *it;
+   Evas_List *l;
+   Etk_Bool delete_node;
    
-   if (!nodes)
+   if (!tb || !nodes)
       return NULL;
    
    for (n = nodes; n; )
    {
-      n->children = _etk_texblock_nodes_clean(n->children);
+      n->children = _etk_textblock_nodes_clean(tb, n->children);
       
+      delete_node = ETK_FALSE;
       if (!n->children && etk_string_length_get(n->text) <= 0)
+      {
+         delete_node = ETK_TRUE;
+         for (l = tb->iters; l; l = l->next)
+         {
+            it = l->data;
+            if (it->node == n)
+            {
+               delete_node = ETK_FALSE;
+               break;
+            }
+         }
+      }
+      
+      if (delete_node)
          n = _etk_textblock_node_free(n);
       else
       {
@@ -911,12 +999,6 @@
    char *tag_name;
    Etk_Bool closing_tag;
    Etk_Textblock_Tag_Type tag_type;
-   Etk_Textblock_Node *node, *new_node, *new_iter_node;
-   const char *node_text;
-   Etk_String *new_string;
-   int trunc_len, uni_trunc_len, orig_len;
-   Evas_List *l;
-   Etk_Textblock_Iter *it;
    
    if (!tb || !iter || !tag)
       return;
@@ -988,127 +1070,82 @@
    }
    free(tag_name);
    
-   node = iter->node;
-   new_iter_node = node;
-   /* If there is no corresponding node to close, we do nothing */
+   /* We close the node */
    if (closing_tag)
    {
-      Etk_Textblock_Node *node_to_close;
-      
-      for (node_to_close = node; node_to_close; node_to_close = 
node_to_close->parent)
-      {
-         if (node_to_close->tag.type == tag_type)
-            break;
-      }
-      if (!node_to_close)
-         return;
-   }
-   
-   /* Splits the text of the iter's node */
-   trunc_len = iter->index;
-   uni_trunc_len = iter->pos;
-   orig_len = etk_string_length_get(node->text);
-   node_text = etk_string_get(node->text);
-   new_string = NULL;
-   if (trunc_len <= 0)
-   {
-      new_string = node->text;
-      node->text = NULL;
-      node->unicode_length = 0;
-   }
-   else if (trunc_len < orig_len)
-   {
-      new_string = etk_string_new(&node_text[trunc_len]);
-      etk_string_truncate(node->text, trunc_len);
-      node->unicode_length = trunc_len;
+      if (tag_type == ETK_TEXTBLOCK_TAG_P)
+         _etk_textblock_paragraph_add(tb, iter);
+      else
+         _etk_textblock_node_close(iter, ETK_TEXTBLOCK_NODE_NORMAL, tag_type, 
NULL);
    }
-   
-   if (closing_tag)
+   /* Or we create the new nodes for the opening tag */
+   else
    {
-      /* Closes the node */
-      Etk_Textblock_Node *node_to_close, *prev_node, *n;
-      
-      new_node = NULL;
-      prev_node = NULL;
-      for (node_to_close = node; node_to_close; node_to_close = 
node_to_close->parent)
-      {
-         if (node_to_close->tag.type == tag_type)
-            break;
-         
-         n = _etk_textblock_node_new(NULL, NULL, node_to_close->tag.type);
-         if (!new_node)
-            new_node = n;
-         if (prev_node)
-            prev_node->parent = n;
-         prev_node = n;
-      }
+      Etk_Textblock_Node *node;
+      Etk_Textblock_Node *new_node;
+      const char *param_start = NULL, *param_end = NULL;
+      const char *value_start = NULL, *value_end = NULL;
+      Etk_Bool equal_met = ETK_FALSE;
+      Etk_Bool open_quote = ETK_FALSE;
+      int param_len;
+      int value_len;
       
-      if (!new_node)
-      {
-         new_node = _etk_textblock_node_new(NULL, NULL, 
ETK_TEXTBLOCK_TAG_DEFAULT);
-         prev_node = new_node;
-      }
-      _etk_textblock_node_attach(new_node, node_to_close->parent, 
node_to_close);
+      node = iter->node;
       
-   }
-   else
-   {
-      /* Creates the new nodes for the opening tag */
-      if (node->tag.type == ETK_TEXTBLOCK_TAG_ROOT)
-         new_node = _etk_textblock_node_new(node, NULL, tag_type);
-      else if (node->tag.type == ETK_TEXTBLOCK_TAG_DEFAULT)
+      if (tag_type == ETK_TEXTBLOCK_TAG_P)
       {
-         if (node->text)
-            new_node = _etk_textblock_node_new(node->parent, node, tag_type);
-         else
+         Etk_Textblock_Node *n;
+         
+         new_node = NULL;
+         for (n = node; n; n = n->parent)
          {
-            _etk_textblock_node_type_set(node, tag_type);
-            new_node = node;
+            if (n->type == ETK_TEXTBLOCK_NODE_PARAGRAPH)
+            {
+               new_node = n;
+               break;
+            }
          }
-      }
-      else if (node->text)
-      {
-         new_node = _etk_textblock_node_new(node, NULL, 
ETK_TEXTBLOCK_TAG_DEFAULT);
-         new_node->text = node->text;
-         node->text = NULL;
-         new_iter_node = new_node;
-         new_node = _etk_textblock_node_new(node, new_node, tag_type);
+         if (!new_node)
+            return;
       }
       else
-         new_node = _etk_textblock_node_new(node, NULL, tag_type);
-   }
-   
-   /* Sets the text of the new node */
-   new_node->text = new_string;
-   new_node->unicode_length = ETK_MAX(0, orig_len - trunc_len);
-   
-   /* Updates the iterators */
-   for (l = tb->iters; l; l = l->next)
-   {
-      it = ETK_TEXTBLOCK_ITER(l->data);
-      if (it->node == node)
       {
-         if (it->index < trunc_len || (it->index == trunc_len && it->gravity 
== ETK_TEXTBLOCK_GRAVITY_LEFT))
-            it->node = new_iter_node;
+         if (node->tag.type == ETK_TEXTBLOCK_TAG_DEFAULT)
+         {
+            if (node->text)
+            {
+               new_node = _etk_textblock_node_split(tb, node, iter->index, 
iter->pos);
+               _etk_textblock_node_type_set(new_node, 
ETK_TEXTBLOCK_NODE_NORMAL, tag_type);
+            }
+            else
+            {
+               _etk_textblock_node_type_set(node, ETK_TEXTBLOCK_NODE_NORMAL, 
tag_type);
+               new_node = node;
+            }
+         }
          else
          {
-            it->node = new_node;
-            it->pos -= uni_trunc_len;
-            it->index -= trunc_len;
+            if (node->text)
+            {
+               Etk_Textblock_Node *parent_node;
+               
+               new_node = _etk_textblock_node_split(tb, node, iter->index, 
iter->pos);
+               
+               parent_node = _etk_textblock_node_new(node->parent, node->prev,
+                  ETK_TEXTBLOCK_NODE_NORMAL, ETK_TEXTBLOCK_TAG_DEFAULT);
+               _etk_textblock_node_copy(parent_node, node, ETK_FALSE);
+               
+               _etk_textblock_node_type_set(node, ETK_TEXTBLOCK_NODE_NORMAL, 
ETK_TEXTBLOCK_TAG_DEFAULT);
+               _etk_textblock_node_attach(node, parent_node, NULL);
+               _etk_textblock_node_type_set(new_node, 
ETK_TEXTBLOCK_NODE_NORMAL, tag_type);
+               _etk_textblock_node_attach(new_node, parent_node, node);
+            }
+            else
+               new_node = _etk_textblock_node_new(node, NULL, 
ETK_TEXTBLOCK_NODE_NORMAL, tag_type);
          }
       }
-   }
-   
-   /* Then, we parse the params of the tag */
-   if (!closing_tag)
-   {
-      const char *param_start = NULL, *param_end = NULL;
-      const char *value_start = NULL, *value_end = NULL;
-      Etk_Bool equal_met = ETK_FALSE;
-      Etk_Bool open_quote = ETK_FALSE;
-      int param_len;
-      int value_len;
       
+      /* Finally, we parse the params of the opening tag */
       for (c = name_end + 1; c <= tag_end && *c != '\0'; c++)
       {
          if (!param_start && *c != ' ' && *c != '=')
@@ -1227,16 +1264,38 @@
          }
       }
    }
+}
+
+/* Adds a new paragragh in the textblock, at the iterator's position */
+static void _etk_textblock_paragraph_add(Etk_Textblock *tb, Etk_Textblock_Iter 
*iter)
+{
+   Etk_Textblock_Node *new_paragraph;
+   
+   if (!tb || !iter || !_etk_textblock_iter_is_valid(tb, iter))
+      return;
+   
+   new_paragraph = _etk_textblock_node_new(NULL, NULL, 
ETK_TEXTBLOCK_NODE_PARAGRAPH, ETK_TEXTBLOCK_TAG_P);
+   if (!_etk_textblock_node_close(iter, ETK_TEXTBLOCK_NODE_PARAGRAPH, 
ETK_TEXTBLOCK_TAG_P, new_paragraph))
+   {
+      ETK_WARNING("Could not add a new paragraph!\n");
+      _etk_textblock_node_free(new_paragraph);
+   }
+}
 
-#ifdef TB_DEBUG
-   char *test;
-   test = malloc(tag_end - tag_start + 2);
-   strncpy(test, tag_start, tag_end - tag_start + 1);
-   test[tag_end - tag_start + 1] = '\0';
-   printf("TAG_INSERT: %s\n", test);
-   free(test);
-   etk_textblock_printf(tb);
-#endif
+/* Adds a new line in the textblock, at the iterator's position */
+static void _etk_textblock_line_add(Etk_Textblock *tb, Etk_Textblock_Iter 
*iter)
+{
+   Etk_Textblock_Node *new_line;
+   
+   if (!tb || !iter || !_etk_textblock_iter_is_valid(tb, iter))
+      return;
+   
+   new_line = _etk_textblock_node_new(NULL, NULL, ETK_TEXTBLOCK_NODE_LINE, 
ETK_TEXTBLOCK_TAG_DEFAULT);
+   if (!_etk_textblock_node_close(iter, ETK_TEXTBLOCK_NODE_LINE, 
ETK_TEXTBLOCK_TAG_DEFAULT, new_line))
+   {
+      ETK_WARNING("Could not add a new line!\n");
+      _etk_textblock_node_free(new_line);
+   }
 }
 
 /* Gets recursively the text of the node */ 
@@ -1279,6 +1338,9 @@
                etk_string_insert(start_tag, 2, " type=\"double\"");
             break;
          case ETK_TEXTBLOCK_TAG_P:
+            if (_etk_textblock_node_is_default_paragraph(node))
+               break;
+            
             start_tag = etk_string_new("<p>");
             end_tag = etk_string_new("</p>");
             
@@ -1344,15 +1406,18 @@
          default:
             break;
       }
+      
+      if (node->type == ETK_TEXTBLOCK_NODE_LINE)
+      {
+         start_tag = etk_string_new("<LINE>");
+         end_tag = etk_string_new("</LINE>");
+      }
    }
    
    /* TODO: escape code for < and > and & in markup mode */
    /* Builds the text of the node */
    etk_string_append(text, etk_string_get(start_tag));
    
-   /* TODO: add the "\n" correctly in !markup mode */
-   if (!markup && node->tag.type == ETK_TEXTBLOCK_TAG_P)
-      etk_string_append_char(text, '\n');
    if (node->text)
       etk_string_append(text, etk_string_get(node->text));
    else
@@ -1362,9 +1427,14 @@
       for (n = node->children; n; n = n->next)
          _etk_textblock_node_text_get(n, markup, text);
    }
-   /* TODO: add the "\n" correctly in !markup mode */
-   if (!markup && node->tag.type == ETK_TEXTBLOCK_TAG_P)
-      etk_string_append_char(text, '\n');
+   /* TODO: adds '\n' at the end of the lines */
+   /*if (node->type == ETK_TEXTBLOCK_NODE_END_OF_LINE)
+   {
+      if (markup)
+         etk_string_append_char(text, '\n');
+      else
+         etk_string_append_char(text, etk_string_get(node->text));
+   }*/
    
    etk_string_append(text, etk_string_get(end_tag));
    
@@ -1372,6 +1442,164 @@
    etk_object_destroy(ETK_OBJECT(end_tag));
 }
 
+/* Copies the content of the node "src" to the node "dest" */
+static void _etk_textblock_node_copy(Etk_Textblock_Node *dest, const 
Etk_Textblock_Node *src, Etk_Bool copy_text)
+{
+   if (!dest || !src)
+      return;
+   
+   if (copy_text)
+   {
+      dest->text = etk_string_set_sized(dest->text, etk_string_get(src->text), 
etk_string_length_get(src->text));
+      dest->unicode_length = src->unicode_length;
+   }
+   
+   dest->type = src->type;
+   dest->tag = src->tag;
+   if (dest->tag.type == ETK_TEXTBLOCK_TAG_FONT && dest->tag.params.font.face)
+      dest->tag.params.font.face = strdup(dest->tag.params.font.face);
+}
+
+/* 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 */
+static Etk_Textblock_Node *_etk_textblock_node_split(Etk_Textblock *tb, 
Etk_Textblock_Node *node, int index, int pos)
+{
+   const char *node_text;
+   int node_len;
+   Etk_Textblock_Node *rnode;
+   Etk_Textblock_Iter *it;
+   Evas_List *l;
+   
+   if (!node)
+      return NULL;
+   
+   node_text = etk_string_get(node->text);
+   node_len = etk_string_length_get(node->text);
+   index = ETK_CLAMP(index, 0, node_len);
+   
+   if (pos < 0 || pos > node->unicode_length)
+   {
+      int i;
+      
+      /* We calculate the unicode split position */
+      for (pos = 0, i = 0; i < index; i++)
+         pos = evas_string_char_next_get(node_text, pos, NULL);
+   }
+   
+   rnode = _etk_textblock_node_new(node->parent, node, node->type, 
node->tag.type);
+   
+   rnode->tag.params = node->tag.params;
+   if (rnode->tag.type == ETK_TEXTBLOCK_TAG_FONT && node->tag.params.font.face)
+      rnode->tag.params.font.face = strdup(node->tag.params.font.face);
+   
+   rnode->text = etk_string_new_sized(&node_text[index], node_len - index);
+   rnode->unicode_length = node->unicode_length - pos;
+   
+   /* We update the iterators */
+   if (tb)
+   {
+      for (l = tb->iters; l; l = l->next)
+      {
+         it = l->data;
+         if (it->node == node)
+         {
+            if (it->index > index || (it->index == index && it->gravity == 
ETK_TEXTBLOCK_GRAVITY_RIGHT))
+            {
+               it->node = rnode;
+               it->index -= index;
+               it->pos -= pos;
+            }
+         }
+      }
+   }
+   
+   return rnode;
+}
+
+/* Closes a parent node of the node attached to "iter" whose type is 
"node_type" and tag type is "tag_type" */
+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)
+{
+   Etk_Textblock_Node *node, *right_node;
+   
+   if (!iter || !_etk_textblock_iter_is_valid(iter->tb, iter))
+      return ETK_FALSE;
+   
+   node = iter->node;
+   
+   if (node->type == node_type && node->tag.type == tag_type)
+   {
+      right_node = _etk_textblock_node_split(iter->tb, node, iter->index, 
iter->pos);
+      _etk_textblock_node_type_set(right_node, ETK_TEXTBLOCK_NODE_NORMAL, 
ETK_TEXTBLOCK_TAG_DEFAULT);
+      
+      if (replace_node)
+      {
+         _etk_textblock_node_attach(replace_node, node->parent, node);
+         _etk_textblock_node_attach(right_node, replace_node, NULL);
+      }
+      
+      return ETK_TRUE;
+   }
+   else
+   {
+      Etk_Textblock_Node *node_to_close, *right_node, *left_node;
+      Etk_Textblock_Node *new_node, *parent, *n;
+      Evas_List *node_hierarchy;
+      
+      node_to_close = NULL;
+      node_hierarchy = NULL;
+      /* We search the node to close and we save the node hierarchy */
+      for (n = node->parent; n; n = n->parent)
+      {
+         if (n->type == node_type && n->tag.type == tag_type)
+         {
+            node_to_close = n;
+            break;
+         }
+         node_hierarchy = evas_list_prepend(node_hierarchy, n);
+      }
+      if (!node_to_close)
+      {
+         ETK_WARNING("There is no node to close");
+         evas_list_free(node_hierarchy);
+         return ETK_FALSE;
+      }
+      
+      /* Then, we attach a new node next to the node to close */
+      if (replace_node)
+      {
+         _etk_textblock_node_attach(replace_node, node_to_close->parent, 
node_to_close);
+         parent = replace_node;
+         left_node = NULL;
+      }
+      else
+      {
+         parent = node_to_close->parent;
+         left_node = node_to_close;
+      }
+      
+      /* And we create new nodes to rebuild the node hierarchy */
+      while (node_hierarchy)
+      {
+         n = node_hierarchy->data;
+         
+         new_node = _etk_textblock_node_new(parent, left_node, 
ETK_TEXTBLOCK_NODE_NORMAL, ETK_TEXTBLOCK_TAG_DEFAULT);
+         _etk_textblock_node_copy(new_node, n, ETK_FALSE);
+         _etk_textblock_node_attach(n->next, parent, new_node);
+         parent = new_node;
+         left_node = NULL;
+         
+         node_hierarchy = evas_list_remove_list(node_hierarchy, 
node_hierarchy);
+      }
+      
+      /* Finally, we split the original node, and we attach the right part to 
the new node hierarchy */ 
+      right_node = _etk_textblock_node_split(iter->tb, node, iter->index, 
iter->pos);
+      _etk_textblock_node_attach(right_node, parent, left_node);
+      
+      return ETK_TRUE;
+   }
+}
+
 /* Checks if the iterator is valid */
 static Etk_Bool _etk_textblock_iter_is_valid(Etk_Textblock *tb, 
Etk_Textblock_Iter *iter)
 {
@@ -1395,10 +1623,39 @@
          ETK_WARNING("The node of the iterator is not a leaf");
          return ETK_FALSE;
       }
+      else if (iter->node->type == ETK_TEXTBLOCK_NODE_PARAGRAPH)
+      {
+         ETK_WARNING("The node can't be attached to a paragraph node");
+         return ETK_FALSE;
+      }
+      else if (iter->node->type == ETK_TEXTBLOCK_NODE_ROOT)
+      {
+         ETK_WARNING("The node can't be attached to the root node");
+         return ETK_FALSE;
+      }
    }
    return ETK_TRUE;
 }
 
+/* Checks if the node has the default params of the paragraph tag */
+static Etk_Bool _etk_textblock_node_is_default_paragraph(Etk_Textblock_Node 
*node)
+{
+   if (!node)
+      return ETK_TRUE;
+   if (node->tag.type != ETK_TEXTBLOCK_TAG_P)
+      return ETK_FALSE;
+   
+   if (node->tag.params.p.align >= 0.0)
+      return ETK_FALSE;
+   if (node->tag.params.p.left_margin != 0)
+      return ETK_FALSE;
+   if (node->tag.params.p.right_margin != 0)
+      return ETK_FALSE;
+   
+   return ETK_TRUE;
+   
+}
+
 /* Parses an integer and return 'error_value' if it fails */
 static int _etk_textblock_int_parse(const char *int_string, int length, int 
error_value)
 {
@@ -1510,161 +1767,6 @@
  *
  **************************/
 
-/* Renders the textblock object */
-static void _etk_tb_object_render(Evas_Object *tbo, int x, int y, int w, int h)
-{
-   Etk_Textblock_Object_SD *tbo_sd;
-   Etk_Textblock *tb;
-   Etk_Geometry geometry;
-   
-   if (!tbo || !(tbo_sd = evas_object_smart_data_get(tbo)) || !(tb = 
tbo_sd->tb))
-      return;
-   
-   while (tbo_sd->text_objects)
-   {
-      evas_object_del(tbo_sd->text_objects->data);
-      tbo_sd->text_objects = evas_list_remove_list(tbo_sd->text_objects, 
tbo_sd->text_objects);
-   }
-   
-   geometry.x = x;
-   geometry.y = y;
-   geometry.w = w;
-   geometry.h = h;
-   _etk_tb_object_render_node(tbo, geometry, &tb->root, 0, 0, NULL, NULL);
-}
-
-/* Renders recursively a node of the textblock, in the textblock object */
-static void _etk_tb_object_render_node(Evas_Object *tbo, Etk_Geometry og, 
Etk_Textblock_Node *node, int x, int y, int *next_x, int *next_y)
-{
-   Etk_Textblock_Object_SD *tbo_sd;
-   const char *text;
-   int x_orig, y_orig;
-   
-   if (!tbo || !(tbo_sd = evas_object_smart_data_get(tbo)) || !node)
-      return;
-   
-   x_orig = x;
-   y_orig = y;
-   
-   if ((text = etk_string_get(node->text)))
-   {
-      int res, idx;
-      int rw, rh, lh;
-      int len;
-      Etk_Textblock_Format format;
-      
-      _etk_textblock_node_format_get(node, &format);
-      len = etk_string_length_get(node->text);
-      
-      idx = 0;
-      lh = 1;
-      while (idx < len && lh > 0 && y < og.h)
-      {
-         lh = 0;
-         res = 0;
-         for (;;)
-         {
-            res = _etk_tb_object_render_segment(tbo, &text[idx], len - idx, 
format, og.x + x, og.y + y, og.w - x, &rw, &rh);
-            if (res <= 0)
-               break;
-            
-            idx += res;
-            x += rw;
-            lh = ETK_MAX(lh, rh);
-         }
-         if (x + 20 >= og.w)
-         {
-            x = og.x;
-            y += lh;
-         }
-      }
-   }
-   else
-   {
-      Etk_Textblock_Node *n;
-      
-      for (n = node->children; n; n = n->next)
-         _etk_tb_object_render_node(tbo, og, n, x, y, &x, &y);
-   }
-   if (next_x)
-      *next_x = x;
-   if (next_y)
-      *next_y = y;
-}
-
-
-/* Renders the text in a segment starting at (sx, sy) and with a max width of 
"sw", in the textblock object.
- * The width and the height of the new segment will be stored in "rw" and "rh".
- * Returns the index of the next character to render (0 means that nothing has 
been rendered) */
-static int _etk_tb_object_render_segment(Evas_Object *tbo, const char *text, 
int len, Etk_Textblock_Format format, int sx, int sy, int sw, int *rw, int *rh)
-{
-   Evas *evas;
-   Etk_Textblock_Object_SD *tbo_sd;
-   Evas_Object *text_object;
-   char buf[ETK_TB_MAX_SEGMENT_CHARS + 1];
-   int tw, th;
-   int res;
-   
-   if (!tbo || !text || !(tbo_sd = evas_object_smart_data_get(tbo)) || !(evas 
= evas_object_evas_get(tbo)))
-      return 0;
-   
-   strncpy(buf, text, ETK_TB_MAX_SEGMENT_CHARS);
-   buf[ETK_TB_MAX_SEGMENT_CHARS] = '\0';
-   
-   text_object = evas_object_text_add(evas);
-   evas_object_text_font_set(text_object, "Vera", 10);
-   evas_object_text_text_set(text_object, buf);
-   evas_object_geometry_get(text_object, NULL, NULL, &tw, &th);
-   
-   if (tw > sw)
-   {
-      int wrap_pos;
-      int i, c;
-      char *wrapped_text;
-      
-      wrap_pos = evas_object_text_char_coords_get(text_object, sw, th / 2, 
NULL, NULL, NULL, NULL);
-      if (wrap_pos <= 0)
-         res = 0;
-      else
-      {
-         for (i = 0, c = 0; i < wrap_pos; i++)
-            c = evas_string_char_next_get(buf, c, NULL);
-         c = evas_string_char_next_get(buf, c, NULL);
-         
-         wrapped_text = malloc(c);
-         snprintf(wrapped_text, c, "%s", buf);
-         wrapped_text[c - 1] = '\0';
-         evas_object_text_text_set(text_object, wrapped_text);
-         free(wrapped_text);
-         
-         res = evas_string_char_prev_get(buf, c, NULL);
-      }
-   }
-   else
-      res = len;
-   
-   if (res > 0)
-   {
-      evas_object_move(text_object, sx, sy);
-      evas_object_color_set(text_object, 0, 0, 0, 255);
-      evas_object_show(text_object);
-      
-      tbo_sd->text_objects = evas_list_append(tbo_sd->text_objects, 
text_object);
-      
-      evas_object_geometry_get(text_object, NULL, NULL, rw, rh);
-   }
-   else
-   {
-      evas_object_del(text_object);
-      if (rw)
-         *rw = 0;
-      if (rh)
-         *rh = 0;
-   }
-   
-   return res;
-}
-
 /**************************
  *
  * Textblock object's smart object
@@ -1684,7 +1786,7 @@
    tbo_sd->tb = NULL;
    tbo_sd->wrap = ETK_TEXTBLOCK_WRAP_WORD;
    tbo_sd->cursor_object = NULL;
-   tbo_sd->text_objects = NULL;
+   tbo_sd->paragraphs = NULL;
    evas_object_smart_data_set(obj, tbo_sd);
 }
 
@@ -1692,14 +1794,20 @@
 static void _etk_tb_object_smart_del(Evas_Object *obj)
 {
    Etk_Textblock_Object_SD *tbo_sd;
+   Etk_Textblock_Object_Paragraph *p;
    
    if (!obj || !(tbo_sd = evas_object_smart_data_get(obj)))
       return;
    
-   while (tbo_sd->text_objects)
+   while (tbo_sd->paragraphs)
    {
-      evas_object_del(tbo_sd->text_objects->data);
-      tbo_sd->text_objects = evas_list_remove_list(tbo_sd->text_objects, 
tbo_sd->text_objects);
+      p = tbo_sd->paragraphs->data;
+      
+      if (p->object)
+         evas_object_del(p->object);
+      free(p);
+      
+      tbo_sd->paragraphs = evas_list_remove_list(tbo_sd->paragraphs, 
tbo_sd->paragraphs);
    }
    evas_object_del(tbo_sd->cursor_object);
    
@@ -1718,13 +1826,22 @@
 static void _etk_tb_object_smart_move(Evas_Object *obj, Evas_Coord x, 
Evas_Coord y)
 {
    Etk_Textblock_Object_SD *tbo_sd;
-   Evas_Coord w, h;
+   Evas_Coord prev_x, prev_y;
+   Evas_List *l;
+   Etk_Textblock_Object_Paragraph *p;
    
    if (!obj || !(tbo_sd = evas_object_smart_data_get(obj)))
       return;
    
-   evas_object_geometry_get(obj, NULL, NULL, &w, &h);
-   _etk_tb_object_render(obj, x, y, w, h);
+   evas_object_geometry_get(obj, &prev_x, &prev_y, NULL, NULL);
+   for (l = tbo_sd->paragraphs; 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);
+   }
 }
 
 /* Resizes the textblock object */
@@ -1737,7 +1854,7 @@
       return;
    
    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
-   _etk_tb_object_render(obj, x, y, w, h);
+   /* TODO: _etk_tb_object_smart_resize(): re-render!! */
 }
 
 /* Shows the textblock object */
===================================================================
RCS file: /cvs/e/e17/proto/etk/src/lib/etk_textblock.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -3 -r1.7 -r1.8
--- etk_textblock.h     17 Jun 2006 12:01:26 -0000      1.7
+++ etk_textblock.h     2 Jul 2006 04:01:19 -0000       1.8
@@ -4,6 +4,7 @@
 
 #include "etk_object.h"
 #include <Evas.h>
+#include <Ecore_Job.h>
 #include "etk_types.h"
 
 /**
@@ -19,50 +20,51 @@
 /** Check if the object is an Etk_Textblock */
 #define ETK_IS_TEXTBLOCK(obj)    (ETK_OBJECT_CHECK_TYPE((obj), 
ETK_TEXTBLOCK_TYPE))
 
-/** Gets the type of a textblock iterator */
-#define ETK_TEXTBLOCK_ITER_TYPE       (etk_textblock_iter_type_get())
-/** Casts the object to an Etk_Textblock_Iter */
-#define ETK_TEXTBLOCK_ITER(obj)       (ETK_OBJECT_CAST((obj), 
ETK_TEXTBLOCK_ITER_TYPE, Etk_Textblock_Iter))
-/** Check if the object is an Etk_Textblock_Iter */
-#define ETK_IS_TEXTBLOCK_ITER(obj)    (ETK_OBJECT_CHECK_TYPE((obj), 
ETK_TEXTBLOCK_ITER_TYPE))
-
-/** TODOC */
+/** @brief The different types of wrapping to apply on a textblock object */
 typedef enum Etk_Textblock_Wrap
 {
-   ETK_TEXTBLOCK_WRAP_NONE,     /**< TODOC */        
-   ETK_TEXTBLOCK_WRAP_WORD,     /**< TODOC */
-   ETK_TEXTBLOCK_WRAP_CHAR      /**< TODOC */
+   ETK_TEXTBLOCK_WRAP_NONE,     /**< The text is not wrapped */
+   ETK_TEXTBLOCK_WRAP_WORD,     /**< The text is wrapped between the words (or 
between the chars if it's not sufficient) */
+   ETK_TEXTBLOCK_WRAP_CHAR      /**< The text is wrapped between the chars */
 } Etk_Textblock_Wrap;
 
-/** TODOC */
+/** @brief The different types of node */
+typedef enum Etk_Textblock_Node_Type
+{
+   ETK_TEXTBLOCK_NODE_ROOT,        /**< The node is the root node */
+   ETK_TEXTBLOCK_NODE_PARAGRAPH,   /**< The node is a paragraph node */
+   ETK_TEXTBLOCK_NODE_LINE,        /**< The node is a line node */
+   ETK_TEXTBLOCK_NODE_NORMAL       /**< The node is a normal normal 
(containing some text or a format) */
+} Etk_Textblock_Node_Type;
+
+/** @brief The different types of tag for a node */
 typedef enum Etk_Textblock_Tag_Type
 {
-   ETK_TEXTBLOCK_TAG_ROOT,
-   ETK_TEXTBLOCK_TAG_DEFAULT,
-   ETK_TEXTBLOCK_TAG_BOLD,
-   ETK_TEXTBLOCK_TAG_ITALIC,
-   ETK_TEXTBLOCK_TAG_UNDERLINE,
-   ETK_TEXTBLOCK_TAG_P,
-   ETK_TEXTBLOCK_TAG_STYLE,
-   ETK_TEXTBLOCK_TAG_FONT
+   ETK_TEXTBLOCK_TAG_DEFAULT,      /**< The default tag: no formatting */
+   ETK_TEXTBLOCK_TAG_BOLD,         /**< The text is bold */
+   ETK_TEXTBLOCK_TAG_ITALIC,       /**< The text is italic */
+   ETK_TEXTBLOCK_TAG_UNDERLINE,    /**< The text is underlined */
+   ETK_TEXTBLOCK_TAG_P,            /**< The tag describes a paragraph */
+   ETK_TEXTBLOCK_TAG_STYLE,        /**< The tag describes the style of the 
text (normal, glow, ...) */
+   ETK_TEXTBLOCK_TAG_FONT          /**< The tag describes the font used by the 
text (face, size, ...) */
    /* ... */
 } Etk_Textblock_Tag_Type;
 
-/** TODOC */
+/** @brief The different types of style that can be applied on a text */
 typedef enum Etk_Textblock_Style_Type
 {
-   ETK_TEXTBLOCK_STYLE_NONE,
-   ETK_TEXTBLOCK_STYLE_OUTLINE,
-   ETK_TEXTBLOCK_STYLE_SHADOW
+   ETK_TEXTBLOCK_STYLE_NONE,       /**< No style is applied */
+   ETK_TEXTBLOCK_STYLE_OUTLINE,    /**< The text is oulined */
+   ETK_TEXTBLOCK_STYLE_SHADOW      /**< The text has a sharp shadow */
    /* ... */
 } Etk_Textblock_Style_Type;
 
-/** TODOC */
+/** @brief The different type of underlining for a text */
 typedef enum Etk_Textblock_Underline_Type
 {
-   ETK_TEXTBLOCK_UNDERLINE_NONE,
-   ETK_TEXTBLOCK_UNDERLINE_SINGLE,
-   ETK_TEXTBLOCK_UNDERLINE_DOUBLE
+   ETK_TEXTBLOCK_UNDERLINE_NONE,    /**< The text is not underlined */
+   ETK_TEXTBLOCK_UNDERLINE_SINGLE,  /**< The text is underlined by a single 
line */
+   ETK_TEXTBLOCK_UNDERLINE_DOUBLE   /**< The text is underlined by two lines */
 } Etk_Textblock_Underline_Type;
 
 /** TODOC */
@@ -138,6 +140,7 @@
       Etk_Textblock_Tag_Type type;
    } tag;
    
+   Etk_Textblock_Node_Type type;
    Etk_String *text;
    int unicode_length;
    
@@ -148,15 +151,12 @@
 };
 
 /**
- * @brief @object The structure of a textblock iterator
+ * @brief The structure of a textblock iterator
  * @structinfo
  */
 struct Etk_Textblock_Iter
 {
    /* private: */
-   /* Inherit from Etk_Object */
-   Etk_Object object;
-   
    Etk_Textblock *tb;
    Etk_Textblock_Node *node;
    
@@ -177,17 +177,14 @@
    
    Etk_Textblock_Node root;
    Evas_List *iters;
-   Evas_List *line_iters;
    
    Evas_List *evas_objects;
+   Ecore_Job *update_job;
 };
 
 /* Textblock's funcs */
 Etk_Type *etk_textblock_type_get();
-Etk_Type *etk_textblock_iter_type_get();
-
 Etk_Textblock *etk_textblock_new();
-Etk_Textblock_Iter *etk_textblock_iter_new(Etk_Textblock *tb);
 
 void etk_textblock_text_set(Etk_Textblock *tb, const char *text, Etk_Bool 
markup);
 Etk_String *etk_textblock_text_get(Etk_Textblock *tb, Etk_Bool markup);
@@ -199,6 +196,12 @@
 void etk_textblock_printf(Etk_Textblock *tb);
 
 /* Textblock iter's funcs */
+Etk_Textblock_Iter *etk_textblock_iter_new(Etk_Textblock *tb);
+void etk_textblock_iter_free(Etk_Textblock_Iter *iter);
+
+void etk_textblock_iter_gravity_set(Etk_Textblock_Iter *iter, 
Etk_Textblock_Gravity gravity);
+Etk_Textblock_Gravity etk_textblock_iter_gravity_get(Etk_Textblock_Iter *iter);
+
 void etk_textblock_iter_backward_start(Etk_Textblock_Iter *iter);
 void etk_textblock_iter_forward_end(Etk_Textblock_Iter *iter);
 



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

Reply via email to