Evas textblock: Implemented cursor_word_start/end
authortasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 12 Dec 2011 15:25:46 +0000 (15:25 +0000)
committertasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 12 Dec 2011 15:25:46 +0000 (15:25 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@66119 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

ChangeLog
src/lib/Evas.h
src/lib/canvas/evas_object_textblock.c
src/tests/evas_test_textblock.c

index 39e8b7e..2f90c18 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
         * Fix rounding error in map clip bounds calculation
 
+2011-12-12  Tom Hacohen (TAsn)
+
+       * Textblock: Added evas_textblock_cursor_word_start/end.
+       Those functions let you jump to the start/end of the word under the
+       cursor.
+
index 8cb49fa..a0f197b 100644 (file)
@@ -8478,6 +8478,24 @@ EAPI Eina_Bool                    evas_textblock_cursor_char_next(Evas_Textblock
 EAPI Eina_Bool                    evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
 
 /**
+ * Moves the cursor to the start of the word under the cursor.
+ *
+ * @param cur the cursor to move.
+ * @return #EINA_TRUE on success #EINA_FALSE otherwise.
+ * @since 1.2.0
+ */
+EAPI Eina_Bool                    evas_textblock_cursor_word_start(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
+ * Moves the cursor to the end of the word under the cursor.
+ *
+ * @param cur the cursor to move.
+ * @return #EINA_TRUE on success #EINA_FALSE otherwise.
+ * @since 1.2.0
+ */
+EAPI Eina_Bool                    evas_textblock_cursor_word_end(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1);
+
+/**
  * Go to the first char in the node the cursor is pointing on.
  *
  * @param cur the cursor to update.
index cfc4753..bf9d708 100644 (file)
@@ -67,6 +67,7 @@
 
 #ifdef HAVE_LINEBREAK
 #include "linebreak.h"
+#include "wordbreak.h"
 #endif
 
 /* save typing */
@@ -5734,6 +5735,111 @@ evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur)
    return EINA_FALSE;
 }
 
+#ifdef HAVE_LINEBREAK
+
+/* BREAK_AFTER: true if we can break after the current char.
+ * Both macros assume str[i] is not the terminating nul */
+#define BREAK_AFTER(i) \
+   (breaks[i] == WORDBREAK_BREAK)
+
+#else
+
+#define BREAK_AFTER(i) \
+   ((!str[i + 1]) || \
+    (_is_white(str[i]) && !_is_white(str[i + 1])) || \
+    (!_is_white(str[i]) && _is_white(str[i + 1])))
+
+#endif
+
+EAPI Eina_Bool
+evas_textblock_cursor_word_start(Evas_Textblock_Cursor *cur)
+{
+   const Eina_Unicode *text;
+   size_t i;
+#ifdef HAVE_LINEBREAK
+   char *breaks;
+#endif
+
+   if (!cur) return EINA_FALSE;
+   if (!cur->node) return EINA_FALSE;
+
+   text = eina_ustrbuf_string_get(cur->node->unicode);
+
+#ifdef HAVE_LINEBREAK
+     {
+        const char *lang = ""; /* FIXME: get lang */
+        size_t len = eina_ustrbuf_length_get(cur->node->unicode);
+        breaks = malloc(len);
+        set_wordbreaks_utf32((const utf32_t *) text, len, lang, breaks);
+     }
+#endif
+
+   i = cur->pos;
+
+   /* Skip the first one. This ensures we don't point to the nul, and also
+    * we just don't care about it anyway. */
+   if (i > 0) i--;
+
+   for ( ; i > 0 ; i--)
+     {
+        if (BREAK_AFTER(i))
+          {
+             /* Advance to the current char */
+             i++;
+             break;
+          }
+     }
+
+   cur->pos = i;
+
+#ifdef HAVE_LINEBREAK
+   free(breaks);
+#endif
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+evas_textblock_cursor_word_end(Evas_Textblock_Cursor *cur)
+{
+   const Eina_Unicode *text;
+   size_t i;
+#ifdef HAVE_LINEBREAK
+   char *breaks;
+#endif
+
+   if (!cur) return EINA_FALSE;
+   if (!cur->node) return EINA_FALSE;
+
+   text = eina_ustrbuf_string_get(cur->node->unicode);
+
+#ifdef HAVE_LINEBREAK
+     {
+        const char *lang = ""; /* FIXME: get lang */
+        size_t len = eina_ustrbuf_length_get(cur->node->unicode);
+        breaks = malloc(len);
+        set_wordbreaks_utf32((const utf32_t *) text, len, lang, breaks);
+     }
+#endif
+
+   i = cur->pos;
+
+   for ( ; text[i] ; i++)
+     {
+        if (BREAK_AFTER(i))
+          {
+             /* This is the one to break after. */
+             break;
+          }
+     }
+
+   cur->pos = i;
+
+#ifdef HAVE_LINEBREAK
+   free(breaks);
+#endif
+   return EINA_TRUE;;
+}
+
 EAPI Eina_Bool
 evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur)
 {
@@ -8828,6 +8934,7 @@ evas_object_textblock_init(Evas_Object *obj)
      {
         linebreak_init = EINA_TRUE;
         init_linebreak();
+        init_wordbreak();
      }
 #endif
 
index b8526b8..8eb9fb3 100644 (file)
@@ -568,6 +568,32 @@ START_TEST(evas_textblock_cursor)
         fail_if(evas_textblock_cursor_compare(main_cur, cur));
      }
 
+     {
+        const char *buf_wb = "a This is_a t:e.s't a";
+        evas_object_textblock_text_markup_set(tb, buf_wb);
+
+        /* Word start/end */
+        evas_textblock_cursor_pos_set(cur, 3);
+        evas_textblock_cursor_word_start(cur);
+        fail_if(2 != evas_textblock_cursor_pos_get(cur));
+        evas_textblock_cursor_word_end(cur);
+        fail_if(5 != evas_textblock_cursor_pos_get(cur));
+
+        evas_textblock_cursor_pos_set(cur, 13);
+        evas_textblock_cursor_word_end(cur);
+        fail_if(18 != evas_textblock_cursor_pos_get(cur));
+        evas_textblock_cursor_word_start(cur);
+        fail_if(12 != evas_textblock_cursor_pos_get(cur));
+        evas_textblock_cursor_word_start(cur);
+        fail_if(12 != evas_textblock_cursor_pos_get(cur));
+        evas_textblock_cursor_word_start(cur);
+        fail_if(12 != evas_textblock_cursor_pos_get(cur));
+        evas_textblock_cursor_word_end(cur);
+        fail_if(18 != evas_textblock_cursor_pos_get(cur));
+        evas_textblock_cursor_word_end(cur);
+        fail_if(18 != evas_textblock_cursor_pos_get(cur));
+     }
+
    END_TB_TEST();
 }
 END_TEST