list: Add item loop feature
authorHosang Kim <hosang12.kim@samsung.com>
Mon, 24 Mar 2014 08:35:07 +0000 (17:35 +0900)
committerDaniel Juyung Seo <seojuyung2@gmail.com>
Mon, 24 Mar 2014 08:35:07 +0000 (17:35 +0900)
Summary:
If item loop feature is enabled, item is moved infinitely.

1. add new widget api - item_loop_enabled
2. add smart event using new config - elm_list.c
3. add demo - test_list.c/list_focus

Reviewers: seoz, woohyun, raster, jaehwan, Hermet

CC: singh.amitesh, c
Differential Revision: https://phab.enlightenment.org/D619

data/themes/edc/elm/scroller.edc
src/bin/test_list.c
src/lib/elm_list.c
src/lib/elm_main.c
src/lib/elm_scroll.h
src/lib/elm_widget.c
src/lib/elm_widget.eo
src/lib/elm_widget.h
src/lib/elm_widget_list.h

index 9898161..0c72146 100644 (file)
@@ -769,6 +769,14 @@ group { name: "elm/scroller/base/default";
             visible: 1;
          }
       }
+      part { name: "dim_effect"; type: RECT; mouse_events: 0;
+         description { state: "default" 0.0;
+            color: 0 0 0 0;
+         }
+         description { state: "effect" 0.0;
+            color: 50 50 50 255;
+         }
+      }
    }
    programs {
       program {
@@ -803,6 +811,70 @@ group { name: "elm/scroller/base/default";
          target: "glow_hbar";
          target: "center_glow_hbar";
       }
+      program {
+         signal: "elm,action,looping,left"; source: "elm";
+         action: STATE_SET "effect" 0.0;
+         transition: LINEAR 0.3;
+         target: "dim_effect";
+         after: "looping,left,done";
+      }
+      program { name: "looping,left,done";
+         action: SIGNAL_EMIT "elm,looping,left,done" "elm";
+      }
+      program {
+         signal: "elm,action,looping,left,end"; source: "elm";
+         action: STATE_SET "default" 0.0;
+         transition: LINEAR 0.3;
+         target: "dim_effect";
+      }
+      program {
+         signal: "elm,action,looping,right"; source: "elm";
+         action: STATE_SET "effect" 0.0;
+         transition: LINEAR 0.3;
+         target: "dim_effect";
+         after: "looping,right,done";
+      }
+      program { name: "looping,right,done";
+         action: SIGNAL_EMIT "elm,looping,right,done" "elm";
+      }
+      program {
+         signal: "elm,action,looping,right,end"; source: "elm";
+         action: STATE_SET "default" 0.0;
+         transition: LINEAR 0.3;
+         target: "dim_effect";
+      }
+      program {
+         signal: "elm,action,looping,up"; source: "elm";
+         action: STATE_SET "effect" 0.0;
+         transition: LINEAR 0.3;
+         target: "dim_effect";
+         after: "looping,up,done";
+      }
+      program { name: "looping,up,done";
+         action: SIGNAL_EMIT "elm,looping,up,done" "elm";
+      }
+      program {
+         signal: "elm,action,looping,up,end"; source: "elm";
+         action: STATE_SET "default" 0.0;
+         transition: LINEAR 0.3;
+         target: "dim_effect";
+      }
+      program {
+         signal: "elm,action,looping,down"; source: "elm";
+         action: STATE_SET "effect" 0.0;
+         transition: LINEAR 0.3;
+         target: "dim_effect";
+         after: "looping,down,done";
+      }
+      program { name: "looping,down,done";
+         action: SIGNAL_EMIT "elm,looping,down,done" "elm";
+      }
+      program {
+         signal: "elm,action,looping,down,end"; source: "elm";
+         action: STATE_SET "default" 0.0;
+         transition: LINEAR 0.3;
+         target: "dim_effect";
+      }
    }
 }
 
index d864860..faa7a05 100644 (file)
@@ -1310,6 +1310,14 @@ test_list_focus_focus_move_policy_changed(void *data EINA_UNUSED,
 }
 
 static void
+test_list_focus_item_loop_enable_check_changed(void *data, Evas_Object *obj,
+                                               void *event_info  EINA_UNUSED)
+{
+   Evas_Object *li = data;
+   elm_object_scroll_item_loop_enabled_set(li, elm_check_state_get(obj));
+}
+
+static void
 _item_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
 {
    printf("%s: %p\n", (char *)data, event_info);
@@ -1497,6 +1505,17 @@ _test_list_focus(const char *name, const char *title, Eina_Bool horiz)
 
    test_list_focus_focus_on_selection_set(li, chk, EINA_FALSE);
 
+   chk = elm_check_add(bx_opt);
+   elm_object_text_set(chk, "Item Looping Enable");
+   elm_check_state_set(chk, elm_object_scroll_item_loop_enabled_get(li));
+   evas_object_size_hint_weight_set(chk, EVAS_HINT_EXPAND, 0.0);
+   evas_object_smart_callback_add(chk, "changed",
+                                  test_list_focus_item_loop_enable_check_changed,
+                                  li);
+   elm_box_pack_end(bx_opt, chk);
+   evas_object_show(chk);
+
+   elm_box_pack_end(bx, bx_opt);
    // Focus Movement Policy
    fr = elm_frame_add(bx);
    elm_object_text_set(fr, "Focus Movement Policy");
@@ -1572,8 +1591,8 @@ _test_list_focus(const char *name, const char *title, Eina_Bool horiz)
         if (lhand > 4) lhand = 4;
         if (rhand > 4) rhand = 4;
         snprintf(buf, sizeof(buf), " %s / %s ",
-            _list_focus_names[lhand],
-            _list_focus_names[rhand]);
+                               _list_focus_names[lhand],
+                               _list_focus_names[rhand]);
 
         it = elm_list_item_append(li, buf,
                                   test_list_focus_content_get(li, lhand, horiz),
index aa0367a..9ae2eff 100644 (file)
@@ -334,6 +334,8 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
    Evas_Coord step_y = 0;
    Evas_Coord page_x = 0;
    Evas_Coord page_y = 0;
+   Evas_Coord minw = 0;
+   Evas_Coord minh = 0;
    Elm_List_Item *it = NULL;
    Eina_Bool sel_ret = EINA_FALSE;
 
@@ -346,7 +348,8 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
          elm_interface_scrollable_content_pos_get(&x, &y),
          elm_interface_scrollable_step_size_get(&step_x, &step_y),
          elm_interface_scrollable_page_size_get(&page_x, &page_y),
-         elm_interface_scrollable_content_viewport_size_get(&v_w, &v_h));
+         elm_interface_scrollable_content_viewport_size_get(&v_w, &v_h),
+         elm_interface_scrollable_content_size_get(&minw, &minh));
 
    /* TODO: fix logic for horizontal mode */
    if ((!strcmp(ev->key, "Left")) ||
@@ -369,6 +372,24 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
                   if (ret) *ret = EINA_TRUE;
                   return;
                }
+             else
+               {
+                  if (sd->item_loop_enable)
+                    {
+                       if (minw > v_w)
+                         {
+                            elm_layout_signal_emit(obj, "elm,action,looping,left", "elm");
+                         }
+                       else
+                         {
+                            it = (Elm_List_Item *)elm_list_last_item_get(obj);
+                            elm_list_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
+                         }
+                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+                       if (ret) *ret = EINA_TRUE;
+                       return;
+                    }
+               }
           }
         if (ret) *ret = EINA_FALSE;
         return;
@@ -393,6 +414,24 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
                   if (ret) *ret = EINA_TRUE;
                   return;
                }
+             else
+               {
+                  if (sd->item_loop_enable)
+                    {
+                       if (minw > v_w)
+                         {
+                            elm_layout_signal_emit(obj, "elm,action,looping,right", "elm");
+                         }
+                       else
+                         {
+                            it = (Elm_List_Item *)elm_list_first_item_get(obj);
+                            elm_list_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
+                         }
+                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+                       if (ret) *ret = EINA_TRUE;
+                       return;
+                    }
+               }
           }
         if (ret) *ret = EINA_FALSE;
         return;
@@ -417,6 +456,24 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
                   if (ret) *ret = EINA_TRUE;
                   return;
                }
+             else
+               {
+                  if (sd->item_loop_enable)
+                    {
+                       if (minh > v_h)
+                         {
+                            elm_layout_signal_emit(obj, "elm,action,looping,up", "elm");
+                         }
+                       else
+                         {
+                            it = (Elm_List_Item *)elm_list_last_item_get(obj);
+                            elm_list_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
+                         }
+                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+                       if (ret) *ret = EINA_TRUE;
+                       return;
+                    }
+               }
           }
         if (ret) *ret = EINA_FALSE;
         return;
@@ -441,6 +498,24 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
                   if (ret) *ret = EINA_TRUE;
                   return;
                }
+             else
+               {
+                  if (sd->item_loop_enable)
+                    {
+                       if (minh > v_h)
+                         {
+                            elm_layout_signal_emit(obj, "elm,action,looping,down", "elm");
+                         }
+                       else
+                         {
+                            it = (Elm_List_Item *)elm_list_first_item_get(obj);
+                            elm_list_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
+                         }
+                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+                       if (ret) *ret = EINA_TRUE;
+                       return;
+                    }
+               }
           }
         if (ret) *ret = EINA_FALSE;
         return;
@@ -1622,6 +1697,58 @@ _mouse_up_cb(void *data,
 }
 
 static void
+_elm_list_looping_left_cb(void *data,
+                          Evas_Object *obj EINA_UNUSED,
+                          const char *emission EINA_UNUSED,
+                          const char *source EINA_UNUSED)
+{
+   Evas_Object *list = data;
+   Elm_List_Item *it = (Elm_List_Item *)elm_list_last_item_get(list);
+   elm_list_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
+   elm_object_item_focus_set((Elm_Object_Item *)it, EINA_TRUE);
+   elm_layout_signal_emit(list, "elm,action,looping,left,end", "elm");
+}
+
+static void
+_elm_list_looping_right_cb(void *data,
+                          Evas_Object *obj EINA_UNUSED,
+                          const char *emission EINA_UNUSED,
+                          const char *source EINA_UNUSED)
+{
+   Evas_Object *list = data;
+   Elm_List_Item *it = (Elm_List_Item *)elm_list_first_item_get(list);
+   elm_list_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
+   elm_object_item_focus_set((Elm_Object_Item *)it, EINA_TRUE);
+   elm_layout_signal_emit(list, "elm,action,looping,right,end", "elm");
+}
+
+static void
+_elm_list_looping_up_cb(void *data,
+                          Evas_Object *obj EINA_UNUSED,
+                          const char *emission EINA_UNUSED,
+                          const char *source EINA_UNUSED)
+{
+   Evas_Object *list = data;
+   Elm_List_Item *it = (Elm_List_Item *)elm_list_last_item_get(list);
+   elm_list_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
+   elm_object_item_focus_set((Elm_Object_Item *)it, EINA_TRUE);
+   elm_layout_signal_emit(list, "elm,action,looping,up,end", "elm");
+}
+
+static void
+_elm_list_looping_down_cb(void *data,
+                          Evas_Object *obj EINA_UNUSED,
+                          const char *emission EINA_UNUSED,
+                          const char *source EINA_UNUSED)
+{
+   Evas_Object *list = data;
+   Elm_List_Item *it = (Elm_List_Item *)elm_list_first_item_get(list);
+   elm_list_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
+   elm_object_item_focus_set((Elm_Object_Item *)it, EINA_TRUE);
+   elm_layout_signal_emit(list, "elm,action,looping,down,end", "elm");
+}
+
+static void
 _item_disable_hook(Elm_Object_Item *it)
 {
    Elm_List_Item *item = (Elm_List_Item *)it;
@@ -2133,6 +2260,11 @@ _elm_list_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
    evas_object_event_callback_add
      (priv->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
      _size_hints_changed_cb, obj);
+
+   edje_object_signal_callback_add(wd->resize_obj, "elm,looping,left,done", "elm", _elm_list_looping_left_cb, obj);
+   edje_object_signal_callback_add(wd->resize_obj, "elm,looping,right,done", "elm", _elm_list_looping_right_cb, obj);
+   edje_object_signal_callback_add(wd->resize_obj, "elm,looping,up,done", "elm", _elm_list_looping_up_cb, obj);
+   edje_object_signal_callback_add(wd->resize_obj, "elm,looping,down,done", "elm", _elm_list_looping_down_cb, obj);
 }
 
 static void
@@ -3177,6 +3309,25 @@ _elm_list_focused_item_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
 }
 
 static void
+_elm_list_item_loop_enabled_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+   Eina_Bool enable = va_arg(*list, int);
+   Elm_List_Smart_Data *sd = _pd;
+
+   if (sd->item_loop_enable == enable) return;
+   sd->item_loop_enable = !!enable;
+}
+
+static void
+_elm_list_item_loop_enabled_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+   Eina_Bool *ret = va_arg(*list, Eina_Bool *);
+   Elm_List_Smart_Data *sd = _pd;
+
+   if (ret) *ret = sd->item_loop_enable;
+}
+
+static void
 _class_constructor(Eo_Class *klass)
 {
       const Eo_Op_Func_Description func_desc[] = {
@@ -3200,6 +3351,8 @@ _class_constructor(Eo_Class *klass)
            EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_ACCESS), _elm_list_smart_access),
            EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_HIGHLIGHT_GEOMETRY_GET), _elm_list_focus_highlight_geometry_get),
            EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUSED_ITEM_GET), _elm_list_focused_item_get),
+           EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_ITEM_LOOP_ENABLED_SET), _elm_list_item_loop_enabled_set),
+           EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_ITEM_LOOP_ENABLED_GET), _elm_list_item_loop_enabled_get),
 
            EO_OP_FUNC(ELM_OBJ_LAYOUT_ID(ELM_OBJ_LAYOUT_SUB_ID_SIZING_EVAL), _elm_list_smart_sizing_eval),
 
index 4268811..aacc4f4 100644 (file)
@@ -1530,6 +1530,21 @@ elm_object_scroll_lock_y_get(const Evas_Object *obj)
    return elm_widget_drag_lock_y_get(obj);
 }
 
+EAPI void
+elm_object_scroll_item_loop_enabled_set(Evas_Object *obj,
+                                        Eina_Bool   enable)
+{
+   EINA_SAFETY_ON_NULL_RETURN(obj);
+   elm_widget_item_loop_enabled_set(obj, enable);
+}
+
+EAPI Eina_Bool
+elm_object_scroll_item_loop_enabled_get(const Evas_Object *obj)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
+   return elm_widget_item_loop_enabled_get(obj);
+}
+
 EAPI Eina_Bool
 elm_object_widget_check(const Evas_Object *obj)
 {
index 3d5546b..feb541c 100644 (file)
@@ -134,5 +134,34 @@ EAPI Eina_Bool elm_object_scroll_lock_x_get(const Evas_Object *obj);
 EAPI Eina_Bool elm_object_scroll_lock_y_get(const Evas_Object *obj);
 
 /**
+ * Enable item loop feature of the given widget
+ *
+ * If @p enable is @c EINA_TRUE, item selection/focus will loop internally.
+ * This means if arrow keys are pressed at end of scroller's item,
+ * screen is moved to opposite side.
+ *
+ * @param obj The object
+ * @param enable item loop feature (@c EINA_TRUE == enable, @c EINA_FALSE == disable)
+ *
+ * @see elm_object_scroll_item_loop_enabled_get()
+ * @since 1.10
+ * @ingroup Scrollitem
+ */
+EAPI void      elm_object_scroll_item_loop_enabled_set(Evas_Object *obj, Eina_Bool enable);
+
+/**
+ * Get the item loop enable status of the given widget
+ *
+ * This gets the item loop enabled status.
+ *
+ * @param obj The object
+ *
+ * @see elm_objecdt_scroll_item_enabled_set()
+ * @since 1.10
+ * @ingroup Scrollitem
+ */
+EAPI Eina_Bool elm_object_scroll_item_loop_enabled_get(const Evas_Object *obj);
+
+/**
  * @}
  */
index 4249d75..2ad01bd 100644 (file)
@@ -3406,6 +3406,18 @@ _elm_widget_drag_child_locked_y_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *
    return sd->child_drag_y_locked;
 }
 
+EOLIAN static void
+_elm_widget_item_loop_enabled_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd EINA_UNUSED, Eina_Bool enable EINA_UNUSED)
+{
+       return;
+}
+
+EOLIAN static Eina_Bool
+_elm_widget_item_loop_enabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd EINA_UNUSED)
+{
+       return EINA_FALSE;
+}
+
 EOLIAN static Eina_Bool
 _elm_widget_theme_object_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *edj, const char *wname, const char *welement, const char *wstyle)
 {
index 0a770fe..8bc1421 100644 (file)
@@ -317,6 +317,17 @@ abstract Elm_Widget (Evas_Smart)
             return int;
          }
       }
+      item_loop_enabled {
+         set {
+            /*@ Set enable or disable item loop feature. */
+         }
+         get {
+            /*@ Get the value whether item loop feature is enabled or not. */
+         }
+         values {
+            Eina_Bool enable;
+         }
+      }
       child_can_focus {
          get {
             /*@ No description supplied by the EAPI. */
index 9706cfd..da8c432 100644 (file)
@@ -727,6 +727,8 @@ EAPI Eina_Bool        elm_widget_drag_lock_x_get(const Evas_Object *obj);
 EAPI Eina_Bool        elm_widget_drag_lock_y_get(const Evas_Object *obj);
 EAPI int              elm_widget_drag_child_locked_x_get(const Evas_Object *obj);
 EAPI int              elm_widget_drag_child_locked_y_get(const Evas_Object *obj);
+EAPI void             elm_widget_item_loop_enabled_set(Evas_Object *obj, Eina_Bool enable);
+EAPI Eina_Bool        elm_widget_item_loop_enabled_get(const Evas_Object *obj);
 EAPI Eina_Bool        elm_widget_theme_object_set(Evas_Object *obj, Evas_Object *edj, const char *wname, const char *welement, const char *wstyle);
 EAPI Eina_Bool        elm_widget_type_check(const Evas_Object *obj, const char *type, const char *func);
 EAPI Evas_Object     *elm_widget_name_find(const Evas_Object *obj, const char *name, int recurse);
@@ -1281,6 +1283,8 @@ enum
    ELM_WIDGET_SUB_ID_DRAG_LOCK_Y_GET,
    ELM_WIDGET_SUB_ID_DRAG_CHILD_LOCKED_X_GET,
    ELM_WIDGET_SUB_ID_DRAG_CHILD_LOCKED_Y_GET,
+   ELM_WIDGET_SUB_ID_ITEM_LOOP_ENABLED_SET,
+   ELM_WIDGET_SUB_ID_ITEM_LOOP_ENABLED_GET,
 
    ELM_WIDGET_SUB_ID_EVENT_CALLBACK_ADD,
    ELM_WIDGET_SUB_ID_EVENT_CALLBACK_DEL,
@@ -2257,6 +2261,25 @@ enum
  */
 #define elm_wdg_drag_child_locked_y_get(ret) ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_DRAG_CHILD_LOCKED_Y_GET), EO_TYPECHECK(int *, ret)
 
+/**
+ * @def elm_wdg_item_loop_enabled_set
+ * @since 1.10
+ *
+ * Set enable or disable item loop feature.
+ *
+ * @param[in] enable
+ */
+#define elm_wdg_item_loop_enabled_set(enable) ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_ITEM_LOOP_ENABLED_SET), EO_TYPECHECK(Eina_Bool, enable)
+
+/**
+ * @def elm_wdg_item_loop_enabled_get
+ * @since 1.10
+ *
+ * Get the value whether item loop feature is enabled or not.
+ *
+ * @param[out] ret
+ */
+#define elm_wdg_item_loop_enabled_get(ret) ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_ITEM_LOOP_ENABLED_GET), EO_TYPECHECK(Eina_Bool *, ret)
 
 /**
  * @def elm_wdg_event_callback_add
index b6dfb9e..ddb0f42 100644 (file)
@@ -54,6 +54,7 @@ struct _Elm_List_Smart_Data
    Eina_Bool                             swipe : 1;
    Eina_Bool                             delete_me : 1;
    Eina_Bool                             mouse_down : 1; /**< a flag that mouse is down on the list at the moment. this flag is set to true on mouse and reset to false on mouse up */
+   Eina_Bool                             item_loop_enable : 1; /**< value whether item loop feature is enabled or not. */
 };
 
 typedef struct _Elm_List_Item Elm_List_Item;