From d4fa25a126f41c3d5d4a472f0af5e38c92fca034 Mon Sep 17 00:00:00 2001 From: tasn Date: Mon, 12 Dec 2011 15:25:46 +0000 Subject: [PATCH] Evas textblock: Implemented cursor_word_start/end git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@66119 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- ChangeLog | 6 ++ src/lib/Evas.h | 18 ++++++ src/lib/canvas/evas_object_textblock.c | 107 +++++++++++++++++++++++++++++++++ src/tests/evas_test_textblock.c | 26 ++++++++ 4 files changed, 157 insertions(+) diff --git a/ChangeLog b/ChangeLog index 39e8b7e..2f90c18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -544,3 +544,9 @@ * 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. + diff --git a/src/lib/Evas.h b/src/lib/Evas.h index 8cb49fa..a0f197b 100644 --- a/src/lib/Evas.h +++ b/src/lib/Evas.h @@ -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. diff --git a/src/lib/canvas/evas_object_textblock.c b/src/lib/canvas/evas_object_textblock.c index cfc4753..bf9d708 100644 --- a/src/lib/canvas/evas_object_textblock.c +++ b/src/lib/canvas/evas_object_textblock.c @@ -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 diff --git a/src/tests/evas_test_textblock.c b/src/tests/evas_test_textblock.c index b8526b8..8eb9fb3 100644 --- a/src/tests/evas_test_textblock.c +++ b/src/tests/evas_test_textblock.c @@ -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 -- 2.7.4