elementary - added elm_object_item_translatable_part_text_set() elm_object_item_trans...
[framework/uifw/elementary.git] / src / lib / elm_widget.c
index 4e6945a..24980f8 100644 (file)
@@ -13,6 +13,9 @@ static const char ELM_WIDGET_SMART_NAME[] = "elm_widget";
   if (!sd)                                                      \
     return
 
+#define ELM_WIDGET_FOCUS_GET(obj)                                    \
+  ((_elm_access_read_mode_get()) ? (elm_widget_highlight_get(obj)) : \
+                                  (elm_widget_focus_get(obj)))
 typedef struct _Elm_Event_Cb_Data         Elm_Event_Cb_Data;
 typedef struct _Elm_Translate_String_Data Elm_Translate_String_Data;
 
@@ -244,6 +247,7 @@ _elm_widget_sub_object_add_func(Evas_Object *obj,
                return EINA_FALSE;
           }
         sdc->parent_obj = obj;
+        sdc->orient_mode = sd->orient_mode;
         _elm_widget_top_win_focused_set(sobj, sd->top_win_focused);
 
         /* update child focusable-ness on self and parents, now that a
@@ -415,41 +419,6 @@ _smart_add(Evas_Object *obj)
      }
 }
 
-static Evas_Object *
-_newest_focus_order_get(Evas_Object *obj,
-                        unsigned int *newest_focus_order,
-                        Eina_Bool can_focus_only)
-{
-   const Eina_List *l;
-   Evas_Object *child, *ret, *best;
-
-   API_ENTRY return NULL;
-
-   if (!evas_object_visible_get(obj)
-       || (elm_widget_disabled_get(obj))
-       || (elm_widget_tree_unfocusable_get(obj)))
-     return NULL;
-
-   best = NULL;
-   if (*newest_focus_order < sd->focus_order)
-     {
-        *newest_focus_order = sd->focus_order;
-        best = obj;
-     }
-   EINA_LIST_FOREACH(sd->subobjs, l, child)
-     {
-        ret = _newest_focus_order_get
-            (child, newest_focus_order, can_focus_only);
-        if (!ret) continue;
-        best = ret;
-     }
-   if (can_focus_only)
-     {
-        if ((!best) || (!elm_widget_can_focus_get(best)))
-          return NULL;
-     }
-   return best;
-}
 
 static void
 _if_focused_revert(Evas_Object *obj,
@@ -467,8 +436,8 @@ _if_focused_revert(Evas_Object *obj,
    top = elm_widget_top_get(sd->parent_obj);
    if (top)
      {
-        newest = _newest_focus_order_get
-            (top, &newest_focus_order, can_focus_only);
+        newest = elm_widget_newest_focus_order_get
+           (top, &newest_focus_order, can_focus_only);
         if (newest)
           {
              elm_object_focus_set(newest, EINA_FALSE);
@@ -1831,7 +1800,15 @@ elm_widget_focus_cycle(Evas_Object *obj,
      return;
    elm_widget_focus_next_get(obj, dir, &target);
    if (target)
-     elm_widget_focus_steal(target);
+     {
+        /* access */
+        if (_elm_config->access_mode && _elm_access_read_mode_get())
+          {
+             _elm_access_highlight_set(target);
+             _elm_widget_focus_region_show(target);
+          }
+        else elm_widget_focus_steal(target);
+     }
 }
 
 /**
@@ -2354,14 +2331,65 @@ elm_widget_focus_next_get(const Evas_Object *obj,
 
    /* Try use hook */
    if (_elm_widget_focus_chain_manager_is(obj))
-     return sd->api->focus_next(obj, dir, next);
+     {
+        Eina_Bool ret;
+        ret = sd->api->focus_next(obj, dir, next);
+        if (!ret && elm_widget_focus_get(obj))
+          {
+             Evas_Object *o = NULL;
+             if (dir == ELM_FOCUS_PREVIOUS)
+               o = sd->focus_previous;
+             else if (dir == ELM_FOCUS_NEXT)
+               o = sd->focus_next;
+             else if (dir == ELM_FOCUS_UP)
+               o = sd->focus_up;
+             else if (dir == ELM_FOCUS_DOWN)
+               o = sd->focus_down;
+             else if (dir == ELM_FOCUS_RIGHT)
+               o = sd->focus_right;
+             else if (dir == ELM_FOCUS_LEFT)
+               o = sd->focus_left;
+
+             if (o)
+               {
+                  *next = o;
+                  return EINA_TRUE;
+               }
+          }
+        else
+          return ret;
+     }
 
    if (!elm_widget_can_focus_get(obj))
      return EINA_FALSE;
 
+   /* focusable object but does not have access info */
+   if (_elm_config->access_mode)
+     {
+        if (!_elm_access_object_get(obj)) return EINA_FALSE;
+     }
+
+   if (elm_widget_focus_get(obj))
+     {
+        if (dir == ELM_FOCUS_PREVIOUS)
+          *next = sd->focus_previous;
+        else if (dir == ELM_FOCUS_NEXT)
+          *next = sd->focus_next;
+        else if (dir == ELM_FOCUS_UP)
+          *next = sd->focus_up;
+        else if (dir == ELM_FOCUS_DOWN)
+          *next = sd->focus_down;
+        else if (dir == ELM_FOCUS_RIGHT)
+          *next = sd->focus_right;
+        else if (dir == ELM_FOCUS_LEFT)
+          *next = sd->focus_left;
+
+        if (*next)
+          return EINA_TRUE;
+     }
    /* Return */
    *next = (Evas_Object *)obj;
-   return !elm_widget_focus_get(obj);
+   return !ELM_WIDGET_FOCUS_GET(obj);
 }
 
 /**
@@ -2391,6 +2419,7 @@ elm_widget_focus_list_next_get(const Evas_Object *obj,
                                Evas_Object **next)
 {
    Eina_List *(*list_next)(const Eina_List *list) = NULL;
+   Evas_Object *focused_object = NULL;
 
    if (!next)
      return EINA_FALSE;
@@ -2402,13 +2431,51 @@ elm_widget_focus_list_next_get(const Evas_Object *obj,
    if (!items)
      return EINA_FALSE;
 
+   /* When Up, Down, Right, or Left, try direction_get first. */
+   focused_object = elm_widget_focused_object_get(obj);
+   if (focused_object)
+     {
+        if((dir == ELM_FOCUS_UP)
+           || (dir == ELM_FOCUS_DOWN)
+           || (dir == ELM_FOCUS_RIGHT)
+           || (dir == ELM_FOCUS_LEFT))
+          {
+             *next = elm_widget_focus_next_object_get(focused_object, dir);
+             if (*next)
+               return EINA_TRUE;
+             else
+               {
+                  Evas_Object *n;
+                  double degree;
+                  double weight;
+
+                  if (dir == ELM_FOCUS_UP) degree = 0.0;
+                  else if (dir == ELM_FOCUS_DOWN) degree = 180.0;
+                  else if (dir == ELM_FOCUS_RIGHT) degree = 90.0;
+                  else if (dir == ELM_FOCUS_LEFT) degree = 270.0;
+
+                  if (elm_widget_focus_list_direction_get(obj, focused_object,
+                                                          items, list_data_get,
+                                                          degree, &n, &weight))
+                    {
+                       *next = n;
+                       return EINA_TRUE;
+                    }
+               }
+          }
+     }
+
    /* Direction */
    if (dir == ELM_FOCUS_PREVIOUS)
      {
         items = eina_list_last(items);
         list_next = eina_list_prev;
      }
-   else if (dir == ELM_FOCUS_NEXT)
+   else if ((dir == ELM_FOCUS_NEXT)
+            || (dir == ELM_FOCUS_UP)
+            || (dir == ELM_FOCUS_DOWN)
+            || (dir == ELM_FOCUS_RIGHT)
+            || (dir == ELM_FOCUS_LEFT))
      list_next = eina_list_next;
    else
      return EINA_FALSE;
@@ -2416,12 +2483,12 @@ elm_widget_focus_list_next_get(const Evas_Object *obj,
    const Eina_List *l = items;
 
    /* Recovery last focused sub item */
-   if (elm_widget_focus_get(obj))
+   if (ELM_WIDGET_FOCUS_GET(obj))
      {
         for (; l; l = list_next(l))
           {
              Evas_Object *cur = list_data_get(l);
-             if (elm_widget_focus_get(cur)) break;
+             if (ELM_WIDGET_FOCUS_GET(cur)) break;
           }
 
          /* Focused object, but no focused sub item */
@@ -2447,6 +2514,17 @@ elm_widget_focus_list_next_get(const Evas_Object *obj,
              *next = tmp;
              return EINA_TRUE;
           }
+        else if ((dir == ELM_FOCUS_UP)
+                 || (dir == ELM_FOCUS_DOWN)
+                 || (dir == ELM_FOCUS_RIGHT)
+                 || (dir == ELM_FOCUS_LEFT))
+          {
+             if (tmp && elm_widget_focus_get(cur))
+               {
+                  *next = tmp;
+                  return EINA_FALSE;
+               }
+          }
         else if ((tmp) && (!to_focus))
           to_focus = tmp;
      }
@@ -2475,6 +2553,100 @@ elm_widget_focus_list_next_get(const Evas_Object *obj,
    return EINA_FALSE;
 }
 
+
+/**
+ * @internal
+ *
+ * Get next object which was set with specific focus direction.
+ *
+ * Get next object which was set by elm_widget_focus_next_object_set
+ * with specific focus directioin.
+ *
+ * @param obj The widget
+ * @param dir Direction of focus
+ * @return Widget which was registered with sepecific focus direction.
+ *
+ * @ingroup Widget
+ */
+EAPI Evas_Object *
+elm_widget_focus_next_object_get(const Evas_Object *obj, Elm_Focus_Direction dir)
+{
+   API_ENTRY return NULL;
+
+   if (dir == ELM_FOCUS_PREVIOUS)
+     return sd->focus_previous;
+   else if (dir == ELM_FOCUS_NEXT)
+     return sd->focus_next;
+   else if (dir == ELM_FOCUS_UP)
+     return sd->focus_up;
+   else if (dir == ELM_FOCUS_DOWN)
+     return sd->focus_down;
+   else if (dir == ELM_FOCUS_RIGHT)
+     return sd->focus_right;
+   else if (dir == ELM_FOCUS_LEFT)
+     return sd->focus_left;
+
+   return NULL;
+}
+
+/**
+ * @internal
+ *
+ * Set next object with specific focus direction.
+ *
+ * When a widget is set with specific focus direction, this widget will be
+ * the first candidate when finding the next focus object.
+ * Focus next object can be registered with six directions that are previous,
+ * next, up, down, right, and left.
+ *
+ * @param obj The widget
+ * @param next Next focus object
+ * @param dir Direction of focus
+ *
+ * @ingroup Widget
+ */
+EAPI void
+elm_widget_focus_next_object_set(Evas_Object *obj, Evas_Object *next, Elm_Focus_Direction dir)
+{
+   API_ENTRY return;
+
+   if (dir == ELM_FOCUS_PREVIOUS)
+     sd->focus_previous = next;
+   else if (dir == ELM_FOCUS_NEXT)
+     sd->focus_next = next;
+   else if (dir == ELM_FOCUS_UP)
+     sd->focus_up = next;
+   else if (dir == ELM_FOCUS_DOWN)
+     sd->focus_down = next;
+   else if (dir == ELM_FOCUS_RIGHT)
+     sd->focus_right = next;
+   else if (dir == ELM_FOCUS_LEFT)
+     sd->focus_left = next;
+}
+
+
+EAPI Eina_Bool
+elm_widget_highlight_get(const Evas_Object *obj)
+{
+   API_ENTRY return EINA_FALSE;
+   return sd->highlighted;
+}
+
+EAPI void
+elm_widget_parent_highlight_set(Evas_Object *obj,
+                                Eina_Bool highlighted)
+{
+   API_ENTRY return;
+
+   highlighted = !!highlighted;
+
+   Evas_Object *o = elm_widget_parent_get(obj);
+
+   if (o) elm_widget_parent_highlight_set(o, highlighted);
+
+   sd->highlighted = highlighted;
+}
+
 EAPI void
 elm_widget_signal_emit(Evas_Object *obj,
                        const char *emission,
@@ -2616,6 +2788,10 @@ elm_widget_focused_object_clear(Evas_Object *obj)
    if (!sd->api) return;
 
    if (!sd->focused) return;
+
+   // FIXME: evas_object_ref/unref is temporary code to fix logical issue.
+   // After Eo is applied to elementary, remove these.
+   evas_object_ref(obj);
    if (sd->resize_obj && elm_widget_focus_get(sd->resize_obj))
      elm_widget_focused_object_clear(sd->resize_obj);
    else
@@ -2633,6 +2809,7 @@ elm_widget_focused_object_clear(Evas_Object *obj)
      }
    sd->focused = EINA_FALSE;
    sd->api->on_focus(obj);
+   evas_object_unref(obj);
 }
 
 EAPI void
@@ -2695,7 +2872,7 @@ elm_widget_focus_restore(Evas_Object *obj)
    unsigned int newest_focus_order = 0;
    API_ENTRY return;
 
-   newest = _newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE);
+   newest = elm_widget_newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE);
    if (newest)
      {
         elm_object_focus_set(newest, EINA_FALSE);
@@ -3070,35 +3247,32 @@ elm_widget_text_part_get(const Evas_Object *obj,
    return NULL;
 }
 
-EAPI void
-elm_widget_domain_translatable_text_part_set(Evas_Object *obj,
-                                             const char *part,
-                                             const char *domain,
-                                             const char *label)
+static Eina_Bool
+_translatable_part_text_set(Eina_List **translate_strings, const char *part, const char *domain, const char *label)
 {
    const char *str;
-   Eina_List *l;
+   Eina_List *t, *l;
    Elm_Translate_String_Data *ts = NULL;
-   API_ENTRY return;
 
+   t = *translate_strings;
    str = eina_stringshare_add(part);
-   EINA_LIST_FOREACH(sd->translate_strings, l, ts)
-     if (ts->id == str)
-       break;
-     else
-       ts = NULL;
+   EINA_LIST_FOREACH(t, l, ts)
+     {
+        if (ts->id == str) break;
+        else ts = NULL;
+     }
 
    if (!ts && !label)
      eina_stringshare_del(str);
    else if (!ts)
      {
         ts = malloc(sizeof(Elm_Translate_String_Data));
-        if (!ts) return;
+        if (!ts) return EINA_FALSE;
 
         ts->id = str;
         ts->domain = eina_stringshare_add(domain);
         ts->string = eina_stringshare_add(label);
-        sd->translate_strings = eina_list_append(sd->translate_strings, ts);
+        t = eina_list_append(t, ts);
      }
    else
      {
@@ -3109,8 +3283,7 @@ elm_widget_domain_translatable_text_part_set(Evas_Object *obj,
           }
         else
           {
-             sd->translate_strings = eina_list_remove_list(
-                 sd->translate_strings, l);
+             t = eina_list_remove_list(t, l);
              eina_stringshare_del(ts->id);
              eina_stringshare_del(ts->domain);
              eina_stringshare_del(ts->string);
@@ -3119,6 +3292,20 @@ elm_widget_domain_translatable_text_part_set(Evas_Object *obj,
         eina_stringshare_del(str);
      }
 
+   *translate_strings = t;
+   return EINA_TRUE;
+}
+
+EAPI void
+elm_widget_domain_translatable_part_text_set(Evas_Object *obj,
+                                             const char *part,
+                                             const char *domain,
+                                             const char *label)
+{
+   API_ENTRY return;
+
+   if (!_translatable_part_text_set(&sd->translate_strings, part, domain,
+                                    label)) return;
 #ifdef HAVE_GETTEXT
    if (label && label[0])
      label = dgettext(domain, label);
@@ -3126,26 +3313,33 @@ elm_widget_domain_translatable_text_part_set(Evas_Object *obj,
    elm_widget_text_part_set(obj, part, label);
 }
 
-EAPI const char *
-elm_widget_translatable_text_part_get(const Evas_Object *obj,
-                                      const char *part)
+static const char *
+_translatable_part_text_get(Eina_List *translate_strings, const char *part)
 {
-   const char *str, *ret = NULL;
-   Eina_List *l;
    Elm_Translate_String_Data *ts;
-   API_ENTRY return NULL;
+   const char*ret = NULL, *str;
+   Eina_List *l;
 
    str = eina_stringshare_add(part);
-   EINA_LIST_FOREACH(sd->translate_strings, l, ts)
+   EINA_LIST_FOREACH(translate_strings, l, ts)
      if (ts->id == str)
        {
           ret = ts->string;
           break;
        }
    eina_stringshare_del(str);
+
    return ret;
 }
 
+EAPI const char *
+elm_widget_translatable_part_text_get(const Evas_Object *obj,
+                                      const char *part)
+{
+   API_ENTRY return NULL;
+   return _translatable_part_text_get(sd->translate_strings, part);
+}
+
 EAPI void
 elm_widget_translate(Evas_Object *obj)
 {
@@ -3353,7 +3547,19 @@ elm_widget_theme_object_set(Evas_Object *obj,
                             const char *wstyle)
 {
    API_ENTRY return EINA_FALSE;
-   return _elm_theme_object_set(obj, edj, wname, welement, wstyle);
+   char buf[128];
+
+   if (!_elm_theme_object_set(obj, edj, wname, welement, wstyle))
+     return EINA_FALSE;
+
+   if (sd->orient_mode != -1)
+     {
+
+        snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode);
+        elm_widget_signal_emit(obj, buf, "elm");
+
+     }
+   return EINA_TRUE;
 }
 
 EAPI Eina_Bool
@@ -3458,6 +3664,62 @@ elm_widget_name_find(const Evas_Object *obj,
    return _widget_name_find(obj, name, recurse);
 }
 
+EAPI void
+elm_widget_orientation_mode_disabled_set(Evas_Object *obj, Eina_Bool disabled)
+{
+   int orient_mode = -1;
+
+   API_ENTRY return;
+
+   if (disabled && (sd->orient_mode == -1)) return;
+   if (!disabled && (sd->orient_mode != -1)) return;
+
+   if (!disabled)
+     {
+        //Get current orient mode from it's parent otherwise, 0.
+        sd->orient_mode = 0;
+        ELM_WIDGET_DATA_GET(sd->parent_obj, sd_parent);
+        if (!sd_parent) orient_mode = 0;
+        else orient_mode = sd_parent->orient_mode;
+     }
+   elm_widget_orientation_set(obj, orient_mode);
+}
+
+EAPI Eina_Bool
+elm_widget_orientation_mode_disabled_get(const Evas_Object *obj)
+{
+   Eina_Bool ret;
+
+   API_ENTRY return EINA_FALSE;
+
+   if (sd->orient_mode == -1) ret = EINA_TRUE;
+   else ret = EINA_FALSE;
+   return ret;
+}
+
+EAPI void
+elm_widget_orientation_set(Evas_Object *obj, int rotation)
+{
+   Evas_Object *child;
+   Eina_List *l;
+
+   API_ENTRY return;
+
+   if ((sd->orient_mode == rotation) || (sd->orient_mode == -1)) return;
+
+   sd->orient_mode = rotation;
+
+   EINA_LIST_FOREACH (sd->subobjs, l, child)
+     elm_widget_orientation_set(child, rotation);
+
+   if (rotation != -1)
+     {
+        char buf[128];
+        snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode);
+        elm_widget_signal_emit(obj, buf, "elm");
+     }
+}
+
 /**
  * @internal
  *
@@ -3553,6 +3815,42 @@ elm_widget_focus_order_get(const Evas_Object *obj)
    return sd->focus_order;
 }
 
+EAPI Evas_Object *
+elm_widget_newest_focus_order_get(const Evas_Object *obj,
+                                  unsigned int *newest_focus_order,
+                                  Eina_Bool can_focus_only)
+{
+   const Eina_List *l;
+   Evas_Object *child, *ret, *best;
+
+   API_ENTRY return NULL;
+
+   if (!evas_object_visible_get(obj)
+       || (elm_widget_disabled_get(obj))
+       || (elm_widget_tree_unfocusable_get(obj)))
+     return NULL;
+
+   best = NULL;
+   if (*newest_focus_order < sd->focus_order)
+     {
+        *newest_focus_order = sd->focus_order;
+        best = (Evas_Object *)obj;
+     }
+   EINA_LIST_FOREACH(sd->subobjs, l, child)
+     {
+        ret = elm_widget_newest_focus_order_get
+           (child, newest_focus_order, can_focus_only);
+        if (!ret) continue;
+        best = ret;
+     }
+   if (can_focus_only)
+     {
+        if ((!best) || (!elm_widget_can_focus_get(best)))
+          return NULL;
+     }
+   return best;
+}
+
 EAPI void
 elm_widget_activate(Evas_Object *obj, Elm_Activate act)
 {
@@ -3640,6 +3938,19 @@ elm_widget_display_mode_set(Evas_Object *obj, Evas_Display_Mode dispmode)
 
 }
 
+// temporary code. should be removed after eo is applied.
+EAPI void
+_elm_widget_orient_signal_emit(Evas_Object *obj)
+{
+   ELM_WIDGET_DATA_GET(obj, sd);
+   char buf[128];
+   if (sd->orient_mode > 0)
+     {
+        snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode);
+        elm_widget_signal_emit(obj, buf, "elm");
+     }
+}
+
 /**
  * @internal
  *
@@ -3682,6 +3993,9 @@ _elm_widget_item_new(Evas_Object *widget,
 EAPI void
 _elm_widget_item_free(Elm_Widget_Item *item)
 {
+   Elm_Translate_String_Data *ts;
+   Elm_Widget_Item_Signal_Data *wisd;
+
    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
 
    if (item->del_func)
@@ -3693,6 +4007,21 @@ _elm_widget_item_free(Elm_Widget_Item *item)
    if (item->access_info)
      eina_stringshare_del(item->access_info);
 
+   EINA_LIST_FREE(item->signals, wisd)
+     {
+        eina_stringshare_del(wisd->emission);
+        eina_stringshare_del(wisd->source);
+        free(wisd);
+     }
+
+   EINA_LIST_FREE(item->translate_strings, ts)
+     {
+        eina_stringshare_del(ts->id);
+        eina_stringshare_del(ts->domain);
+        eina_stringshare_del(ts->string);
+        free(ts);
+     }
+
    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
    free(item);
 }
@@ -3724,8 +4053,12 @@ _elm_widget_item_del(Elm_Widget_Item *item)
 
    //Widget item delete callback
    if (item->del_pre_func)
-      if (item->del_pre_func((Elm_Object_Item *)item))
-         _elm_widget_item_free(item);
+     {
+        if (item->del_pre_func((Elm_Object_Item *)item))
+          _elm_widget_item_free(item);
+     }
+   else
+     _elm_widget_item_free(item);
  }
 
 /**
@@ -3887,6 +4220,31 @@ _elm_widget_item_disable_hook_set(Elm_Widget_Item *item,
    item->disable_func = func;
 }
 
+EAPI void
+_elm_widget_item_domain_translatable_part_text_set(Elm_Widget_Item *item,
+                                                   const char *part,
+                                                   const char *domain,
+                                                   const char *label)
+{
+   ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
+
+   if (!_translatable_part_text_set(&item->translate_strings, part, domain,
+                                    label)) return;
+#ifdef HAVE_GETTEXT
+   if (label && label[0])
+     label = dgettext(domain, label);
+#endif
+   _elm_widget_item_part_text_set(item, part, label);
+}
+
+EAPI const char *
+_elm_widget_item_translatable_part_text_get(const Elm_Widget_Item *item,
+                                            const char *part)
+{
+   ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
+   return _translatable_part_text_get(item->translate_strings, part);
+}
+
 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
 
 struct _Elm_Widget_Item_Tooltip
@@ -4395,6 +4753,88 @@ _elm_widget_item_signal_emit_hook_set(Elm_Widget_Item *item,
    item->signal_emit_func = func;
 }
 
+
+static void
+_elm_widget_item_signal_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission,
+                           const char *source)
+{
+   Elm_Widget_Item_Signal_Data *wisd = data;
+   wisd->func(wisd->data, wisd->item, emission, source);
+}
+
+EAPI void
+_elm_widget_item_signal_callback_add(Elm_Widget_Item *item,
+                                     const char *emission,
+                                     const char *source,
+                                     Elm_Widget_Item_Signal_Cb func,
+                                     void *data)
+{
+   ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
+   EINA_SAFETY_ON_NULL_RETURN(func);
+
+   Elm_Widget_Item_Signal_Data *wisd;
+
+   wisd = malloc(sizeof(Elm_Widget_Item_Signal_Data));
+   if (!wisd) return;
+
+   wisd->item = item;
+   wisd->func = func;
+   wisd->data = data;
+   wisd->emission = eina_stringshare_add(emission);
+   wisd->source = eina_stringshare_add(source);
+
+   if (_elm_widget_is(item->view))
+     elm_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
+   else if (!strcmp(evas_object_type_get(item->view), "edje"))
+     edje_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
+   else
+     {
+        WRN("The %s widget item doesn't support signal callback add!",
+            evas_object_type_get(item->widget));
+        free(wisd);
+        return;
+     }
+
+   item->signals = eina_list_append(item->signals, wisd);
+}
+
+EAPI void *
+_elm_widget_item_signal_callback_del(Elm_Widget_Item *item,
+                                    const char *emission,
+                                    const char *source,
+                                    Elm_Widget_Item_Signal_Cb func)
+{
+   ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
+
+   Elm_Widget_Item_Signal_Data *wisd;
+   Eina_List *l;
+   void *data = NULL;
+
+   EINA_LIST_FOREACH(item->signals, l, wisd)
+     {
+        if ((wisd->func == func) && !strcmp(wisd->emission, emission) &&
+            !strcmp(wisd->source, source))
+          {
+             item->signals = eina_list_remove_list(item->signals, l);
+             eina_stringshare_del(wisd->emission);
+             eina_stringshare_del(wisd->source);
+             data = wisd->data;
+
+             if (_elm_widget_is(item->view))
+               elm_object_signal_callback_del(item->view, emission, source,
+                                              _elm_widget_item_signal_cb);
+             else if (!strcmp(evas_object_type_get(item->view), "edje"))
+               edje_object_signal_callback_del_full(item->view, emission,
+                                                    source,
+                                                    _elm_widget_item_signal_cb,
+                                                    data);
+          }
+     }
+
+   return data;
+}
+
 EAPI void
 _elm_widget_item_access_info_set(Elm_Widget_Item *item,
                                  const char *txt)