[Scroller] Add the infinite loop feature.
authorJaehwan Kim <jae.hwan.kim@samsung.com>
Tue, 28 May 2013 07:16:12 +0000 (16:16 +0900)
committerSungho Kwak <sungho1.kwak@samsung.com>
Wed, 12 Jun 2013 05:17:09 +0000 (14:17 +0900)
Change-Id: I2f7db8a6513b654b94dedab4cd490bedff0758b1

src/lib/elm_interface_scrollable.c
src/lib/elm_interface_scrollable.h
src/lib/elm_scroller.c
src/lib/elm_scroller.h
src/lib/elm_widget_scroller.h

index 436a72a..540be30 100644 (file)
@@ -1359,39 +1359,51 @@ _elm_scroll_content_pos_set(Evas_Object *obj,
    _elm_scroll_content_viewport_size_get(obj, &ww, &wh); //// TIZEN ONLY
 
    psd->api->pos_get(sid->pan_obj, &px, &py);
+
+   if (sid->loop_h)
+     {
+        if (x <= 0) x = cw + (x % cw);
+        else if (x >= cw) x = (x % cw);
+     }
+   if (sid->loop_v)
+     {
+        if (y <= 0) y = ch + (y % ch);
+        else if (y >= ch) y = (y % ch);
+     }
+
 //// TIZEN ONLY
    if (cw > ww)
      {
         if (x < minx)
           edje_object_signal_emit(sid->edje_obj, "elm,edge,left", "elm");
-        if ((x - minx) > mx)
+        if (!sid->loop_h && (x - minx) > mx)
           edje_object_signal_emit(sid->edje_obj, "elm,edge,right", "elm");
      }
    if (ch > wh)
      {
         if (y < miny)
           edje_object_signal_emit(sid->edje_obj, "elm,edge,top", "elm");
-        if ((y - miny) > my)
+        if (!sid->loop_v && (y - miny) > my)
           edje_object_signal_emit(sid->edje_obj, "elm,edge,bottom", "elm");
      }
 //
    if (!_elm_config->thumbscroll_bounce_enable)
      {
         if (x < minx) x = minx;
-        if ((x - minx) > mx) x = mx + minx;
+        if (!sid->loop_h && (x - minx) > mx) x = mx + minx;
         if (y < miny) y = miny;
-        if ((y - miny) > my) y = my + miny;
+        if (!sid->loop_v && (y - miny) > my) y = my + miny;
      }
 
    if (!sid->bounce_horiz)
      {
         if (x < minx) x = minx;
-        if ((x - minx) > mx) x = mx + minx;
+        if (!sid->loop_h && ((x - minx) > mx)) x = mx + minx;
      }
    if (!sid->bounce_vert)
      {
         if (y < miny) y = miny;
-        if (y - miny > my) y = my + miny;
+        if (!sid->loop_v && ((y - miny) > my)) y = my + miny;
      }
 
    psd->api->pos_set(sid->pan_obj, x, y);
@@ -1416,7 +1428,7 @@ _elm_scroll_content_pos_set(Evas_Object *obj,
    edje_object_part_drag_value_set
      (sid->edje_obj, "elm.dragable.hbar", vx, 0.0);
 
-   if (!sid->down.bounce_x_animator)
+   if (!sid->loop_h && !sid->down.bounce_x_animator)
      {
         if (((x < minx) && (0 <= sid->down.dx)) ||
             ((x > (mx + minx)) && (0 >= sid->down.dx)))
@@ -1427,7 +1439,7 @@ _elm_scroll_content_pos_set(Evas_Object *obj,
         else
           sid->bouncemex = EINA_FALSE;
      }
-   if (!sid->down.bounce_y_animator)
+   if (!sid->loop_v && !sid->down.bounce_y_animator)
      {
         if (((y < miny) && (0 <= sid->down.dy)) ||
             ((y > (my + miny)) && (0 >= sid->down.dy)))
@@ -1894,12 +1906,12 @@ _elm_scroll_momentum_animator(void *data)
         if (!_elm_config->thumbscroll_bounce_enable || !sid->bounce_horiz)
           {
              if (x <= minx) no_bounce_x_end = EINA_TRUE;
-             if ((x - minx) >= maxx) no_bounce_x_end = EINA_TRUE;
+             if (!sid->loop_h && (x - minx) >= maxx) no_bounce_x_end = EINA_TRUE;
           }
         if (!_elm_config->thumbscroll_bounce_enable || !sid->bounce_vert)
           {
              if (y <= miny) no_bounce_y_end = EINA_TRUE;
-             if ((y - miny) >= maxy) no_bounce_y_end = EINA_TRUE;
+             if (!sid->loop_v && (y - miny) >= maxy) no_bounce_y_end = EINA_TRUE;
           }
         if ((dt >= 1.0) ||
             ((sid->down.bounce_x_hold) && (sid->down.bounce_y_hold)) ||
@@ -1960,7 +1972,7 @@ _elm_scroll_page_x_get(Elm_Scrollable_Smart_Interface_Data *sid,
         x = x / (sid->pagesize_h);
         x = x * (sid->pagesize_h);
      }
-   if ((x + w) > cw) x = cw - w;
+   if (!sid->loop_h && (x + w) > cw) x = cw - w;
    if (x < minx) x = minx;
 
    return x;
@@ -2002,7 +2014,7 @@ _elm_scroll_page_y_get(Elm_Scrollable_Smart_Interface_Data *sid,
         y = y / (sid->pagesize_v);
         y = y * (sid->pagesize_v);
      }
-   if ((y + h) > ch) y = ch - h;
+   if (!sid->loop_v && (y + h) > ch) y = ch - h;
    if (y < miny) y = miny;
 
    return y;
@@ -2628,7 +2640,7 @@ _elm_scroll_down_coord_eval(Elm_Scrollable_Smart_Interface_Data *sid,
      *x += (minx - *x) * _elm_config->thumbscroll_border_friction;
    else if (sid->content_info.w <= sid->w)
      *x += (sid->down.sx - *x) * _elm_config->thumbscroll_border_friction;
-   else if ((sid->content_info.w - sid->w + minx) < *x)
+   else if (!sid->loop_h && (sid->content_info.w - sid->w + minx) < *x)
      *x += (sid->content_info.w - sid->w + minx - *x) *
        _elm_config->thumbscroll_border_friction;
 
@@ -2636,7 +2648,7 @@ _elm_scroll_down_coord_eval(Elm_Scrollable_Smart_Interface_Data *sid,
      *y += (miny - *y) * _elm_config->thumbscroll_border_friction;
    else if (sid->content_info.h <= sid->h)
      *y += (sid->down.sy - *y) * _elm_config->thumbscroll_border_friction;
-   else if ((sid->content_info.h - sid->h + miny) < *y)
+   else if (!sid->loop_v && (sid->content_info.h - sid->h + miny) < *y)
      *y += (sid->content_info.h - sid->h + miny - *y) *
        _elm_config->thumbscroll_border_friction;
 }
@@ -2902,7 +2914,7 @@ _elm_scroll_mouse_move_event_cb(void *data,
                           else if (my <= 0)
                             y += (sid->down.sy - y) *
                               _elm_config->thumbscroll_border_friction;
-                          else if ((my + miny) < y)
+                          else if (!sid->loop_v && (my + miny) < y)
                             y += (my + miny - y) *
                               _elm_config->thumbscroll_border_friction;
                           if (x < minx)
@@ -2911,7 +2923,7 @@ _elm_scroll_mouse_move_event_cb(void *data,
                           else if (mx <= 0)
                             x += (sid->down.sx - x) *
                               _elm_config->thumbscroll_border_friction;
-                          else if ((mx + minx) < x)
+                          else if (!sid->loop_h && (mx + minx) < x)
                             x += (mx + minx - x) *
                               _elm_config->thumbscroll_border_friction;
                        }
@@ -4081,6 +4093,34 @@ _elm_scroll_gravity_get(const Evas_Object *obj,
    psd->api->gravity_get(sid->pan_obj, x, y);
 }
 
+
+static void
+_elm_scroll_loop_set(Evas_Object *obj,
+                              Eina_Bool loop_h,
+                              Eina_Bool loop_v)
+{
+   ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
+
+   if (sid->loop_h == loop_h &&
+       sid->loop_v == loop_v)
+     return;
+
+   sid->loop_h = loop_h;
+   sid->loop_v = loop_v;
+}
+
+static void
+_elm_scroll_loop_get(const Evas_Object *obj,
+                              Eina_Bool *loop_h,
+                              Eina_Bool *loop_v)
+{
+   ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
+
+   *loop_h = sid->loop_h;
+   *loop_v = sid->loop_v;
+}
+
+
 static Eina_Bool
 _elm_scroll_interface_add(Evas_Object *obj)
 {
@@ -4104,6 +4144,8 @@ _elm_scroll_interface_add(Evas_Object *obj)
    sid->vbar_flags = ELM_SCROLLER_POLICY_AUTO;
    sid->hbar_visible = EINA_TRUE;
    sid->vbar_visible = EINA_TRUE;
+   sid->loop_h = EINA_FALSE;
+   sid->loop_v = EINA_FALSE;
 
    sid->bounce_horiz = EINA_TRUE;
    sid->bounce_vert = EINA_TRUE;
@@ -4206,6 +4248,8 @@ EAPI const Elm_Scrollable_Smart_Interface ELM_SCROLLABLE_IFACE =
    _elm_scroll_region_bring_in,
    _elm_scroll_gravity_set,
    _elm_scroll_gravity_get,
+   _elm_scroll_loop_set,
+   _elm_scroll_loop_get,
    _elm_scroll_momentum_animator_disabled_get,
    _elm_scroll_momentum_animator_disabled_set,
    _elm_scroll_bounce_animator_disabled_set,
index e127ea6..1e2857b 100644 (file)
@@ -328,6 +328,8 @@ struct _Elm_Scrollable_Smart_Interface_Data
    Eina_Bool  go_right : 1;
    Eina_Bool  go_up : 1;
    Eina_Bool  go_down : 1;
+   Eina_Bool  loop_h : 1;
+   Eina_Bool  loop_v : 1;
 };
 
 typedef struct _Elm_Scrollable_Smart_Interface Elm_Scrollable_Smart_Interface;
@@ -527,6 +529,13 @@ struct _Elm_Scrollable_Smart_Interface
                              double *x,
                              double *y);
 
+   void       (*loop_set)(Evas_Object *obj,
+                                   Eina_Bool loop_h,
+                                   Eina_Bool loop_v);
+   void       (*loop_get)(const Evas_Object *obj,
+                                   Eina_Bool *loop_h,
+                                   Eina_Bool *loop_v);
+
    Eina_Bool  (*momentum_animator_disabled_get)(const Evas_Object *obj);
    void       (*momentum_animator_disabled_set)(Evas_Object *obj,
                                                 Eina_Bool disabled);
index 721c5c9..fbc8ec0 100644 (file)
@@ -314,6 +314,7 @@ _elm_scroller_smart_sizing_eval(Evas_Object *obj)
    Evas_Coord vw = 0, vh = 0, minw = 0, minh = 0, maxw = 0, maxh = 0, w, h,
               vmw, vmh;
    double xw = 0.0, yw = 0.0;
+   int i;
 
    ELM_SCROLLER_DATA_GET(obj, sd);
 
@@ -349,6 +350,11 @@ _elm_scroller_smart_sizing_eval(Evas_Object *obj)
      vh = minh;
 
    if (sd->content) evas_object_resize(sd->content, vw, vh);
+   if (sd->contents) evas_object_resize(sd->contents, vw, vh);
+
+   for (i = 0 ; i < 3 ; i++)
+     if (sd->proxy_content[i])
+       evas_object_image_fill_set(sd->proxy_content[i], 0, 0, vw, vh);
 
    w = -1;
    h = -1;
@@ -605,6 +611,71 @@ _scroll_drag_stop_cb(Evas_Object *obj,
    evas_object_smart_callback_call(obj, SIG_SCROLL_DRAG_STOP, NULL);
 }
 
+static void
+_loop_content_set(Evas_Object *obj, Evas_Object *content)
+{
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   if (!sd->contents)
+     {
+        sd->contents = elm_layout_add(obj);
+        evas_object_smart_member_add(sd->contents, obj);
+        elm_layout_theme_set(sd->contents, "scroller", "contents", elm_widget_style_get(obj));
+        evas_object_size_hint_weight_set(sd->contents, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(sd->contents, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+        elm_widget_sub_object_add(obj, sd->contents);
+        elm_widget_on_show_region_hook_set(sd->contents, _show_region_hook, obj);
+     }
+   elm_object_part_content_set(sd->contents, "elm.swallow.content", content);
+   sd->content = content;
+
+   if (sd->loop_h)
+     {
+        if (!sd->proxy_content[0])
+          {
+             sd->proxy_content[0] = evas_object_image_add(evas_object_evas_get(sd->contents));
+             evas_object_smart_member_add(sd->proxy_content[0], obj);
+             evas_object_size_hint_weight_set(sd->proxy_content[0], EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+             evas_object_size_hint_align_set(sd->proxy_content[0], EVAS_HINT_FILL, EVAS_HINT_FILL);
+          }
+        evas_object_image_source_set(sd->proxy_content[0], content);
+        evas_object_image_source_clip_set(sd->proxy_content[0], EINA_FALSE);
+        elm_object_part_content_set(sd->contents, "elm.swallow.content_r", sd->proxy_content[0]);
+        evas_object_show(sd->proxy_content[0]);
+     }
+
+   if (sd->loop_v)
+     {
+        if (!sd->proxy_content[1])
+          {
+             sd->proxy_content[1] = evas_object_image_add(evas_object_evas_get(sd->contents));
+             evas_object_smart_member_add(sd->proxy_content[1], obj);
+             evas_object_size_hint_weight_set(sd->proxy_content[1], EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+             evas_object_size_hint_align_set(sd->proxy_content[1], EVAS_HINT_FILL, EVAS_HINT_FILL);
+          }
+        evas_object_image_source_set(sd->proxy_content[1], content);
+        evas_object_image_source_clip_set(sd->proxy_content[1], EINA_FALSE);
+        elm_object_part_content_set(sd->contents, "elm.swallow.content_b", sd->proxy_content[1]);
+        evas_object_show(sd->proxy_content[1]);
+     }
+
+   if (sd->loop_h && sd->loop_v)
+     {
+        if (!sd->proxy_content[2])
+          {
+             sd->proxy_content[2] = evas_object_image_add(evas_object_evas_get(sd->contents));
+             evas_object_smart_member_add(sd->proxy_content[2], obj);
+             evas_object_size_hint_weight_set(sd->proxy_content[2], EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+             evas_object_size_hint_align_set(sd->proxy_content[2], EVAS_HINT_FILL, EVAS_HINT_FILL);
+          }
+        evas_object_image_source_set(sd->proxy_content[2], content);
+        evas_object_image_source_clip_set(sd->proxy_content[2], EINA_FALSE);
+        elm_object_part_content_set(sd->contents, "elm.swallow.content_rb", sd->proxy_content[2]);
+        evas_object_show(sd->proxy_content[2]);
+     }
+}
+
 static Eina_Bool
 _elm_scroller_smart_content_set(Evas_Object *obj,
                                 const char *part,
@@ -626,7 +697,16 @@ _elm_scroller_smart_content_set(Evas_Object *obj,
         elm_widget_on_show_region_hook_set(content, _show_region_hook, obj);
         elm_widget_sub_object_add(obj, content);
 
+        if (sd->loop_h || sd->loop_v)
+          {
+             _loop_content_set(obj, content);
+             if(sd->contents)
+               content = sd->contents;
+          }
         sd->s_iface->content_set(obj, content);
+
+        evas_object_event_callback_add
+           (sd->content, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints_cb, obj);
      }
 
    elm_layout_sizing_eval(obj);
@@ -1109,6 +1189,52 @@ elm_scroller_gravity_get(const Evas_Object *obj,
 }
 
 EAPI void
+elm_scroller_loop_set(Evas_Object *obj,
+                      Eina_Bool loop_h,
+                      Eina_Bool loop_v)
+{
+   ELM_SCROLLABLE_CHECK(obj);
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   if (sd->loop_h == loop_h && sd->loop_v == loop_v) return;
+
+   sd->loop_h = loop_h;
+   sd->loop_v = loop_v;
+
+   s_iface->loop_set(obj, loop_h, loop_v);
+
+   if (sd->content)
+     if (sd->loop_h || sd->loop_v)
+       {
+          sd->s_iface->content_set(obj, NULL);
+          _loop_content_set(obj, sd->content);
+
+          if (sd->contents)
+            {
+               sd->s_iface->content_set(obj, sd->contents);
+               elm_widget_sub_object_add(obj, sd->contents);
+               elm_widget_on_show_region_hook_set(sd->contents, _show_region_hook, obj);
+            }
+       }
+     else
+       {
+          sd->s_iface->content_set(obj, NULL);
+          sd->s_iface->content_set(obj, sd->content);
+       }
+   elm_layout_sizing_eval(obj);
+}
+
+EAPI void
+elm_scroller_loop_get(const Evas_Object *obj,
+                      Eina_Bool *loop_h,
+                      Eina_Bool *loop_v)
+{
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->loop_get(obj, loop_h, loop_v);
+}
+
+EAPI void
 elm_scroller_propagate_events_set(Evas_Object *obj,
                                   Eina_Bool propagation)
 {
index 4e1ce3e..5a893ac 100644 (file)
@@ -540,5 +540,38 @@ EAPI void                          elm_scroller_gravity_set(Evas_Object *obj, do
 EAPI void                          elm_scroller_gravity_get(const Evas_Object *obj, double *x, double *y);
 
 /**
+ * @brief Set the infinite loop for a scroller
+ *
+ * @param obj The scroller object
+ * @param loop_h The scrolling horizontal loop
+ * @param loop_v The scrolling vertical loop
+ *
+ * This sets infinite loop for a scroller.
+ *
+ * @since 1.8
+ *
+ * @ingroup Scroller
+ */
+EAPI void                          elm_scroller_loop_set(Evas_Object *obj, Eina_Bool loop_h, Eina_Bool loop_v);
+
+/**
+ * @brief Get the infinite loop for a scroller
+ *
+ * @param obj The scroller object
+ * @param loop_h The scrolling horizontal loop
+ * @param loop_v The scrolling vertical loop
+ *
+ * This gets infinite loop for a scroller.
+ *
+ * @see elm_scroller_loop_set()
+ *
+ * @since 1.8
+ *
+ * @ingroup Scroller
+ */
+
+EAPI void                          elm_scroller_loop_get(const Evas_Object *obj, Eina_Bool *loop_h, Eina_Bool *loop_v);
+
+/**
  * @}
  */
index 7b2241c..6bc3dbd 100644 (file)
@@ -132,9 +132,13 @@ struct _Elm_Scroller_Smart_Data
    Evas_Object                          *g_layer;
 
    Evas_Object                          *content;
+   Evas_Object                          *contents;
+   Evas_Object                          *proxy_content[3];
 
    Eina_Bool                             min_w : 1;
    Eina_Bool                             min_h : 1;
+   Eina_Bool                             loop_h : 1;
+   Eina_Bool                             loop_v : 1;
 };
 
 /**