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 EailPopup implementation
26 #include <Elementary.h>
28 #include "eail_popup.h"
29 #include "eail_notify.h"
30 #include "eail_factory.h"
31 #include "eail_utils.h"
32 #include "eail_priv.h"
33 #include "eail_text.h"
35 static void atk_text_interface_init(AtkTextIface *iface);
38 * @brief Definition of EailPopup as GObject
40 * EailPopup is extended EAIL_TYPE_NOTIFY with ATK_TYPE_TEXT interface
43 G_DEFINE_TYPE_WITH_CODE(EailPopup, eail_popup, EAIL_TYPE_NOTIFY,
44 G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT,
45 atk_text_interface_init));
50 #define EAIL_POPUP_BUTTON_FORMAT "button%d"
52 * @brief Number of popup buttons
54 #define EAIL_POPUP_NUM_BUTTONS 3
56 * @brief Part name buffer size
58 #define EAIL_POPUP_CHAR_BUF_SIZE 30
61 * @brief Initializer for AtkObject
63 * @param obj AtkObject instance
64 * @param data initialization data
67 eail_popup_initialize(AtkObject *obj, gpointer data)
69 ATK_OBJECT_CLASS(eail_popup_parent_class) ->initialize(obj, data);
70 obj->role = ATK_ROLE_POPUP_MENU;
74 * @brief EailPopup GObject instance initializer
76 * @param button EailPopup instance
79 eail_popup_init(EailPopup *button)
84 * @brief Helper function for getting elm_popup Evas_Object* from Atk EailPopup
86 * @param obj AtkObject instance
88 * @returns Evas_Object representing the nested elm_popup widget
91 _eail_get_popup_widget_from_atkobj(AtkObject *obj)
93 Evas_Object *popup_widget = NULL;
94 popup_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
97 ERR("No widget found for notification object!");
105 * @brief Helper func to get Textblock form popup widget
107 * @param text AtkText instance
108 * @returns Textblock part of popup widget
110 static const Evas_Object *
111 _eail_get_textblock(AtkText *text)
114 const Evas_Object *textblock;
115 Evas_Object *label = NULL;
116 Evas_Object *layout = NULL;
117 Evas_Object *layout_edje_layer = NULL;
118 Evas_Object *label_edje_layer = NULL;
119 Evas_Object *popup_edje_layer = NULL;
121 widget = eail_widget_get_widget(EAIL_WIDGET(text));
122 if (!widget) return NULL;
124 popup_edje_layer = elm_layout_edje_get(widget);
125 if (!popup_edje_layer) return NULL;
127 layout = edje_object_part_swallow_get(popup_edje_layer, "elm.swallow.content");
128 if (!layout) return NULL;
130 layout_edje_layer = elm_layout_edje_get(layout);
131 if (!layout_edje_layer) return NULL;
133 label = edje_object_part_swallow_get(layout_edje_layer, "elm.swallow.content");
134 if (!label) return NULL;
136 label_edje_layer = elm_layout_edje_get(label);
137 if (!label_edje_layer) return NULL;
139 textblock = edje_object_part_object_get(label_edje_layer, "elm.text");
140 if (!textblock) return NULL;
147 * @brief Helper function for getting nested content in elm_popup widget
149 * @param obj AtkObject instance
151 * @returns Evas_Object representing the nested widget content from elm_popup widget
154 _eail_get_nested_widget(AtkObject *obj)
156 Evas_Object *popup_widget = NULL, *nested_widget = NULL;
158 /* getting widget of popup class */
159 popup_widget = _eail_get_popup_widget_from_atkobj(obj);
160 if (!popup_widget) return NULL;
162 nested_widget = elm_object_part_content_get(popup_widget, "default");
164 return nested_widget;
168 * @brief Helper function for getting nested button content in elm_popup widget
170 * @param obj AtkObject instance
171 * @param index index of button in popup widget
173 * @returns Evas_Object representing the nested button widget
174 * from elm_popup widget or NULL in case of a failure
177 _eail_get_nested_popup_button(AtkObject *obj, gint index)
179 gchar buf[EAIL_POPUP_CHAR_BUF_SIZE];
180 Evas_Object *ret_button = NULL, *popup_widget = NULL;
182 if (index >= EAIL_POPUP_NUM_BUTTONS)
184 ERR("Index of popup button cannot be >= %d", EAIL_POPUP_NUM_BUTTONS);
188 popup_widget = _eail_get_popup_widget_from_atkobj(obj);
189 if (!popup_widget) return NULL;
191 g_snprintf(buf, sizeof(buf), EAIL_POPUP_BUTTON_FORMAT, (index + 1));
192 ret_button = elm_object_part_content_get(popup_widget, buf);
198 * @brief Prepares Eina_List filled with Evas_Object * objects
199 * representing nested content in elm_popup widget
201 * Call eina_list_free on the returned list when results processing has been finished.
203 * @param obj AtkObject instance
205 * @return Eina_List representing the list of Evas_Object* objects
208 _eail_popup_get_items(AtkObject *obj)
210 Eina_List *items = NULL;
211 Evas_Object *widget = NULL;
215 widget = _eail_get_nested_widget(obj);
217 items = eina_list_append(items, widget);
219 /* action buttons below popup content */
220 for (i = 0; i < EAIL_POPUP_NUM_BUTTONS; ++i)
222 widget = _eail_get_nested_popup_button(obj, i);
224 items = eina_list_append(items, widget);
231 * @brief Gets the number of accessible children of the accessible
233 * Implementation of AtkObject->get_n_children callback.
235 * @param obj AtkObject instance
237 * @returns integer representing the number of accessible children of
241 eail_popup_get_n_children(AtkObject *obj)
243 Eina_List *items = NULL;
244 gint num_of_children = 0;
246 items = _eail_popup_get_items(obj);
247 num_of_children = eina_list_count(items);
249 return num_of_children;
253 * @brief Gets a reference to the specified accessible child of the object.
255 * The accessible children are 0-based so the first accessible child is at index 0,
256 * the second at index 1 and so on.
258 * Implementation of AtkObject->ref_child callback.
260 * @param obj AtkObject instance
261 * @param i index of a child
263 * @returns AtkObject representing the specified accessible child of the
267 eail_popup_ref_child(AtkObject *obj, gint i)
269 Eina_List *items = NULL;
270 AtkObject *atk_obj = NULL;
272 items = _eail_popup_get_items(obj);
273 if (eina_list_count(items) > i)
274 atk_obj = eail_factory_get_accessible(eina_list_nth(items, i));
277 g_object_ref(atk_obj);
283 * @brief Gets the accessible name of EailItem
285 * Implementation of AtkObject->get_name callback.
287 * @param obj AtkObject instance
289 * @returns character string representing the accessible description of
293 eail_popup_get_name(AtkObject *obj)
295 Evas_Object *popup_widget = NULL;
296 const char *atk_name;
298 atk_name = ATK_OBJECT_CLASS(eail_popup_parent_class)->get_name(obj);
299 if (atk_name) return atk_name;
301 popup_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
304 ERR("No widget found for notification object!");
308 return elm_object_part_text_get(popup_widget, "title,text");
312 * @brief Destructor for EailPopup class
313 * @param object GObject instance
316 eail_popup_finalize(GObject *object)
318 G_OBJECT_CLASS(eail_popup_parent_class)->finalize(object);
322 * @brief Initializer for EailPopup GObject class
324 * Defines callbacks for base AtkObject.
326 * @param klass EailPopupClass instance
329 eail_popup_class_init(EailPopupClass *klass)
331 AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
332 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
333 class->initialize = eail_popup_initialize;
334 class->get_n_children = eail_popup_get_n_children;
335 class->ref_child = eail_popup_ref_child;
336 class->get_name = eail_popup_get_name;
337 gobject_class->finalize = eail_popup_finalize;
341 * AtkText interface functions
345 * @brief Helper function that gets text from popup as Eina_Strbuf*
347 * @param popup AtkText instance
349 * @returns Eina_Strbuf representing the text content of the popup
352 _eail_popup_get_strbuf(AtkText *popup)
354 Evas_Object *popup_widget = NULL;
355 Eina_Strbuf* str_buf = NULL;
356 const gchar *text_part = NULL;
358 g_return_val_if_fail (ATK_IS_OBJECT(popup), NULL);
360 /* getting widget of popup class */
361 popup_widget = _eail_get_popup_widget_from_atkobj(ATK_OBJECT(popup));
362 if (!popup_widget) return NULL;
364 text_part = elm_object_part_text_get(popup_widget, "default");
365 if (!text_part) return NULL;
367 str_buf = eina_strbuf_new();
368 eina_strbuf_append(str_buf, text_part);
374 * @brief Gets the text content from popup
376 * Use g_free() to free the returned string.
378 * Implementation of AtkTextIface->get_text callback.
380 * @param popup AtkText instance
381 * @param start_offset start position
382 * @param end_offset end position, or -1 for the end of the string.
384 * @returns newly allocated string containing the text from start_offset
385 * up to, but not including end_offset
388 eail_popup_get_text(AtkText *popup,
392 Eina_Strbuf* str_buf = NULL;
393 gchar *ret_str = NULL;
395 g_return_val_if_fail(EAIL_IS_POPUP(popup), NULL);
397 str_buf = _eail_popup_get_strbuf(popup);
398 if (!str_buf) return NULL;
400 ret_str = eail_get_substring
401 (eina_strbuf_string_get(str_buf), start_offset, end_offset);
403 eina_strbuf_free(str_buf);
409 * @brief Gets the character from popup at given offset
411 * Implementation of AtkTextIface->get_character_at_offset callback,
413 * @param popup AtkText instance
414 * @param offset offset
416 * @returns char representing the character at offset
419 eail_popup_get_character_at_offset(AtkText *popup, gint offset)
421 gunichar character = '\0';
422 gchar* time_str = NULL;
424 g_return_val_if_fail(EAIL_IS_POPUP(popup), character);
426 time_str = eail_popup_get_text(popup, 0, -1);
430 character = g_utf8_get_char
431 (g_utf8_offset_to_pointer(time_str, offset));
439 * @brief Gets the character count from text content in popup
441 * Implementation of AtkTextIface->get_character_count callback.
443 * @param popup AtkText instance
445 * @returns char representing the the character count
448 eail_popup_get_character_count(AtkText *popup)
451 gchar* time_str = NULL;
453 g_return_val_if_fail(EAIL_IS_POPUP(popup), 0);
455 time_str = eail_popup_get_text(popup, 0, -1);
459 count = g_utf8_strlen(time_str, -1);
467 * @brief Get the bounding box containing the glyph
468 * representing the character at a particular text offset.
470 * @param text AtkText instance
471 * @param offset The offset of the text character for which
472 * bounding information is required.
473 * @param x Pointer for the x cordinate of the bounding box
474 * @param y Pointer for the y cordinate of the bounding box
475 * @param width Pointer for the width of the bounding box
476 * @param height Pointer for the height of the bounding box
477 * @param coords specify whether coordinates are relative to the
478 * screen or widget window
482 eail_popup_get_character_extents(AtkText *text,
491 Evas_Textblock_Cursor *cur = NULL;
493 const Evas_Object *textblock;
495 widget = eail_widget_get_widget(EAIL_WIDGET(text));
498 textblock = _eail_get_textblock(text);
499 if (!textblock) return;
501 cur = evas_object_textblock_cursor_new(textblock);
504 evas_textblock_cursor_pos_set(cur, offset);
506 result = evas_textblock_cursor_char_geometry_get(cur, x, y, width, height);
508 evas_textblock_cursor_free(cur);
510 if (-1 == result) return;
512 if (coords == ATK_XY_SCREEN)
515 Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
517 ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
524 * @brief Creates an AtkAttributeSet which consists of the attributes
525 * explicitly set at the position offset in the text.
527 * start_offset and end_offset are set to the start and end of the range around offset
528 * where the attributes are invariant.
530 * Note that end_offset is the offset of the first character after the range.
532 * This AtkAttributeSet should be freed by a call to
533 * atk_attribute_set_free()
535 * @param text AtkText instance
536 * @param offset the offset at which to get the attributes
537 * @param [out] start_offset start offset of the range
538 * @param [out] end_offset end offset of the range
540 * @returns an AtkAttributeSet which contains the attributes explicitly set at
543 static AtkAttributeSet *
544 eail_popup_get_run_attributes(AtkText *text,
549 AtkAttributeSet *at_set = NULL;
550 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
551 gint len = eail_popup_get_character_count(ATK_TEXT(text));
553 if (!widget || offset >= len)
564 /* NOTE: Elm_Wrap_Type value is in 100% compatible with ATK wrap modes, so
565 * no additional conversion is needed*/
566 Elm_Wrap_Type wrap_type = elm_popup_content_text_wrap_type_get(widget);
567 at_set = eail_utils_text_add_attribute
568 (at_set, ATK_TEXT_ATTR_WRAP_MODE,
569 atk_text_attribute_get_value
570 (ATK_TEXT_ATTR_WRAP_MODE, wrap_type));
572 at_set = eail_utils_text_add_attribute
573 (at_set, ATK_TEXT_ATTR_EDITABLE,
574 atk_text_attribute_get_value
575 (ATK_TEXT_ATTR_EDITABLE, FALSE));
581 * @brief Creates an AtkAttributeSet which consists of the default values of
582 * attributes for the text.
584 * This AtkAttributeSet should be freed by a call to
585 * atk_attribute_set_free()
587 * @param text AtkText instance
589 * @returns AtkAttributeSet containing default values of attributes
592 static AtkAttributeSet *
593 eail_popup_get_default_attributes(AtkText *text)
595 AtkAttributeSet *at_set = NULL;
597 at_set = eail_utils_text_add_attribute
598 (at_set, ATK_TEXT_ATTR_WRAP_MODE,
599 atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0));
601 at_set = eail_utils_text_add_attribute
602 (at_set, ATK_TEXT_ATTR_EDITABLE,
603 atk_text_attribute_get_value
604 (ATK_TEXT_ATTR_EDITABLE, FALSE));
610 * @brief Gets the specified text after offset
612 * Use g_free() to free the returned string.
614 * @param text AtkText instance
615 * @param offset character offset
616 * @param boundary_type AtkTextBoundary instance
617 * @param [out] start_offset start offset of the returned string
618 * @param [out] end_offset offset of the first character after the returned
620 * @returns newly allocated string containing the text after offset bounded
621 * by the specified boundary_type
624 eail_popup_get_text_after_offset(AtkText *text,
626 AtkTextBoundary boundary_type,
630 const Evas_Object *textblock;
632 textblock = _eail_get_textblock(text);
633 if (!textblock) return NULL;
635 return eail_get_text_after(textblock, offset, boundary_type, start_offset,
641 * @brief Gets the specified text at offset
643 * Use g_free() to free the returned string.
645 * @param text AtkText instance
646 * @param offset character offset
647 * @param boundary_type AtkTextBoundary instance
648 * @param [out] start_offset start offset of the returned string
649 * @param [out] end_offset offset of the first character after the returned
651 * @returns newly allocated string containing the text after offset bounded
652 * by the specified boundary_type
655 eail_popup_get_text_at_offset(AtkText *text,
657 AtkTextBoundary boundary_type,
661 const Evas_Object *textblock;
663 textblock = _eail_get_textblock(text);
664 if (!textblock) return NULL;
666 return eail_get_text_at(textblock, offset, boundary_type, start_offset,
671 * @brief Gets the specified text before offset
673 * Use g_free() to free the returned string.
675 * @param text AtkText instance
676 * @param offset character offset
677 * @param boundary_type AtkTextBoundary instance
678 * @param [out] start_offset start offset of the returned string
679 * @param [out] end_offset offset of the first character after the returned
681 * @returns newly allocated string containing the text after offset bounded
682 * by the specified boundary_type
685 eail_popup_get_text_before_offset(AtkText *text,
687 AtkTextBoundary boundary_type,
691 const Evas_Object *textblock;
693 textblock = _eail_get_textblock(text);
694 if (!textblock) return NULL;
696 return eail_get_text_before(textblock, offset, boundary_type, start_offset,
701 * @brief Gets the offset of the character located at coordinates
702 * x and y. x and y are interpreted as being relative to the
703 * screen or this widget's window depending on coords.
705 * @param text AtkText instance
706 * @param x screen x-position of character
707 * @param y screen y-position of character
708 * @param coords specify whether coordinates are relative to the
709 * screen or widget window
711 * @returns the offset to the character which is located at the
712 * specified x and y coordinates.
715 eail_popup_get_offset_at_point(AtkText *text,
720 const Evas_Object *textblock;
722 Eina_Bool result = EINA_FALSE;
723 Evas_Textblock_Cursor *cur = NULL;
725 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
727 if (!widget) return offset;
729 textblock = _eail_get_textblock(text);
730 if (!textblock) return offset;
732 cur = evas_object_textblock_cursor_new(textblock);
733 if (!cur) return offset;
735 if (coords == ATK_XY_SCREEN)
738 Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
740 ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
745 result = evas_textblock_cursor_char_coord_set(cur, x, y);
747 if (result == EINA_FALSE)
749 evas_textblock_cursor_free(cur);
753 offset = evas_textblock_cursor_pos_get(cur);
754 evas_textblock_cursor_free(cur);
760 * @brief Initializer for AtkTextIface interface class
762 * Defines callbacks for AtkTextIface.
764 * @param iface AtkTextIface instance
767 atk_text_interface_init(AtkTextIface *iface)
769 iface->get_text = eail_popup_get_text;
770 iface->get_character_at_offset = eail_popup_get_character_at_offset;
771 iface->get_character_count = eail_popup_get_character_count;
772 iface->get_character_extents = eail_popup_get_character_extents;
773 iface->get_run_attributes = eail_popup_get_run_attributes;
774 iface->get_default_attributes = eail_popup_get_default_attributes;
775 iface->get_text_after_offset = eail_popup_get_text_after_offset;
776 iface->get_text_at_offset = eail_popup_get_text_at_offset;
777 iface->get_text_before_offset = eail_popup_get_text_before_offset;
778 iface->get_offset_at_point = eail_popup_get_offset_at_point;