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 EailEntry implementation
25 #include <Elementary.h>
27 #include "eail_entry.h"
28 #include "eail_utils.h"
29 #include "eail_priv.h"
30 #include "eail_clipboard.h"
32 static void atk_text_interface_init(AtkTextIface *iface);
33 static void atk_editable_text_interface_init(AtkEditableTextIface *iface);
36 * @brief Definition of EailEntry as GObject
38 * EailEntry is extended EAIL_TYPE_TEXT with ATK_TYPE_TEXT and
39 * ATK_TYPE_EDITABLE_TEXT interfaces implemented.
42 G_DEFINE_TYPE_WITH_CODE(EailEntry,
45 G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT,
46 atk_text_interface_init)
47 G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT,
48 atk_editable_text_interface_init));
51 * @brief Handler for event which is raised when entry content has changed
53 * @param data data passed to callback
54 * @param obj Evas_Object that raised event
55 * @param event_info additional event info
58 _eail_entry_handle_changed_event(void *data,
63 (ATK_OBJECT(data), "visible-data-changed", ATK_TYPE_OBJECT);
67 * @brief handler for event which is raised when entry content is being pressed
69 * @param data passed to callback
70 * @param obj object that raised event
71 * @param event_info additional event info
74 _eail_entry_handle_pressed_event(void *data,
78 atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_PRESSED, TRUE);
82 * @brief handler for event which is raised when entry cusror position is being changed
84 * @param data passed to callback
85 * @param obj object that raised event
86 * @param event_info additional event info
89 _eail_entry_handle_cursor_changed_event(void *data,
93 g_signal_emit_by_name (ATK_OBJECT(data), "text_caret_moved",
94 elm_entry_cursor_pos_get(obj));
98 * @brief Initializer for AtkObject
100 * @param obj AtkObject instance
101 * @param data initialization data
104 eail_entry_initialize(AtkObject *obj, gpointer data)
106 Evas_Object *nested_widget = NULL;
107 ATK_OBJECT_CLASS(eail_entry_parent_class)->initialize(obj, data);
109 obj->role = ATK_ROLE_ENTRY;
111 g_return_if_fail(EAIL_IS_WIDGET(obj));
112 nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
115 ERR("No evas object inside EailWidget was found");
119 evas_object_smart_callback_add(nested_widget, "changed",
120 _eail_entry_handle_changed_event, obj);
121 evas_object_smart_callback_add(nested_widget, "cursor,changed",
122 _eail_entry_handle_cursor_changed_event, obj);
123 evas_object_smart_callback_add(nested_widget, "press",
124 _eail_entry_handle_pressed_event, obj);
128 * @brief Class destructor
130 * @param obj GObject instance
133 eail_entry_finalize(GObject *obj)
138 * @brief Gets a reference to the state set of the accessible
140 * The caller must unreference it when it is no longer needed.
142 * Implementation of AtkObject->ref_state_set callback.
144 * @param obj AtkObject instance
146 * @returns AtkStateSet representing the state set of the
150 eail_entry_ref_state_set(AtkObject *obj)
152 AtkStateSet *state_set;
153 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
158 state_set = ATK_OBJECT_CLASS(eail_entry_parent_class)->ref_state_set(obj);
160 if (elm_entry_editable_get(widget))
161 atk_state_set_add_state(state_set, ATK_STATE_EDITABLE);
163 if (elm_entry_single_line_get(widget))
164 atk_state_set_add_state(state_set, ATK_STATE_SINGLE_LINE);
166 atk_state_set_add_state(state_set, ATK_STATE_MULTI_LINE);
172 * @brief Initializer for EailEntry GObject implementation
174 * @param entry EailEntry instance
177 eail_entry_init(EailEntry *entry)
179 entry->selection_start = 0;
180 entry->selection_end = 0;
184 * @brief Initializer for EailPopup GObject class
186 * Defines callbacks for base AtkObject.
188 * @param klass EailEntryClass instance
191 eail_entry_class_init(EailEntryClass *klass)
193 AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
194 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
196 atk_class->initialize = eail_entry_initialize;
197 atk_class->ref_state_set = eail_entry_ref_state_set;
198 gobject_class->finalize = eail_entry_finalize;
202 * @brief Gets the caret offset
204 * @param text AtkText instance
205 * @return integer representing the caret offset
208 eail_entry_get_caret_offset(AtkText *text)
212 widget = eail_widget_get_widget(EAIL_WIDGET(text));
216 return elm_entry_cursor_pos_get(widget);
220 * @brief Sets the caret (cursor) position to the specified offset.
222 * Implementation of AtkTextIface->set_caret_offset callback.
224 * @param text AtkText instance
225 * @param offset starting position
227 * @returns TRUE on success, FALSE otherwise
230 eail_entry_set_caret_offset (AtkText *text,
235 widget = eail_widget_get_widget(EAIL_WIDGET(text));
239 elm_entry_cursor_pos_set(widget, offset);
245 * @brief Gets the number of selected text regions
247 * @param text AtkText instance
248 * @returns integer representing the number of
249 * selected text regions
252 eail_entry_get_n_selections(AtkText *text)
256 widget = eail_widget_get_widget(EAIL_WIDGET(text));
257 if (!widget) return 0;
259 if (elm_entry_selection_get(widget)) return 1;
265 * @brief Gets text selection from entry
267 * Use g_free() to free the returned string.
269 * The selected regions are assigned
270 * numbers that correspond to how far the region is from the start of the text.
271 * The selected region closest to the beginning of the text region is assigned
272 * the number 0, etc. Note that adding, moving or deleting a selected region can
273 * change the numbering.
275 * Implementation of AtkTextIface->get_selection callback.
277 * @param text AtkText instance
278 * @param selection_num selection number
279 * @param start_offset start position of the selected region
280 * @param end_offset end position of the selected region
282 * @returns newly allocated string containing the selected text
285 eail_entry_get_selection(AtkText *text,
290 const char* selection;
293 widget = eail_widget_get_widget(EAIL_WIDGET(text));
297 if (0 != selection_num)
300 selection = elm_entry_selection_get(widget);
303 *start_offset = EAIL_ENTRY(text)->selection_start;
304 *end_offset = EAIL_ENTRY(text)->selection_end;
305 return g_strdup(selection);
312 * @brief Adds a selection bounded by the specified offsets
314 * @param text AtkText instance
315 * @param start_offset start position of the selection
316 * @param end_offset offset of the first character after selection
317 * @returns TRUE on success, FALSE otherwise
320 eail_entry_add_selection(AtkText *text,
326 widget = eail_widget_get_widget(EAIL_WIDGET(text));
327 if (!widget) return FALSE;
329 elm_entry_cursor_pos_set(widget, start_offset);
330 elm_entry_cursor_selection_begin(widget);
331 elm_entry_cursor_pos_set(widget, end_offset);
332 elm_entry_cursor_selection_end(widget);
334 EAIL_ENTRY(text)->selection_start = start_offset;
335 EAIL_ENTRY(text)->selection_end = end_offset;
341 * @brief Removes text selection
343 * Only one selection is supported, so
344 * selection number equals 0.
346 * @param text AtkText instance
347 * @param selection_num selection number
348 * @return TRUE on success, FALSE otherwise
351 eail_entry_remove_selection(AtkText *text,
356 widget = eail_widget_get_widget(EAIL_WIDGET(text));
357 if (!widget) return FALSE;
359 if (selection_num != 0 || !elm_entry_selection_get(widget)) return FALSE;
361 elm_entry_select_none(widget);
362 EAIL_ENTRY(text)->selection_start = 0;
363 EAIL_ENTRY(text)->selection_end = 0;
369 * @brief Sets text selection for entry
371 * The selected regions are assigned
372 * numbers that correspond to how far the region is from the start of the text.
373 * The selected region closest to the beginning of the text region is assigned
374 * the number 0, etc. Note that adding, moving or deleting a selected region can
375 * change the numbering.
377 * Implementation of AtkTextIface->set_selection callback.
379 * @param text AtkText instance
380 * @param selection_num selection number
381 * @param start_pos start position of the selected region
382 * @param end_pos end position of the selected region
384 * @returns TRUE on success, FALSE otherwise
387 eail_entry_set_selection(AtkText *text,
392 if (0 != selection_num)
395 return eail_entry_add_selection(text, start_pos, end_pos);
399 * @brief Gets text bounded by start_offset and end_offset
401 * Use g_free() to free the returned string.
403 * @param text AtkText instance
404 * @param start_offset start position
405 * @param end_offset end position, -1 for the end of the string
406 * @return string containing text from start_offset up to,
407 * but not including end_offset
410 eail_entry_get_text(AtkText *text,
414 const gchar *string = NULL;
415 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
418 string = elm_entry_entry_get(widget);
420 return eail_get_substring(string, start_offset, end_offset);
425 * @brief Gets the specified text after offset
427 * Use g_free() to free the returned string.
429 * @param text AtkText instance
430 * @param offset character offset
431 * @param boundary_type AtkTextBoundary instance
432 * @param [out] start_offset start offset of the returned string
433 * @param [out] end_offset offset of the first character after the returned
435 * @returns newly allocated string containing the text after offset bounded
436 * by the specified boundary_type
439 eail_entry_get_text_after_offset(AtkText *text,
441 AtkTextBoundary boundary_type,
446 Evas_Object *textblock;
448 widget = eail_widget_get_widget(EAIL_WIDGET(text));
449 if (!widget) return NULL;
451 textblock = elm_entry_textblock_get(widget);
453 return eail_get_text_after(textblock, offset, boundary_type, start_offset,
459 * @brief Gets the specified text at offset
461 * Use g_free() to free the returned string.
463 * @param text AtkText instance
464 * @param offset character offset
465 * @param boundary_type AtkTextBoundary instance
466 * @param [out] start_offset start offset of the returned string
467 * @param [out] end_offset offset of the first character after the returned
469 * @returns newly allocated string containing the text after offset bounded
470 * by the specified boundary_type
473 eail_entry_get_text_at_offset(AtkText *text,
475 AtkTextBoundary boundary_type,
480 Evas_Object *textblock;
482 widget = eail_widget_get_widget(EAIL_WIDGET(text));
483 if (!widget) return NULL;
485 textblock = elm_entry_textblock_get(widget);
487 return eail_get_text_at(textblock, offset, boundary_type, start_offset,
492 * @brief Gets the specified text before offset
494 * Use g_free() to free the returned string.
496 * @param text AtkText instance
497 * @param offset character offset
498 * @param boundary_type AtkTextBoundary instance
499 * @param [out] start_offset start offset of the returned string
500 * @param [out] end_offset offset of the first character after the returned
502 * @returns newly allocated string containing the text after offset bounded
503 * by the specified boundary_type
506 eail_entry_get_text_before_offset(AtkText *text,
508 AtkTextBoundary boundary_type,
513 Evas_Object *textblock;
515 widget = eail_widget_get_widget(EAIL_WIDGET(text));
516 if (!widget) return NULL;
518 textblock = elm_entry_textblock_get(widget);
520 return eail_get_text_before(textblock, offset, boundary_type, start_offset,
525 * @brief Gets the character at offset
527 * @param text AtkText instance
528 * @param offset character offset
529 * @return char representing the character at offset
532 eail_entry_get_character_at_offset(AtkText *text,
535 gunichar character = '\0';
536 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
539 character = g_utf8_get_char(
540 g_utf8_offset_to_pointer(elm_entry_entry_get(widget), offset));
546 * @brief Gets the text's length
548 * @param text AtkText instance
549 * @return integer representing the text length
552 eail_entry_get_character_count(AtkText *text)
555 const gchar *string_text = NULL;
557 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
559 if (!widget) return count;
561 string_text = elm_object_text_get(widget);
562 if (!string_text) return count;
564 count = g_utf8_strlen(string_text, -1);
570 * @brief Creates an AtkAttributeSet which consists of the default values of
571 * attributes for the text
573 * The returned AtkAttributeSet should be freed by a call to
574 * atk_attribute_set_free().
576 * @param text AtkText instance
578 * @returns AtkAttributeSet which contains the default values of attributes
581 static AtkAttributeSet *
582 eail_entry_get_default_attributes(AtkText *text)
584 AtkAttributeSet *at_set = NULL;
586 at_set = eail_utils_text_add_attribute
587 (at_set, ATK_TEXT_ATTR_WRAP_MODE,
588 atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0));
590 at_set = eail_utils_text_add_attribute
591 (at_set, ATK_TEXT_ATTR_EDITABLE,
592 atk_text_attribute_get_value
593 (ATK_TEXT_ATTR_EDITABLE, TRUE));
599 * @brief Creates an AtkAttributeSet which consists of the attributes
600 * explicitly set at the position offset in the text
602 * start_offset and end_offset are set to the start and end of the range
603 * around offset where the attributes are invariant. Note that end_offset
604 * is the offset of the first character after the range.
606 * The returned AtkAttributeSet should be freed by a call to
607 * atk_attribute_set_free()
609 * @param text AtkText instance
610 * @param offset offset at which to get the attributes
611 * @param [out] start_offset start offset of the range
612 * @param [out] end_offset end offset of the range
614 * @returns AtkAttributeSet which contains the attributes explicitly set at
617 static AtkAttributeSet *
618 eail_entry_get_run_attributes(AtkText *text,
623 AtkAttributeSet *at_set = NULL;
624 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
626 if (!widget || offset >= eail_entry_get_character_count(text))
635 *end_offset = eail_entry_get_character_count(text);
637 /* NOTE: Elm_Wrap_Type value is in 100% compatible with ATK wrap modes, so
638 * no additional conversion is needed*/
639 Elm_Wrap_Type wrap_type = elm_entry_line_wrap_get(widget);
640 at_set = eail_utils_text_add_attribute
641 (at_set, ATK_TEXT_ATTR_WRAP_MODE,
642 atk_text_attribute_get_value
643 (ATK_TEXT_ATTR_WRAP_MODE, wrap_type));
645 Eina_Bool editable = elm_entry_editable_get(widget);
646 at_set = eail_utils_text_add_attribute
647 (at_set, ATK_TEXT_ATTR_EDITABLE,
648 atk_text_attribute_get_value
649 (ATK_TEXT_ATTR_EDITABLE, editable));
655 * @brief Get the bounding box containing the glyph
656 * representing the character at a particular text offset.
658 * @param text AtkText instance
659 * @param offset The offset of the text character for which
660 * bounding information is required.
661 * @param x Pointer for the x cordinate of the bounding box
662 * @param y Pointer for the y cordinate of the bounding box
663 * @param width Pointer for the width of the bounding box
664 * @param height Pointer for the height of the bounding box
665 * @param coords specify whether coordinates are relative to the
666 * screen or widget window
670 eail_entry_get_character_extents(AtkText *text,
679 Evas_Object *textblock = NULL;
680 Evas_Textblock_Cursor *cur = NULL;
682 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
689 textblock = elm_entry_textblock_get(widget);
690 cur = evas_object_textblock_cursor_new(textblock);
691 evas_textblock_cursor_pos_set(cur, offset);
693 result = evas_textblock_cursor_char_geometry_get(cur, x, y, width, height);
695 evas_textblock_cursor_free(cur);
697 if (-1 == result) return;
699 if (coords == ATK_XY_SCREEN)
702 Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
704 ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
711 * @brief Gets the offset of the character located at coordinates
712 * x and y. x and y are interpreted as being relative to the
713 * screen or this widget's window depending on coords.
715 * @param text AtkText instance
716 * @param x screen x-position of character
717 * @param y screen y-position of character
718 * @param coords specify whether coordinates are relative to the
719 * screen or widget window
721 * @returns the offset to the character which is located at the
722 * specified x and y coordinates.
725 eail_entry_get_offset_at_point(AtkText *text,
730 Eina_Bool result = EINA_FALSE;
731 Evas_Object *textblock = NULL;
732 Evas_Textblock_Cursor *cur = NULL;
735 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
737 if (!widget) return offset;
739 if (coords == ATK_XY_SCREEN)
742 Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
744 ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
749 textblock = elm_entry_textblock_get(widget);
750 if (!textblock) return offset;
752 cur = evas_object_textblock_cursor_new(textblock);
753 if (!cur) return offset;
755 result = evas_textblock_cursor_char_coord_set(cur, x, y);
757 if (result == EINA_FALSE)
759 evas_textblock_cursor_free(cur);
763 offset = evas_textblock_cursor_pos_get(cur);
764 evas_textblock_cursor_free(cur);
770 * @brief Initializes AtkTextIface interface
772 * @param iface AtkTextIface instance
775 atk_text_interface_init(AtkTextIface *iface)
777 iface->get_caret_offset = eail_entry_get_caret_offset;
778 iface->set_caret_offset = eail_entry_set_caret_offset;
779 iface->get_selection = eail_entry_get_selection;
780 iface->set_selection = eail_entry_set_selection;
781 iface->get_text = eail_entry_get_text;
782 iface->get_character_at_offset = eail_entry_get_character_at_offset;
783 iface->get_character_count = eail_entry_get_character_count;
784 iface->remove_selection = eail_entry_remove_selection;
785 iface->get_n_selections = eail_entry_get_n_selections;
786 iface->add_selection = eail_entry_add_selection;
787 iface->get_run_attributes = eail_entry_get_run_attributes;
788 iface->get_default_attributes = eail_entry_get_default_attributes;
789 iface->get_text_after_offset = eail_entry_get_text_after_offset;
790 iface->get_text_at_offset = eail_entry_get_text_at_offset;
791 iface->get_text_before_offset = eail_entry_get_text_before_offset;
792 iface->get_character_extents = eail_entry_get_character_extents;
793 iface->get_offset_at_point = eail_entry_get_offset_at_point;
797 * Implementation of the *AtkEditableText* interface
801 * @brief Sets text content of entry
803 * @param text AtkEditableText instance
804 * @param string string to be set as the content of entry
807 eail_entry_set_text_contents(AtkEditableText *text,
812 widget = eail_widget_get_widget(EAIL_WIDGET(text));
813 if (widget && elm_entry_editable_get(widget))
814 elm_object_text_set(widget, string);
818 * @brief Copies text content from entry to clipboard
820 * @param text AtkEditableText instance
821 * @param start_pos start position of the cursor
822 * @param end_pos end position of the cursor
825 eail_entry_copy_text(AtkEditableText *text,
830 const char *entry_text;
833 widget = eail_widget_get_widget(EAIL_WIDGET(text));
836 entry_text = elm_entry_entry_get(widget);
837 tmp = eail_get_substring(entry_text, start_pos, end_pos);
838 eail_clipboard_set_text(tmp);
843 * @brief Cuts text content from entry to clipboard
845 * @param text AtkEditableText instance
846 * @param start_pos start position of the cursor
847 * @param end_pos end position of the cursor
850 eail_entry_cut_text(AtkEditableText *text,
855 const char *entry_text;
859 widget = eail_widget_get_widget(EAIL_WIDGET(text));
860 if (!widget || !elm_entry_editable_get(widget))
863 entry_text = elm_entry_entry_get(widget);
864 tmp = eail_get_substring(entry_text, start_pos, end_pos);
865 eail_clipboard_set_text(tmp);
868 s = g_string_new(entry_text);
869 s = g_string_erase(s, start_pos, end_pos - start_pos);
871 elm_entry_entry_set(widget, s->str);
872 g_string_free(s, TRUE);
876 * @brief Pastes text content from clipboard into entry
878 * @param text AtkEditableText instance
879 * @param position start position of the cursor
882 eail_entry_paste_text(AtkEditableText *text,
889 widget = eail_widget_get_widget(EAIL_WIDGET(text));
890 if (!widget || !elm_entry_editable_get(widget))
893 clip = eail_clipboard_get_text();
896 s = g_string_new(elm_entry_entry_get(widget));
897 s = g_string_insert(s, position, clip);
898 elm_entry_entry_set(widget, s->str);
899 g_string_free(s, TRUE);
903 * @brief Deletes text between start_pos and end_pos but not
906 * @param text AtkEditableText instance
907 * @param start_pos start position
908 * @param end_pos end position
911 eail_entry_delete_text(AtkEditableText *text,
918 widget = eail_widget_get_widget(EAIL_WIDGET(text));
919 if (!widget || !elm_entry_editable_get(widget))
922 entry_text = g_string_new(elm_entry_entry_get(widget));
923 entry_text = g_string_erase(entry_text, start_pos, end_pos-start_pos);
925 elm_entry_entry_set(widget, entry_text->str);
926 g_string_free(entry_text, TRUE);
930 * @brief Inserts text at the specified position
932 * After the call position points to the position after the newly inserted text.
934 * @param text AtkEditableText instance
935 * @param string string to insert
936 * @param length string's length
937 * @param [out] position position at which text is inserted
940 eail_entry_insert_text(AtkEditableText *text,
948 widget = eail_widget_get_widget(EAIL_WIDGET(text));
949 if (!widget || !elm_entry_editable_get(widget))
952 entry_text = g_string_new(elm_entry_entry_get(widget));
953 entry_text = g_string_insert_len(entry_text, *position, string,
955 elm_entry_entry_set(widget, entry_text->str);
957 g_string_free(entry_text, TRUE);
961 * @brief Initialization for AtkEditableTextIface interface
963 * Function called upon instance creation. It initializes AtkText interface
964 * implementation i.e hooks method pointers in the interface structure
965 * to the implementing class's implementation.
967 * @param iface AtkEditableTextIface instance
970 atk_editable_text_interface_init(AtkEditableTextIface *iface)
972 iface->set_text_contents = eail_entry_set_text_contents;
973 iface->copy_text = eail_entry_copy_text;
974 iface->cut_text = eail_entry_cut_text;
975 iface->paste_text = eail_entry_paste_text;
976 iface->delete_text = eail_entry_delete_text;
977 iface->insert_text = eail_entry_insert_text;