elm: genlist: enhance accessibility scroll & highlight
authorLukasz Stanislawski <l.stanislaws@samsung.com>
Tue, 14 Nov 2017 11:45:24 +0000 (12:45 +0100)
committerJiyoun Park <jy0703.park@samsung.com>
Thu, 21 Dec 2017 01:12:27 +0000 (10:12 +0900)
Conflicts:
src/lib/elm_widget_genlist.h

@tizen_feature

original patch: 30d9a6012e629cd9ea60eae8d576f3ebb94ada86

Change-Id: Idbf0d08f7cecf3d903024971fa8e0f1d775c35c6

src/lib/elementary/elm_genlist.c
src/lib/elementary/elm_genlist.eo
src/lib/elementary/elm_genlist_item.eo
src/lib/elementary/elm_widget_genlist.h

index 664bee7..6b79408 100644 (file)
@@ -6,7 +6,10 @@
 
 #define EFL_ACCESS_PROTECTED
 #define EFL_ACCESS_SELECTION_PROTECTED
-#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
+//TIZEN_ONLY(20171114) genlist: enhance accessibility scroll & highlight
+#define EFL_ACCESS_COMPONENT_PROTECTED
+//
+#define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED
 #define ELM_WIDGET_ITEM_PROTECTED
 #define EFL_UI_FOCUS_COMPOSITION_PROTECTED
 
@@ -2045,6 +2048,13 @@ _item_realize(Elm_Gen_Item *it, const int index, Eina_Bool calc)
    if (it->decorate_it_set) _decorate_item_set(it);
 
    edje_object_message_signal_process(VIEW(it));
+   //TIZEN_ONLY(20171114) genlist: enhance accessibility scroll & highlight
+   if (sd->atspi_item_to_highlight == it)
+     {
+       sd->atspi_item_to_highlight = NULL;
+       efl_access_component_highlight_grab(efl_super(EO_OBJ(it), ELM_GENLIST_ITEM_CLASS));
+     }
+   //
 }
 
 static void
@@ -8809,6 +8819,169 @@ ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(elm_genlist, Elm_Genlist_Data)
 #define ELM_GENLIST_PAN_EXTRA_OPS \
    EFL_CANVAS_GROUP_DEL_OPS(elm_genlist_pan)
 
+//TIZEN_ONLY(20171114) genlist: enhance accessibility scroll & highlight
+static int _is_item_in_viewport(int viewport_y, int viewport_h, int obj_y, int obj_h)
+{
+    if ((obj_y + obj_h/2) < viewport_y)
+      return 1;
+    else if ((obj_y + obj_h/2) > viewport_y + viewport_h)
+      return -1;
+    return 0;
+}
+
+static Eina_Bool _atspi_enabled()
+{
+    Eo *bridge = NULL;
+    Eina_Bool ret = EINA_FALSE;
+    if (_elm_config->atspi_mode && (bridge = _elm_atspi_bridge_get()))
+      ret = elm_obj_atspi_bridge_connected_get(bridge);
+    return ret;
+}
+
+EOLIAN static void
+_elm_genlist_elm_interface_scrollable_content_pos_set(Eo *obj, Elm_Genlist_Data *sid EINA_UNUSED, Evas_Coord x, Evas_Coord y, Eina_Bool sig)
+{
+    if (!_atspi_enabled())
+      {
+        elm_interface_scrollable_content_pos_set(efl_super(obj, MY_CLASS), x, y, sig);
+        return;
+      }
+
+    int old_x, old_y, delta_y;
+    elm_interface_scrollable_content_pos_get(efl_super(obj, MY_CLASS), &old_x, &old_y);
+    elm_interface_scrollable_content_pos_set(efl_super(obj, MY_CLASS), x, y, sig);
+    delta_y = old_y - y;
+
+    //check if highlighted item is genlist descendant
+    Evas_Object *win = elm_object_top_widget_get(obj);
+    Evas_Object *highlighted_obj = _elm_win_accessibility_highlight_get(win);
+    Evas_Object *parent = highlighted_obj;
+    if (efl_isa(highlighted_obj, ELM_WIDGET_CLASS))
+      {
+        while ((parent = elm_widget_parent_get(parent)))
+          if (parent == obj)
+            break;
+      }
+    else if (efl_isa(highlighted_obj, EDJE_OBJECT_CLASS))
+      {
+        while ((parent = evas_object_smart_parent_get(parent)))
+          if (parent == obj)
+            break;
+      }
+    if (parent)
+      {
+        int obj_x, obj_y, w, h, hx, hy, hw, hh;
+        evas_object_geometry_get(obj, &obj_x, &obj_y, &w, &h);
+
+        evas_object_geometry_get(highlighted_obj, &hx, &hy, &hw, &hh);
+
+        Elm_Gen_Item * next_previous_item = NULL;
+        int viewport_position_result = _is_item_in_viewport(obj_y, h, hy, hh);
+        //only highlight if move direction is correct
+        //sometimes highlighted item is brought in and it does not fit viewport
+        //however content goes to the viewport position so soon it will
+        //meet _is_item_in_viewport condition
+        if ((viewport_position_result < 0 && delta_y > 0) ||
+            (viewport_position_result > 0 && delta_y < 0))
+          {
+
+              Eina_List *realized_items = elm_genlist_realized_items_get(obj);
+              Eo *item;
+              Eina_List *l;
+              Eina_Bool traverse_direction = viewport_position_result > 0;
+              l = traverse_direction ? realized_items: eina_list_last(realized_items);
+
+              while(l)
+                {
+                  item = eina_list_data_get(l);
+                  ELM_GENLIST_ITEM_DATA_GET(item, it_data);
+                  next_previous_item = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it_data));
+                  evas_object_geometry_get(VIEW(next_previous_item), &hx, &hy, &hw, &hh);
+                  if (_is_item_in_viewport(obj_y, h, hy, hh) == 0)
+                    break;
+
+                  next_previous_item = NULL;
+
+                  l = traverse_direction ? eina_list_next(l): eina_list_prev(l);
+              }
+          }
+        if (next_previous_item)
+          efl_access_component_highlight_grab(EO_OBJ(next_previous_item));
+      }
+}
+
+EOLIAN static Eina_Bool
+_elm_genlist_item_efl_access_component_highlight_grab(Eo *eo_it, Elm_Gen_Item *it)
+{
+  ELM_GENLIST_DATA_GET(WIDGET(it), sd);
+  Eina_Bool ret = EINA_TRUE;
+
+  // if item is realized check if in viewport
+  if (VIEW(it))
+    {
+        Evas_Coord wy, wh, y, h;
+        evas_object_geometry_get(WIDGET(it), NULL, &wy, NULL, &wh);
+        evas_object_geometry_get(VIEW(it), NULL, &y, NULL, &h);
+        int res = _is_item_in_viewport(wy, wh, y, h);
+        if (res > 0)
+          {
+            // new item is above current
+            elm_genlist_item_show(eo_it, ELM_GENLIST_ITEM_SCROLLTO_BOTTOM);
+          }
+        else if (res < 0)
+          {
+            // new item is below current
+            elm_genlist_item_show(eo_it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
+          }
+        else
+          elm_genlist_item_show(eo_it, ELM_GENLIST_ITEM_SCROLLTO_IN);
+      }
+  else // if item is not realized we should search if we are over or below viewport
+    {
+        Eina_List *realized;
+        int idx, top, bottom;
+        realized = elm_genlist_realized_items_get(WIDGET(it));
+        if (realized)
+          {
+            // index of realized element on top of viewport
+            top = elm_obj_genlist_item_index_get(eina_list_nth(realized, 0));
+            // index of realized element on bottom of viewport
+            bottom = elm_obj_genlist_item_index_get(eina_list_last_data_get(realized));
+            idx = elm_obj_genlist_item_index_get(eo_it);
+            eina_list_free(realized);
+            if (idx < top)
+              elm_genlist_item_show(eo_it, ELM_GENLIST_ITEM_SCROLLTO_BOTTOM);
+            else if (idx > bottom)
+              elm_genlist_item_show(eo_it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
+            else
+              elm_genlist_item_show(eo_it, ELM_GENLIST_ITEM_SCROLLTO_IN);
+          }
+    }
+
+  if (VIEW(it))
+    ret = efl_access_component_highlight_grab(efl_super(eo_it, ELM_GENLIST_ITEM_CLASS));
+  else
+    sd->atspi_item_to_highlight = it;//it will be highlighted when realized
+
+  efl_event_callback_call(WIDGET(it), EFL_ACCESS_EVENT_ACTIVE_DESCENDANT_CHANGED, eo_it);
+
+  return ret;
+}
+
+EOLIAN static Eina_Bool
+_elm_genlist_item_efl_access_component_highlight_clear(Eo *eo_it, Elm_Gen_Item *it)
+{
+  Eina_Bool ret;
+  ELM_GENLIST_DATA_GET(WIDGET(it), sd);
+  if (sd->atspi_item_to_highlight == it)
+      sd->atspi_item_to_highlight = NULL;
+
+  efl_event_callback_call(WIDGET(it), EFL_ACCESS_EVENT_ACTIVE_DESCENDANT_CHANGED, eo_it);
+
+  ret = efl_access_component_highlight_clear(efl_super(eo_it, ELM_GENLIST_ITEM_CLASS));
+  return ret;
+}
+//
 #include "elm_genlist.eo.c"
 #include "elm_genlist_pan.eo.c"
 #include "elm_genlist_item.eo.c"
index 1c5d74c..fa33206 100644 (file)
@@ -546,7 +546,7 @@ class Elm.Genlist (Efl.Ui.Layout, Efl.Ui.Focus.Composition, Elm.Interface_Scroll
       Elm.Interface_Scrollable.policy { get; set; }
       Efl.Access.children { get; }
       Efl.Access.state_set { get; }
-      Efl.Access.Widget.Action.elm_actions { get; }
+      Elm.Interface.Atspi_Widget_Action.elm_actions { get; }
       Efl.Access.Selection.selected_children_count { get; }
       Efl.Access.Selection.selected_child { get; }
       Efl.Access.Selection.selected_child_deselect;
index 64fb098..00aa8ad 100644 (file)
@@ -462,5 +462,9 @@ class Elm.Genlist.Item(Elm.Widget.Item.Static_Focus)
            Efl.Access.name { get; }
            Efl.Access.state_set { get; }
            Efl.Ui.Focus.Object.prepare_logical;
+           //TIZEN_ONLY(20171114) genlist: enhance accessibility scroll & highlight
+           Efl.Access.Component.highlight_grab;
+           Efl.Access.Component.highlight_clear;
+           //
       }
 }
index 69c0cb5..ebbeda0 100644 (file)
@@ -152,6 +152,10 @@ struct _Elm_Genlist_Data
    Eina_Hash                            *content_item_map;
    Eo                                   *provider;
 
+   //TIZEN_ONLY(20171114) genlist: enhance accessibility scroll & highlight
+   Elm_Gen_Item                         *atspi_item_to_highlight;
+   //
+
    Eina_Bool                             filter;
    Eina_Bool                             focus_on_selection_enabled : 1;
    Eina_Bool                             tree_effect_enabled : 1;