2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 * @brief Implementation of Utility Functions
25 /* enabling beta API support for Eo parts*/
26 #define EFL_BETA_API_SUPPORT
29 #include <Elementary.h>
33 /* internal elm_widget api for listening EDJE parts */
35 #define ELM_INTERNAL_API_ARGESFSDFEFC
36 #include <elm_widget.h>
38 #include "eail_utils.h"
39 #include "eail_factory.h"
40 #include "eail_dynamic_content.h"
41 #include "eail_priv.h"
44 * @param string base string to get substring from
45 * @param start_offset beginning offset
46 * @param end_offset end offset
48 * @returns newly allocated substring
51 eail_get_substring(const gchar *string,
55 gchar *substring = NULL;
59 if (!string) return NULL;
61 len = g_utf8_strlen(string, -1);
63 if ((start_offset < 0) ||
64 (start_offset > len - 1) ||
67 else if (end_offset == -1 ||
68 end_offset >= len - 1)
69 sub_len = len - start_offset + 1;
71 sub_len = end_offset - start_offset;
73 substring = g_malloc0(sub_len + 1);
75 return g_utf8_strncpy(substring, &string[start_offset], sub_len);
79 * @param widget Evas_Object instance for getting state set
80 * @param state_set current state set taken from object's parent
82 * @returns AtkStateSet representing the given Evas_Object
85 eail_evas_obj_ref_state_set(Evas_Object *widget, AtkStateSet *state_set)
88 atk_state_set_add_state(state_set, ATK_STATE_DEFUNCT);
92 if (!elm_object_disabled_get(widget)) {
93 atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE);
94 atk_state_set_add_state(state_set, ATK_STATE_ENABLED);
97 if (evas_object_visible_get(widget)) {
98 int x, y, width, height;
99 int vp_x, vp_y, vp_width, vp_height;
101 atk_state_set_add_state(state_set, ATK_STATE_VISIBLE);
103 evas_object_geometry_get(widget, &x, &y, &width, &height);
104 evas_output_viewport_get(evas_object_evas_get(widget),
105 &vp_x, &vp_y, &vp_width, &vp_height);
107 if ((x + width) >= vp_x && (y + height) >= vp_y &&
108 (vp_x + vp_width) >= x && (vp_y + vp_height) >= y) {
109 atk_state_set_add_state(state_set, ATK_STATE_SHOWING);
113 if (elm_object_focus_allow_get(widget)) {
114 atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE);
116 if (elm_object_focus_get(widget)) {
117 atk_state_set_add_state(state_set, ATK_STATE_FOCUSED);
125 * @param widget Evas_Object instance
126 * @return TRUE if grabbing focus was successfull, FALSE otherwise
129 eail_evas_obj_grab_focus(Evas_Object *widget)
131 Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
133 if (!widget || !elm_object_focus_allow_get(widget)) {
137 ecore_evas_activate(ee);
138 elm_object_focus_set(widget, EINA_TRUE);
144 * @param widget Evas_Object instance to press on
145 * @param x x coordinate
146 * @param y y coordinate
149 eail_mouse_press_on_coords(Evas_Object *widget, int x, int y)
152 evas = evas_object_evas_get(widget);
154 evas_event_feed_mouse_move(evas, x, y, 0, NULL);
155 evas_event_feed_mouse_down(evas, 1, EVAS_BUTTON_NONE, 0, NULL);
159 * @param widget Evas_Object instance to press on
160 * @param x x coordinate
161 * @param y y coordinate
164 eail_mouse_release_on_coords(Evas_Object *widget, int x, int y)
167 evas = evas_object_evas_get(widget);
169 evas_event_feed_mouse_move(evas, x, y, 0, NULL);
170 evas_event_feed_mouse_up(evas, 1, EVAS_BUTTON_NONE, 0, NULL);
174 * @param widget Evas_Object instance to click on
175 * @param x x coordinate
176 * @param y y coordinate
179 eail_mouse_click_on_coords(Evas_Object *widget, int x, int y)
182 evas = evas_object_evas_get(widget);
184 evas_event_feed_mouse_move(evas, x, y, 0, NULL);
185 evas_event_feed_mouse_down(evas, 1, EVAS_BUTTON_NONE, 0, NULL);
186 evas_event_feed_mouse_up(evas, 1, EVAS_BUTTON_NONE, 0, NULL);
190 * @param widget Evas_Object instance to get values for
191 * @param [out] x x coordinate
192 * @param [out] y Y coordinate
195 eail_get_coords_widget_center(Evas_Object *widget, int *x, int *y)
198 evas_object_geometry_get(widget, x, y, &w, &h);
205 * @param item Elm_Object_Item* instance
207 * @returns Eina_List * representing the list of raw Evas_Object*
208 * (not every returned Evas_Object is a widget - widget-only content
209 * is returned by eail_get_edje_parts_for_item function)
212 eail_get_raw_evas_obj_list_from_item(Elm_Object_Item *item)
214 Evas_Object *edje = NULL;
219 DBG("Edje object for item not found. Returning empty list");\
223 return evas_object_smart_members_get(edje);
227 * @param item Elm_Object_Item* instance
229 * @returns Evas_Object* representing the edje object related to item
232 eail_get_edje_obj_from_item(Elm_Object_Item *item)
234 Evas_Object *edje = NULL;
238 DBG("Edje object for item not found.");
245 * The returned list has to be freed when no longer needed but DO NOT
246 * FREE CONTENT STRINGS.
248 * @param item Elm_Object_Item * to get strings from
249 * @returns Eina_List representing the list of string that represent text
253 eail_item_get_content_strings(Elm_Object_Item *item)
255 Eina_List *strings_list = NULL;
256 Eina_List *edje_parts = NULL;
257 Evas_Object *part = NULL;
261 edje_parts = eail_get_raw_evas_obj_list_from_item(item);
262 EINA_LIST_FOREACH(edje_parts, l, part)
264 const gchar *type_name = evas_object_type_get(part);
266 if (0 == strcmp(type_name, "text"))
268 const gchar *text = evas_object_text_text_get(part);
271 strings_list = eina_list_append(strings_list, text);
279 * It does filtering inside and returs only parts that can be used later in
280 * eail factory (only widgets will be returned).
282 * @param item Elm_Object_Item instance to get objects from
284 * @returns an Eina_List filled with Evas_Object* objects representing content
288 eail_get_edje_parts_for_item(Elm_Object_Item *item)
290 Eina_List *edje_parts = NULL;
291 Eina_List *usable_parts = NULL;
294 edje_parts = eail_get_raw_evas_obj_list_from_item(item);
295 for (i = 0; i < eina_list_count(edje_parts); ++i)
297 Evas_Object *obj = eina_list_nth(edje_parts, i);
299 /* adding only parts that can be used by eail_factory later */
300 if (elm_object_widget_check(obj))
301 usable_parts = eina_list_append(usable_parts, obj);
304 eina_list_free(edje_parts);
311 * @param widget Evas_Object instance
312 * @param type type of scroll action
314 * @returns TRUE if scroll action was successful, FALSE otherwise
317 eail_handle_scroll(Evas_Object *widget,
318 enum EAIL_SCROLL_TYPE type)
322 elm_scroller_region_get(widget, &x, &y, &w, &h);
324 if (EAIL_SCROLL_TYPE_UP == type)
326 else if (EAIL_SCROLL_TYPE_DOWN == type)
328 else if (EAIL_SCROLL_TYPE_RIGHT == type)
330 else if (EAIL_SCROLL_TYPE_LEFT == type)
333 elm_scroller_region_bring_in(widget, x, y, w, h);
340 * @param widget Evas_Object* instance
341 * @param data additional action data
342 * @returns TRUE if scroll action was successful, FALSE otherwise
345 eail_action_scroll_up(Evas_Object *widget,
348 return eail_handle_scroll(widget, EAIL_SCROLL_TYPE_UP);
353 * @param widget Evas_Object* instance
354 * @param data additional action data
356 * @returns TRUE if scroll action was successful, FALSE otherwise
359 eail_action_scroll_down(Evas_Object *widget,
362 return eail_handle_scroll(widget, EAIL_SCROLL_TYPE_DOWN);
367 * @param widget Evas_Object* instance
368 * @param data additional action data
370 * @returns TRUE if scroll action was successful, FALSE otherwise
373 eail_action_scroll_left(Evas_Object *widget,
376 return eail_handle_scroll(widget, EAIL_SCROLL_TYPE_LEFT);
381 * @param widget Evas_Object* instance
382 * @param data additional action data
384 * @returns TRUE if scroll action was successful, FALSE otherwise
387 eail_action_scroll_right(Evas_Object *widget,
390 return eail_handle_scroll(widget, EAIL_SCROLL_TYPE_RIGHT);
394 * @param atk_obj AtkObject instance that emits the signal
395 * @param signal_name name of signal
396 * @param object_type GType of object
399 eail_emit_atk_signal(AtkObject *atk_obj, const gchar *signal_name,
402 guint signal = g_signal_lookup (signal_name,object_type);
405 ERR("No signal with name %s was found", signal_name);
409 DBG("Raising %s signal", signal_name);
410 g_signal_emit (atk_obj, signal, 0);
414 * @param added boolean used for marking if child is added. TRUE if child was
415 * added, FALSE when child was removed
416 * @param atk_obj AtkObject instance that emits the signal
417 * @param child_number index number of changed child
420 eail_emit_children_changed(gboolean added, AtkObject *atk_obj, gint child_number)
423 DBG("Emitting child-changed for index %d. ADDED: %d", child_number, added);
426 g_signal_emit_by_name
427 (atk_obj, "children_changed::add", child_number, NULL, NULL);
429 g_signal_emit_by_name
430 (atk_obj, "children_changed::remove", child_number, NULL, NULL);
435 * @param added boolean used for marking if child is added. TRUE if child was
436 * added, FALSE when child was removed
437 * @param atk_obj an AtkObject that emits the signal
438 * @param changed_obj pointer to object that has been added/removed
441 eail_emit_children_changed_obj(gboolean added,
443 AtkObject *changed_obj)
446 DBG("Emitting child-changed for obj. ADDED: %d", added);
449 g_signal_emit_by_name
450 (atk_obj, "children_changed::add", NULL, changed_obj, NULL);
452 g_signal_emit_by_name
453 (atk_obj, "children_changed::remove", NULL, changed_obj, NULL);
457 * @brief Handles 'selected' state changes for item
459 * @param item Elm_Object instance
460 * @param selected value of 'selected' state
461 * @param parent AtkObject that holds item inside
462 * @param role role of item
465 _eail_handle_selected_for_item(Elm_Object_Item *item,
470 AtkObject *atk_item_obj = NULL;
471 if (!item && !parent)
473 ERR("Wrong parameters passed. Ignoring event");
477 atk_item_obj = eail_factory_get_item_atk_obj(item, role, parent);
480 DBG("Couldn't find factory obj for item. Ignoring 'selected' event");
484 atk_object_notify_state_change(atk_item_obj, ATK_STATE_SELECTED, selected);
485 g_signal_emit_by_name (parent, "selection_changed");
489 * @brief Function that calls apropriate handling for selected event
491 * @param data passed to callback
492 * @param obj Evas_Object that raised event
493 * @param event_info additional event info
494 * @param selected selected state
497 _eail_list_item_do_handle_selected_event(void *data,
502 Elm_Object_Item *obj_item = (Elm_Object_Item*)event_info;
505 DBG("obj_item not found in event_info. Ignoring event..");
509 eail_notify_child_focus_changes();
510 _eail_handle_selected_for_item
511 (obj_item, selected, ATK_OBJECT(data), ATK_ROLE_LIST_ITEM);
516 * @param data passed to callback
517 * @param obj Evas_Object that raised event
518 * @param event_info additional event info
521 eail_list_item_handle_selected_event(void *data,
525 _eail_list_item_do_handle_selected_event(data, obj, event_info, TRUE);
530 * @param data passed to callback
531 * @param obj Evas_Object that raised event
532 * @param event_info additional event info
535 eail_list_item_handle_unselected_event(void *data,
539 _eail_list_item_do_handle_selected_event(data, obj, event_info, FALSE);
543 * @brief Notifies objects with given role about possible hierarchy changes
545 * @param data an AtkRole
547 * @returns always FALSE
550 _notifiy_content_holders_by_type(gpointer data)
552 Eina_List *objs = NULL, *l = NULL;
553 AtkObject *atk_obj = NULL;
554 AtkRole role = ATK_ROLE_INVALID;
556 role = (AtkRole)data;
558 if (ATK_ROLE_APPLICATION == role)
560 atk_obj = atk_get_root();
561 if (atk_obj && EAIL_IS_DYNAMIC_CONTENT(atk_obj))
562 eail_dynamic_content_update_hierarchy(EAIL_DYNAMIC_CONTENT(atk_obj));
568 objs = eail_factory_find_objects_with_role(role);
569 EINA_LIST_FOREACH(objs, l, atk_obj)
571 if (EAIL_IS_DYNAMIC_CONTENT(atk_obj))
573 eail_dynamic_content_update_hierarchy
574 (EAIL_DYNAMIC_CONTENT(atk_obj));
577 eina_list_free(objs);
584 * @brief Sends notification about possible hierarchy changes to objects
585 * with dynamic content interface
587 * @param delay value in miliseconds, objects will be notified after this
591 _eail_notify_focus_listeners_delayed(guint delay)
594 (delay, _notifiy_content_holders_by_type, (gpointer)ATK_ROLE_APPLICATION);
596 (delay, _notifiy_content_holders_by_type, (gpointer)ATK_ROLE_WINDOW);
598 (delay, _notifiy_content_holders_by_type, (gpointer)ATK_ROLE_FILLER);
602 eail_notify_child_focus_changes(void)
604 _eail_notify_focus_listeners_delayed(0);
605 /* sending delayed notifications to objects after hierarchy has
606 * been fully established*/
607 _eail_notify_focus_listeners_delayed(1600);
611 * @brief Returns the position that is obtained by adding count to the
614 * Count may be positive or negative.
616 * @param textblock Evas textblock
617 * @param offset character offset
618 * @param count number of characters to move from offset
619 * @returns integer representing the new position
622 _eail_move_chars(const Evas_Object *textblock,
626 Evas_Textblock_Cursor *cur;
630 dir = count > 0 ? 1 : -1;
631 cur = evas_object_textblock_cursor_new(textblock);
632 evas_textblock_cursor_pos_set(cur, offset);
636 res = dir > 0 ? evas_textblock_cursor_char_next(cur) :
637 evas_textblock_cursor_char_prev(cur);
643 offset = evas_textblock_cursor_pos_get(cur);
644 evas_textblock_cursor_free(cur);
650 * @brief Gets the utf8 character at offset
652 * @param textblock Evas textblock
653 * @param offset character offset
654 * @returns char representing the utf8 character
657 _eail_get_unichar_at_offset(const Evas_Object *textblock,
660 Evas_Textblock_Cursor *cur;
664 cur = evas_object_textblock_cursor_new(textblock);
665 evas_textblock_cursor_pos_set(cur, offset);
666 s = evas_textblock_cursor_content_get(cur);
667 c = g_utf8_get_char(s);
669 evas_textblock_cursor_free(cur);
676 * @brief Checks whether the character at offset in textblock is a word's start
678 * @param textblock Evas textblock
679 * @param offset character offset
680 * @returns TRUE on success, FALSE otherwise
683 _eail_is_word_start(const Evas_Object *textblock,
686 /* first character in a word */
687 Evas_Textblock_Cursor *cur = NULL;
688 cur = evas_object_textblock_cursor_new(textblock);
689 evas_textblock_cursor_pos_set(cur, offset);
690 evas_textblock_cursor_word_start(cur);
691 gint pos = evas_textblock_cursor_pos_get(cur);
692 evas_textblock_cursor_free(cur);
694 return pos == offset;
698 * @brief Checks whether the character at offset in textblock is a word's end
700 * @param textblock Evas textblock
701 * @param offset character offset
702 * @return TRUE on success, FALSE otherwise
705 _eail_is_word_end(const Evas_Object *textblock,
708 /* is first non-word char after a word */
709 Evas_Textblock_Cursor *cur = NULL;
710 cur = evas_object_textblock_cursor_new(textblock);
711 evas_textblock_cursor_pos_set(cur, offset - 2);
712 evas_textblock_cursor_word_end(cur);
713 gint pos = evas_textblock_cursor_pos_get(cur);
714 evas_textblock_cursor_free(cur);
716 return (pos + 1 == offset);
720 * @brief Checks whether the character at offset in textblock is inside a word
722 * @param textblock Evas textblock
723 * @param offset character offset
724 * @returns TRUE on success, FALSE otherwise
727 _eail_is_inside_word(const Evas_Object *textblock,
730 Evas_Textblock_Cursor *cur = NULL;
731 cur = evas_object_textblock_cursor_new(textblock);
732 evas_textblock_cursor_pos_set(cur, offset);
733 evas_textblock_cursor_word_start(cur);
734 gint pos_start = evas_textblock_cursor_pos_get(cur);
735 evas_textblock_cursor_char_prev(cur);
736 evas_textblock_cursor_word_end(cur);
737 gint pos_end = evas_textblock_cursor_pos_get(cur);
738 evas_textblock_cursor_free(cur);
740 return (pos_start <= offset && pos_end >= offset);
744 * @brief Gets the texblock length
746 * @param textblock Evas textblock
747 * @returns integer representing the textblock length
750 _eail_get_len(const Evas_Object *textblock)
752 Evas_Textblock_Cursor *cur;
755 cur = evas_object_textblock_cursor_new(textblock);
756 while (evas_textblock_cursor_char_next(cur))
759 evas_textblock_cursor_free(cur);
765 * @brief Returns the position that is count words from the given offset
767 * Count may be positive or negative. If count is positive, the returned
768 * position will be a word end, otherwise it will be a word start.
770 * @param textblock Evas textblock
771 * @param offset a character offset
772 * @param count the number of words to move from offset
773 * @returns integer representing the new position
776 _eail_move_words(const Evas_Object *textblock,
780 gint len = _eail_get_len(textblock);
782 while (count > 0 && offset < len)
786 while (offset < len && !_eail_is_word_end(textblock, offset));
790 while (count < 0 && offset > 0)
794 while (offset > 0 && !_eail_is_word_start(textblock, offset));
803 * @brief Checks whether the character is sentence break
806 * @returns TRUE on success, FALSE otherwise
809 _eail_is_sentence_break(gunichar c)
811 if (c == '.' || c == '?' || c == '!') return TRUE;
817 * @brief Checks whether the character at offset in textblock is a sentence's start
819 * @param textblock Evas textblock
820 * @param offset character offset
821 * @returns TRUE on success, FALSE otherwise
824 _eail_is_sentence_start(const Evas_Object *textblock,
828 gint len = _eail_get_len(textblock);
830 if (offset > len -1 || offset < 0) return FALSE;
832 if (0 == offset) return TRUE;
834 c = _eail_get_unichar_at_offset(textblock, offset - 1);
835 if (_eail_is_sentence_break(c)) return TRUE;
841 * @brief Checks whether the character at offset in textblock is a sentence's end
843 * @param textblock Evas textblock
844 * @param offset character offset
845 * @return TRUE on success, FALSE otherwise
848 _eail_is_sentence_end(const Evas_Object *textblock,
852 gint len = _eail_get_len(textblock);
854 if (offset > len -1 || offset < 0) return FALSE;
856 if (offset == len -1) return TRUE;
858 c = _eail_get_unichar_at_offset(textblock, offset);
859 if (_eail_is_sentence_break(c)) return TRUE;
865 * @brief Checks whether the character at offset in textblock is inside a senetence
867 * @param textblock Evas textblock
868 * @param offset character offset
869 * @returns TRUE on success, FALSE otherwise
872 _eail_is_inside_sentence(const Evas_Object *textblock,
876 gint len = _eail_get_len(textblock);
878 if ((offset > len -1 || offset < 0)) return FALSE;
880 c = _eail_get_unichar_at_offset(textblock, offset);
882 if (!_eail_is_sentence_break(c)) return TRUE;
888 * @brief Returns the position that is count sentences from the given offset
890 * Count may be positive or negative. If count is positive, the returned
891 * position will be a sentence end, otherwise it will be a sentence start.
893 * @param textblock Evas textblock
894 * @param offset a character offset
895 * @param count the number of words to move from offset
896 * @returns integer representing the new position
899 _eail_move_sentences(const Evas_Object *textblock,
903 gint len = _eail_get_len(textblock);
905 while (count > 0 && offset < len)
909 while (offset < len && !_eail_is_sentence_end(textblock, offset));
913 while (count < 0 && offset > 0)
917 while (offset > 0 && !_eail_is_sentence_start(textblock, offset));
926 * @brief Checks whether the character at offset in textblock is a line's start
928 * @param textblock Evas textblock
929 * @param offset character offset
930 * @returns TRUE on success, FALSE otherwise
933 _eail_is_line_start(const Evas_Object *textblock,
936 Evas_Textblock_Cursor *cur = NULL;
937 cur = evas_object_textblock_cursor_new(textblock);
938 evas_textblock_cursor_pos_set(cur, offset);
939 evas_textblock_cursor_line_char_first(cur);
940 gint pos = evas_textblock_cursor_pos_get(cur);
941 evas_textblock_cursor_free(cur);
943 return pos == offset;
947 * @brief Checks whether the character at offset in textblock is a line's end
949 * @param textblock Evas textblock
950 * @param offset character offset
951 * @return TRUE on success, FALSE otherwise
954 _eail_is_line_end(const Evas_Object *textblock,
957 /* is first non-word char after a word */
958 Evas_Textblock_Cursor *cur = NULL;
959 cur = evas_object_textblock_cursor_new(textblock);
960 evas_textblock_cursor_pos_set(cur, offset);
961 evas_textblock_cursor_line_char_last(cur);
962 gint pos = evas_textblock_cursor_pos_get(cur);
963 evas_textblock_cursor_free(cur);
965 return (pos == offset);
969 * @brief Checks whether the character at offset in textblock is inside a line
971 * @param textblock Evas textblock
972 * @param offset character offset
973 * @returns TRUE on success, FALSE otherwise
976 _eail_is_inside_line(const Evas_Object *textblock,
979 Evas_Textblock_Cursor *cur = NULL;
980 cur = evas_object_textblock_cursor_new(textblock);
981 evas_textblock_cursor_pos_set(cur, offset);
982 evas_textblock_cursor_line_char_last(cur);
983 gint pos_end = evas_textblock_cursor_pos_get(cur);
984 evas_textblock_cursor_free(cur);
985 return pos_end != offset;
989 * @brief Returns the position that is count lines from the given offset
991 * Count may be positive or negative. If count is positive, the returned
992 * position will be a line end, otherwise it will be a line start.
994 * @param textblock Evas textblock
995 * @param offset a character offset
996 * @param count the number of words to move from offset
997 * @returns integer representing the new position
1000 _eail_move_lines(const Evas_Object *textblock,
1004 gint len = _eail_get_len(textblock);
1006 while (count > 0 && offset < len)
1010 while (offset < len && !_eail_is_line_end(textblock, offset));
1014 while (count < 0 && offset > 0)
1018 while (offset > 0 && !_eail_is_line_start(textblock, offset));
1027 * @brief Gets a slice of the text from textblock after offset
1029 * Use g_free() to free the returned string.
1031 * @param textblock Evas textblock
1032 * @param offset character offset
1033 * @param boundary_type AtkTextBoundary instance
1034 * @param [out] start_offset start position of the returned text
1035 * @param [out] end_offset end position of the returned text
1036 * @returns newly allocated string containg a slice of text from textblock
1039 eail_get_text_after(const Evas_Object *textblock,
1041 AtkTextBoundary boundary_type,
1049 text = evas_textblock_text_markup_to_utf8(
1050 textblock, evas_object_textblock_text_markup_get(textblock));
1055 return g_strdup("");
1060 len = _eail_get_len(textblock);
1062 switch (boundary_type)
1064 case ATK_TEXT_BOUNDARY_CHAR:
1065 start = _eail_move_chars(textblock, start, 1);
1067 end = _eail_move_chars(textblock, end, 1);
1070 case ATK_TEXT_BOUNDARY_WORD_START:
1071 if (_eail_is_inside_word(textblock, end))
1072 end = _eail_move_words(textblock, end, 1);
1073 while (!_eail_is_word_start(textblock, end) && end < len)
1074 end = _eail_move_chars(textblock, end, 1);
1078 end = _eail_move_words(textblock, end, 1);
1079 while (!_eail_is_word_start(textblock, end) && end < len)
1080 end = _eail_move_chars(textblock, end, 1);
1084 case ATK_TEXT_BOUNDARY_WORD_END:
1085 end = _eail_move_words(textblock, end, 1);
1088 end = _eail_move_words(textblock, end, 1);
1091 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1092 if (_eail_is_inside_sentence(textblock, end))
1093 end = _eail_move_sentences(textblock, end, 1);
1094 while (!_eail_is_sentence_start(textblock, end) && end < len)
1095 end = _eail_move_chars(textblock, end, 1);
1099 end = _eail_move_sentences(textblock, end, 1);
1100 while (!_eail_is_sentence_start(textblock, end) && end < len)
1101 end = _eail_move_chars(textblock, end, 1);
1105 case ATK_TEXT_BOUNDARY_SENTENCE_END:
1106 end = _eail_move_sentences(textblock, end, 1);
1109 end = _eail_move_sentences(textblock, end, 1);
1112 case ATK_TEXT_BOUNDARY_LINE_START:
1113 if (_eail_is_inside_line(textblock, end))
1114 end = _eail_move_lines(textblock, end, 1);
1115 while (!_eail_is_line_start(textblock, end) && end < len)
1116 end = _eail_move_chars(textblock, end, 1);
1120 end = _eail_move_lines(textblock, end, 1);
1121 while (!_eail_is_line_start(textblock, end) && end < len)
1122 end = _eail_move_chars(textblock, end, 1);
1126 case ATK_TEXT_BOUNDARY_LINE_END:
1127 end = _eail_move_lines(textblock, end, 1);
1130 end = _eail_move_lines(textblock, end, 1);
1134 *start_offset = start;
1136 g_assert(start <= end);
1138 return g_utf8_substring(text, start, end);
1142 * @brief Gets a slice of the text from textblock at offset
1144 * Use g_free() to free the returned string.
1146 * @param textblock Evas textblock
1147 * @param offset character offset
1148 * @param boundary_type AtkTextBoundary instance
1149 * @param [out] start_offset start position of the returned text
1150 * @param [out] end_offset end position of the return text
1151 * @returns newly allocated string containing a slice of text from textblock
1154 eail_get_text_at(const Evas_Object *textblock,
1156 AtkTextBoundary boundary_type,
1164 text = evas_textblock_text_markup_to_utf8(
1165 textblock, evas_object_textblock_text_markup_get(textblock));
1170 return g_strdup("");
1175 len = _eail_get_len(textblock);
1177 switch (boundary_type)
1179 case ATK_TEXT_BOUNDARY_CHAR:
1180 end = _eail_move_chars(textblock, end, 1);
1183 case ATK_TEXT_BOUNDARY_WORD_START:
1184 if (!_eail_is_word_start(textblock, start))
1185 start = _eail_move_words(textblock, start, -1);
1186 if (_eail_is_inside_word(textblock, end))
1187 end = _eail_move_words(textblock, end, 1);
1188 while (!_eail_is_word_start(textblock, end) && end < len)
1189 end = _eail_move_chars(textblock, end, 1);
1192 case ATK_TEXT_BOUNDARY_WORD_END:
1193 if (_eail_is_inside_word(textblock, start) &&
1194 !_eail_is_word_start(textblock, start))
1195 start = _eail_move_words(textblock, start, -1);
1196 while (!_eail_is_word_end(textblock, start) && start > 0)
1197 start = _eail_move_chars(textblock, start, -1);
1198 end = _eail_move_words(textblock, end, 1);
1201 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1202 if (!_eail_is_sentence_start(textblock, start))
1203 start = _eail_move_sentences(textblock, start, -1);
1204 if (_eail_is_inside_sentence(textblock, end))
1205 end = _eail_move_sentences(textblock, end, 1);
1206 while (!_eail_is_sentence_start(textblock, end) && end < len)
1207 end = _eail_move_chars(textblock, end, 1);
1210 case ATK_TEXT_BOUNDARY_SENTENCE_END:
1211 if (_eail_is_inside_sentence(textblock, start) &&
1212 !_eail_is_sentence_start(textblock, start))
1213 start = _eail_move_sentences(textblock, start, -1);
1214 while (!_eail_is_sentence_end(textblock, start) && start > 0)
1215 start = _eail_move_chars(textblock, start, -1);
1216 end = _eail_move_sentences(textblock, end, 1);
1219 case ATK_TEXT_BOUNDARY_LINE_START:
1220 if (!_eail_is_line_start(textblock, start))
1221 start = _eail_move_lines(textblock, start, -1);
1222 if (_eail_is_inside_line(textblock, end))
1223 end = _eail_move_lines(textblock, end, 1);
1224 while (!_eail_is_line_start(textblock, end) && end < len)
1225 end = _eail_move_chars(textblock, end, 1);
1228 case ATK_TEXT_BOUNDARY_LINE_END:
1229 if (_eail_is_inside_line(textblock, start) &&
1230 !_eail_is_line_start(textblock, start))
1231 start = _eail_move_lines(textblock, start, -1);
1232 while (!_eail_is_line_end(textblock, start) && start > 0)
1233 start = _eail_move_chars(textblock, start, -1);
1234 end = _eail_move_lines(textblock, end, 1);
1238 *start_offset = start;
1240 g_assert(start <= end);
1242 return g_utf8_substring(text, start, end);
1246 * @brief Gets a slice of the text from textblock before offset
1248 * Use g_free() to free the returned string.
1250 * @param textblock Evas textblock
1251 * @param offset character offset
1252 * @param boundary_type AtkTextBoundary instance
1253 * @param [out] start_offset start position of the returned text
1254 * @param [out] end_offset end position of the returned text
1255 * @returns newly allocated string containing a slice of text from textblock
1258 eail_get_text_before(const Evas_Object *textblock,
1260 AtkTextBoundary boundary_type,
1267 text = evas_textblock_text_markup_to_utf8(
1268 textblock, evas_object_textblock_text_markup_get(textblock));
1273 return g_strdup("");
1279 switch (boundary_type)
1281 case ATK_TEXT_BOUNDARY_CHAR:
1282 start = _eail_move_chars(textblock, start, -1);
1285 case ATK_TEXT_BOUNDARY_WORD_START:
1286 if (!_eail_is_word_start(textblock, start))
1287 start = _eail_move_words(textblock, start, -1);
1289 start = _eail_move_words(textblock, start, -1);
1292 case ATK_TEXT_BOUNDARY_WORD_END:
1293 if (_eail_is_inside_word(textblock, start) &&
1294 !_eail_is_word_start(textblock, start))
1295 start = _eail_move_words(textblock, start, -1);
1296 while (!_eail_is_word_end(textblock, start) && start > 0)
1297 start = _eail_move_chars(textblock, start, -1);
1299 start = _eail_move_words(textblock, start, -1);
1300 while (!_eail_is_word_end(textblock, start) && start > 0)
1301 start = _eail_move_chars(textblock, start, -1);
1304 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1305 if (!_eail_is_sentence_start(textblock, start))
1306 start = _eail_move_sentences(textblock, start, -1);
1308 start = _eail_move_sentences(textblock, start, -1);
1311 case ATK_TEXT_BOUNDARY_SENTENCE_END:
1312 if (_eail_is_inside_sentence(textblock, start) &&
1313 !_eail_is_sentence_start(textblock, start))
1314 start = _eail_move_sentences(textblock, start, -1);
1315 while (!_eail_is_sentence_end(textblock, start) && start > 0)
1316 start = _eail_move_chars(textblock, start, -1);
1318 start = _eail_move_sentences(textblock, start, -1);
1319 while (!_eail_is_sentence_end(textblock, start) && start > 0)
1320 start = _eail_move_chars(textblock, start, -1);
1323 case ATK_TEXT_BOUNDARY_LINE_START:
1324 if (!_eail_is_line_start(textblock, start))
1325 start = _eail_move_lines(textblock, start, -1);
1327 start = _eail_move_lines(textblock, start, -1);
1330 case ATK_TEXT_BOUNDARY_LINE_END:
1331 if (_eail_is_inside_line(textblock, start) &&
1332 !_eail_is_line_start(textblock, start))
1333 start = _eail_move_lines(textblock, start, -1);
1334 while (!_eail_is_line_end(textblock, start) && start > 0)
1335 start = _eail_move_chars(textblock, start, -1);
1337 start = _eail_move_lines(textblock, start, -1);
1338 while (!_eail_is_line_end(textblock, start) && start > 0)
1339 start = _eail_move_chars(textblock, start, -1);
1344 *start_offset = start;
1346 g_assert(start <= end);
1348 return g_utf8_substring(text, start, end);
1352 * @brief Adds attribute to attribute set
1354 * @param attrib_set AtkAttributeSet to add the attribute to
1355 * @param attr AtkTextAttrribute to be added
1356 * @param value attribute value
1358 * Creates an AtkAttribute from attr and value, and adds it
1361 * @returns AtkAttributeSet containing set with added attribute
1364 eail_utils_text_add_attribute(AtkAttributeSet *attrib_set,
1365 AtkTextAttribute attr,
1368 AtkAttributeSet *return_set;
1369 AtkAttribute *at = g_malloc (sizeof (AtkAttribute));
1370 at->name = g_strdup (atk_text_attribute_get_name (attr));
1371 at->value = g_strdup(value);
1372 return_set = g_slist_prepend(attrib_set, at);