diff --git a/legacy/evas/ChangeLog b/legacy/evas/ChangeLog index 39e8b7e350..2f90c18ab5 100644 --- a/legacy/evas/ChangeLog +++ b/legacy/evas/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/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index 8cb49faafc..a0f197b61d 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -8477,6 +8477,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. * diff --git a/legacy/evas/src/lib/canvas/evas_object_textblock.c b/legacy/evas/src/lib/canvas/evas_object_textblock.c index cfc4753017..bf9d708639 100644 --- a/legacy/evas/src/lib/canvas/evas_object_textblock.c +++ b/legacy/evas/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/legacy/evas/src/tests/evas_test_textblock.c b/legacy/evas/src/tests/evas_test_textblock.c index b8526b85fd..8eb9fb3ceb 100644 --- a/legacy/evas/src/tests/evas_test_textblock.c +++ b/legacy/evas/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