commit 0459243bd4f73aa742f48a473b6b6d5726839781
Author: I-Fan, Chen <tick@openmoko.com>
Date:   Wed Nov 19 14:07:59 2008 +0800

    Adding STOPTOOBJECT bouncy flag for etk_scrolled_view

diff --git a/etk/src/bin/etk_tree_test.c b/etk/src/bin/etk_tree_test.c
index 86ad3f8..30c13b9 100644
--- a/etk/src/bin/etk_tree_test.c
+++ b/etk/src/bin/etk_tree_test.c
@@ -64,6 +64,9 @@ void etk_test_tree_window_create(void *data)
    /* Create the tree widget */
    tree = etk_tree_new();
    etk_tree_mode_set(ETK_TREE(tree), ETK_TREE_MODE_TREE);
+   etk_scrolled_view_extra_vmargin_set(etk_tree_scrolled_view_get(ETK_TREE(tree)), 250);
+   etk_scrolled_view_drag_bouncy_set(etk_tree_scrolled_view_get(ETK_TREE(tree)), ETK_BOUNCY_STOPTOOBJECT);
+   etk_scrolled_view_dragable_set(etk_tree_scrolled_view_get(ETK_TREE(tree)), ETK_TRUE);
    etk_tree_multiple_select_set(ETK_TREE(tree), ETK_TRUE);
    etk_widget_padding_set(tree, 5, 5, 5, 5);
    etk_box_append(ETK_BOX(vbox), tree, ETK_BOX_START, ETK_BOX_EXPAND_FILL, 0);
diff --git a/etk/src/lib/etk_scrolled_view.c b/etk/src/lib/etk_scrolled_view.c
index 991c44c..a015a1f 100644
--- a/etk/src/lib/etk_scrolled_view.c
+++ b/etk/src/lib/etk_scrolled_view.c
@@ -102,11 +102,17 @@ Etk_Type *etk_scrolled_view_type_get(void)
          ETK_PROPERTY_BOOL, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_bool(ETK_FALSE));
 
       etk_type_property_add(scrolled_view_type, "drag-bouncy", ETK_SCROLLED_VIEW_DRAG_BOUNCY_PROPERTY,
-         ETK_PROPERTY_BOOL, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_bool(ETK_TRUE));
+         ETK_PROPERTY_BOOL, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_int(ETK_BOUNCY_NOBOUNCE));
 
       etk_type_property_add(scrolled_view_type, "drag-damping", ETK_SCROLLED_VIEW_DRAG_DAMPING_PROPERTY,
          ETK_PROPERTY_INT, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_int(ETK_SCROLLED_VIEW_DRAG_DAMPING_MAGIC));
 
+      etk_type_property_add(scrolled_view_type, "hmargin", ETK_SCROLLED_VIEW_DRAG_BOUNCY_PROPERTY,
+         ETK_PROPERTY_BOOL, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_int(0));
+
+      etk_type_property_add(scrolled_view_type, "vmargin", ETK_SCROLLED_VIEW_DRAG_BOUNCY_PROPERTY,
+         ETK_PROPERTY_BOOL, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_int(0));
+
       etk_type_property_add(scrolled_view_type, "drag-sample-interval", ETK_SCROLLED_VIEW_DRAG_SAMPLE_INTERVAL_PROPERTY,
          ETK_PROPERTY_INT, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_int(ETK_SCROLLED_VIEW_DRAG_SAMPLE_INTERVAL_MAGIC));
 
@@ -250,9 +256,9 @@ Etk_Bool etk_scrolled_view_dragable_get(Etk_Scrolled_View *scrolled_view)
 /**
  * @brief Set the scrolled view boucy or not.
  * @param scrolled_view  a scrolled view
- * @param bouncy The scrolled view is bouncy or not (Default TRUE)
+ * @param bouncy The scrolled view is bouncy or not (Default NOBOUNCE)
  */ 
-void etk_scrolled_view_drag_bouncy_set(Etk_Scrolled_View *scrolled_view, Etk_Bool bouncy) 
+void etk_scrolled_view_drag_bouncy_set(Etk_Scrolled_View *scrolled_view, Etk_Scrolled_View_Bouncy_Policy bouncy) 
 {
    if (!scrolled_view || scrolled_view->drag.bouncy == bouncy)
       return;
@@ -264,9 +270,9 @@ void etk_scrolled_view_drag_bouncy_set(Etk_Scrolled_View *scrolled_view, Etk_Boo
 /**
  * @brief  Get the scrolled view bouncy flag
  * @param scrolled_view  a scrolled view
- * @return Returns ETK_TURE if the scrolled view is bouncy
+ * @return Returns bounce type
  */ 
-Etk_Bool etk_scrolled_view_drag_bouncy_get(Etk_Scrolled_View *scrolled_view) 
+Etk_Scrolled_View_Bouncy_Policy etk_scrolled_view_drag_bouncy_get(Etk_Scrolled_View *scrolled_view) 
 {
    if (!scrolled_view)
       return ETK_FALSE;
@@ -341,6 +347,8 @@ void etk_scrolled_view_extra_vmargin_set(Etk_Scrolled_View *scrolled_view, int m
       return;
    margin = margin > 0 ? margin : 0;
    scrolled_view->extra_vmargin = margin;
+   etk_widget_redraw_queue(ETK_WIDGET(scrolled_view));
+   etk_object_notify(ETK_OBJECT(scrolled_view), "vmargin");
 }
 
 /**
@@ -355,6 +363,7 @@ int etk_scrolled_view_extra_vmargin_get(Etk_Scrolled_View *scrolled_view)
    return scrolled_view->extra_vmargin;
 }
 
+
 /**
  * @brief Set the horizontal extra margin to the scrolled view
  * @param  scrolled_view a scrolled view
@@ -366,6 +375,8 @@ void etk_scrolled_view_extra_hmargin_set(Etk_Scrolled_View *scrolled_view, int m
       return;
    margin = margin > 0 ? margin : 0;
    scrolled_view->extra_hmargin = margin;
+   etk_widget_redraw_queue(ETK_WIDGET(scrolled_view));
+   etk_object_notify(ETK_OBJECT(scrolled_view), "hmargin");
 }
 
 /**
@@ -381,6 +392,7 @@ int etk_scrolled_view_extra_hmargin_get(Etk_Scrolled_View *scrolled_view)
    return scrolled_view->extra_hmargin;
 }
 
+
 /**************************
  *
  * Etk specific functions
@@ -401,7 +413,7 @@ static void _etk_scrolled_view_constructor(Etk_Scrolled_View *scrolled_view)
    scrolled_view->drag.mouse_down  = ETK_FALSE;
    scrolled_view->drag.bar_pressed = ETK_FALSE;
    scrolled_view->drag.dragable    = ETK_FALSE;
-   scrolled_view->drag.bouncy      = ETK_TRUE;
+   scrolled_view->drag.bouncy      = ETK_BOUNCY_NOBOUNCE;
    scrolled_view->drag.damping_magic = ETK_SCROLLED_VIEW_DRAG_DAMPING_MAGIC;
    scrolled_view->extra_hmargin    = 0;
    scrolled_view->extra_vmargin    = 0;
@@ -460,7 +472,7 @@ static void _etk_scrolled_view_property_set(Etk_Object *object, int property_id,
          etk_scrolled_view_dragable_set(scrolled_view, etk_property_value_bool_get(value));
          break;
        case ETK_SCROLLED_VIEW_DRAG_BOUNCY_PROPERTY:
-         etk_scrolled_view_drag_bouncy_set(scrolled_view, etk_property_value_bool_get(value));
+         etk_scrolled_view_drag_bouncy_set(scrolled_view, etk_property_value_int_get(value));
          break;
        case ETK_SCROLLED_VIEW_DRAG_DAMPING_PROPERTY:
          etk_scrolled_view_drag_damping_set(scrolled_view, etk_property_value_int_get(value));
@@ -493,7 +505,7 @@ static void _etk_scrolled_view_property_get(Etk_Object *object, int property_id,
          etk_property_value_bool_set(value, scrolled_view->drag.dragable);
          break;
        case ETK_SCROLLED_VIEW_DRAG_BOUNCY_PROPERTY:
-         etk_property_value_bool_set(value, scrolled_view->drag.bouncy);
+         etk_property_value_int_set(value, scrolled_view->drag.bouncy);
          break;
        case ETK_SCROLLED_VIEW_DRAG_DAMPING_PROPERTY:
          etk_property_value_int_set(value, scrolled_view->drag.damping_magic);
@@ -572,30 +584,22 @@ static void _etk_scrolled_view_size_allocate(Etk_Widget *widget, Etk_Geometry ge
 
    scrollview_size.w = geometry.w - child->inset.left - child->inset.right;
    scrollview_size.h = geometry.h - child->inset.top - child->inset.bottom;
-   if (child->scroll_margins_get)
-   {
-      Etk_Size margins_size;
-
-      child->scroll_margins_get(child, &margins_size);
-      scrollview_size.w -= margins_size.w;
-      scrollview_size.h -= margins_size.h;
-   }
 
    child->scroll_size_get(child, scrollview_size, scrollbar_size, &scroll_size);
 
    if ((scrolled_view->hpolicy == ETK_POLICY_AUTO 
-            && (scroll_size.w + 2 * scrolled_view->extra_hmargin) > scrollview_size.w)
+            && (scroll_size.w + (scrolled_view->extra_hmargin * 2)) > scrollview_size.w)
          || scrolled_view->hpolicy == ETK_POLICY_SHOW)
    {
       show_hscrollbar = ETK_TRUE;
    }
    if ((scrolled_view->vpolicy == ETK_POLICY_AUTO
-         && (scroll_size.h + 2 * scrolled_view->extra_vmargin) > (scrollview_size.h - (show_hscrollbar ? hscrollbar_size.h : 0) ))
+         && (scroll_size.h + (scrolled_view->extra_vmargin * 2)) > (scrollview_size.h - (show_hscrollbar ? hscrollbar_size.h : 0) ))
       || scrolled_view->vpolicy == ETK_POLICY_SHOW)
    {
       show_vscrollbar = ETK_TRUE;
       if (scrolled_view->hpolicy == ETK_POLICY_AUTO && 
-            (scroll_size.w + 2 * scrolled_view->extra_hmargin) > (scrollview_size.w - vscrollbar_size.w))
+            (scroll_size.w + (scrolled_view->extra_hmargin * 2)) > (scrollview_size.w - vscrollbar_size.w))
          show_hscrollbar = ETK_TRUE;
    }
 
@@ -636,6 +640,7 @@ static void _etk_scrolled_view_size_allocate(Etk_Widget *widget, Etk_Geometry ge
       etk_range_page_size_set(ETK_RANGE(scrolled_view->hscrollbar), scroll_size.w );
    else 
       etk_range_page_size_set(ETK_RANGE(scrolled_view->hscrollbar), scrollview_size.w );
+
    etk_range_range_set(ETK_RANGE(scrolled_view->vscrollbar), 
          0 - scrolled_view->extra_vmargin, 
          scroll_size.h + scrolled_view->extra_vmargin);
@@ -653,7 +658,7 @@ static void _etk_scrolled_view_size_allocate(Etk_Widget *widget, Etk_Geometry ge
 }
 
 /* Check if reaching the boundary */
-static inline double _etk_scrolled_view_bounce_check(Etk_Range * range, double delta,double v) 
+static inline double _etk_scrolled_view_bounce_check(Etk_Range * range, double delta, double v) 
 {
    double pos = (range->value + delta);
    if (pos <= range->lower) 
@@ -667,6 +672,58 @@ static inline double _etk_scrolled_view_bounce_check(Etk_Range * range, double d
    return v;
 }
 
+static inline void _speed_out_of_boundary(Etk_Range *range, unsigned int margin, double *delta_ptr, double *V_ptr)
+{
+   double delta = (*delta_ptr);
+   double V =  (*V_ptr);
+   double rate = 0;
+   double dV = 0 ;
+   if (range->value < ( range->lower + margin)) // Lower
+   {
+      if ( margin == 0 )
+      {
+         V = 0;
+         delta = 0;
+         etk_range_value_set(range, 0);
+      }
+      else 
+      {
+         rate = ((double)(margin-abs(range->value))/margin);
+         dV = 2 * margin * (1 - 1/(1+exp(-10*(2*(rate-0.3)-1)))) +10;
+         V = (V + dV) * 0.5;
+      }
+      if (range->value + delta > (range->lower + margin))
+      {
+         V = 0;
+         delta = 0;
+         etk_range_value_set(range, 0);
+      }
+   }
+   else if (range->value > (range->upper - range->page_size - margin)) 
+   {
+      if ( margin == 0 )
+      {
+         V = 0;
+         delta = 0;
+         etk_range_value_set(range, range->upper - range->page_size - margin);
+      }
+      else 
+      {
+         rate = 1 - ((double)(abs(range->value - (range->upper - range->page_size - margin)))/margin);
+         dV = 0 - 2 * margin * (1 - 1/(1+exp(-10*(2*(rate-0.3)-1)))) - 10;
+         V = (V + dV) * 0.5;
+      }
+      if (range->value + delta < (range->upper - range->page_size - margin))
+      {
+         V = 0;
+         delta = 0;
+         etk_range_value_set(range, (range->upper - range->page_size - margin));
+      }
+   }
+   *V_ptr = V;
+   *delta_ptr = delta;
+}
+
 /* Animator for inertial scrolling */
 static int _etk_scrolled_view_motive_bounce(void *data) 
 {
@@ -721,21 +778,30 @@ static int _etk_scrolled_view_motive_bounce(void *data)
       drag->Vy = drag->Vy + delta_V;
    }
 
-   if (drag->Vx == 0 && drag->Vy == 0) 
-      return 0;
-
    vscrollbar_range = ETK_RANGE(scrolled_view->vscrollbar);
    hscrollbar_range = ETK_RANGE(scrolled_view->hscrollbar);
-   if (drag->bouncy)  
+   if (drag->bouncy == ETK_BOUNCY_BOUNCE )  
    {
       drag->Vx = _etk_scrolled_view_bounce_check(hscrollbar_range, delta_x, drag->Vx);
       drag->Vy = _etk_scrolled_view_bounce_check(vscrollbar_range, delta_y, drag->Vy);
    }
-   else 
+   else if ( drag->bouncy == ETK_BOUNCY_STOPTOOBJECT ) 
+   {
+      _speed_out_of_boundary(hscrollbar_range, scrolled_view->extra_hmargin, &delta_x, &drag->Vx);
+      drag->Vx = _etk_scrolled_view_bounce_check(hscrollbar_range, delta_x, drag->Vx);
+
+      _speed_out_of_boundary(vscrollbar_range, scrolled_view->extra_vmargin, &delta_y, &drag->Vy);
+      drag->Vy = _etk_scrolled_view_bounce_check(vscrollbar_range, delta_y, drag->Vy);
+   }
+   else // default is NOBOUNCE   
    {
       drag->Vx = drag->Vx == _etk_scrolled_view_bounce_check(hscrollbar_range, delta_x, drag->Vx) ? drag->Vx : 0.0f;
       drag->Vy = drag->Vy == _etk_scrolled_view_bounce_check(vscrollbar_range, delta_y, drag->Vy) ? drag->Vy : 0.0f;
-   }
+   }   
+
+   if (drag->Vx == 0 && drag->Vy == 0) 
+      return 0;
+
    drag->timestamp = ecore_time_get();
    return 1;
 }
@@ -769,7 +835,7 @@ static Etk_Bool _etk_scrolled_view_key_down_cb(Etk_Object *object, Etk_Event_Key
    else if (strcmp(event->keyname, "Up") == 0)
       etk_range_value_set(vscrollbar_range, vscrollbar_range->value - vscrollbar_range->step_increment);
    else if (strcmp(event->keyname, "Home") == 0)
-      etk_range_value_set(vscrollbar_range, vscrollbar_range->lower + scrolled_view->extra_vmargin);
+      etk_range_value_set(vscrollbar_range, vscrollbar_range->lower - scrolled_view->extra_vmargin);
    else if (strcmp(event->keyname, "End") == 0)
       etk_range_value_set(vscrollbar_range, vscrollbar_range->upper);
    else if (strcmp(event->keyname, "Next") == 0)
@@ -866,10 +932,21 @@ static Etk_Bool _etk_scrolled_view_mouse_move(Etk_Object *object, Etk_Event_Mous
       {
          double _value = vscrollbar_range->value - (event->cur.widget.y - drag->position.y);
          if (_value > vscrollbar_range->lower && _value < vscrollbar_range->upper) {
+            if (_value < vscrollbar_range->lower + scrolled_view->extra_vmargin || 
+                  _value > vscrollbar_range->upper - vscrollbar_range->page_size - scrolled_view->extra_vmargin) 
+            {
+               _value = vscrollbar_range->value - (event->cur.widget.y - drag->position.y)*0.5;
+            }
             etk_range_value_set(vscrollbar_range, _value);
          }
          _value = hscrollbar_range->value - (event->cur.widget.x - drag->position.x);
          if (_value > hscrollbar_range->lower && _value < hscrollbar_range->upper) {
+            if (_value < hscrollbar_range->lower + scrolled_view->extra_hmargin || 
+                  _value > hscrollbar_range->upper - hscrollbar_range->page_size - scrolled_view->extra_hmargin) 
+            {
+               _value = hscrollbar_range->value - (event->cur.widget.x - drag->position.x)*0.5;
+            }
+
             etk_range_value_set(hscrollbar_range, _value);
          }
       }
@@ -908,6 +985,8 @@ static Etk_Bool _etk_scrolled_view_mouse_up(Etk_Object *object, Etk_Event_Mouse_
 {
    Etk_Scrolled_View *scrolled_view;
    struct Etk_Scrolled_View_Mouse_Drag *drag = (struct Etk_Scrolled_View_Mouse_Drag *) data;
+   Etk_Range *vscrollbar_range;
+   Etk_Range *hscrollbar_range;
 
    if (!(scrolled_view = ETK_SCROLLED_VIEW(object)))
       return ETK_FALSE;
@@ -934,6 +1013,7 @@ static Etk_Bool _etk_scrolled_view_mouse_up(Etk_Object *object, Etk_Event_Mouse_
       int i, idelt;
       double tlast, tdelt;
       Etk_Position lastpos;
+      int boundary_flag=0;
       
       drag->old_timestamp = drag->timestamp;
       drag->timestamp = ecore_time_get();
@@ -957,14 +1037,55 @@ static Etk_Bool _etk_scrolled_view_mouse_up(Etk_Object *object, Etk_Event_Mouse_
 		idelt++;
 	     }
 	}
-      if (idelt < 1)
-	return ETK_FALSE;
-      if ((tdelt / idelt) * 4 < (drag->position_timestamp - drag->prev_position_timestamp[0]))
-	return ETK_FALSE;
-      if ((((drag->position.x - lastpos.x) * (drag->position.x - lastpos.x)) +
-	   ((drag->position.y - lastpos.y) * (drag->position.y - lastpos.y)))
-	  <= (20 * 20))
-	return ETK_FALSE;
+      vscrollbar_range = ETK_RANGE(scrolled_view->vscrollbar);
+      hscrollbar_range = ETK_RANGE(scrolled_view->hscrollbar);
+
+      if ( drag->bouncy == ETK_BOUNCY_STOPTOOBJECT  && 
+            ((vscrollbar_range->value <= vscrollbar_range->lower + scrolled_view->extra_vmargin)  || 
+            (vscrollbar_range->value >= vscrollbar_range->upper - vscrollbar_range->page_size - scrolled_view->extra_vmargin) ))
+      {
+         if ((vscrollbar_range->value <= vscrollbar_range->lower + scrolled_view->extra_vmargin))
+         {
+            tdelt = 1.0f;
+            drag->Vy = 10;
+         }
+         else 
+         {
+            tdelt = -1.0f;
+            drag->Vy = -10;
+         }
+         _speed_out_of_boundary(vscrollbar_range, scrolled_view->extra_vmargin, &tdelt, &drag->Vy);
+         boundary_flag = 1;
+      } 
+      if (drag->bouncy == ETK_BOUNCY_STOPTOOBJECT  &&
+            ((hscrollbar_range->value <= hscrollbar_range->lower + scrolled_view->extra_hmargin) ||
+            (hscrollbar_range->value >= hscrollbar_range->upper - hscrollbar_range->page_size - scrolled_view->extra_hmargin) ))
+      {
+         if ((hscrollbar_range->value <= hscrollbar_range->lower + scrolled_view->extra_hmargin))
+         {
+            tdelt = 1.0f;
+            drag->Vx = 10;
+         }
+         else
+         {
+            tdelt = -1.0f;
+            drag->Vx = -10;
+         }
+
+         _speed_out_of_boundary(hscrollbar_range, scrolled_view->extra_hmargin, &tdelt, &drag->Vx);
+         boundary_flag = 1;
+      }
+      if (!boundary_flag) {
+         if (idelt < 1)
+           return ETK_FALSE;
+         if ((tdelt / idelt) * 4 < (drag->position_timestamp - drag->prev_position_timestamp[0]))
+           return ETK_FALSE;
+         if ((((drag->position.x - lastpos.x) * (drag->position.x - lastpos.x)) +
+              ((drag->position.y - lastpos.y) * (drag->position.y - lastpos.y)))
+             <= (20 * 20))
+           return ETK_FALSE;
+      }
+
       drag->Vx = drag->Vx > 0 ?  
          drag->Vx > max_speed ?  max_speed : drag->Vx : 
          drag->Vx < -max_speed ? -max_speed : drag->Vx;
diff --git a/etk/src/lib/etk_scrolled_view.h b/etk/src/lib/etk_scrolled_view.h
index 7a1b0e9..26e4030 100644
--- a/etk/src/lib/etk_scrolled_view.h
+++ b/etk/src/lib/etk_scrolled_view.h
@@ -54,6 +54,16 @@ typedef enum
    ETK_POLICY_HIDE,     /**< The scrollbar is always hidden */
 } Etk_Scrolled_View_Policy;
 
+/**
+ * @brief Etk_Scrolled_View_Bouncy_Policy describes how the scrolled view bounce when hit the margin.
+ */ 
+typedef enum
+{
+   ETK_BOUNCY_NOBOUNCE=0,     /** < No bounce at all, stop at margin. It's default */
+   ETK_BOUNCY_BOUNCE,         /** < Bounce to the margin, and do not stop. */
+   ETK_BOUNCY_STOPTOOBJECT,   /** < Do not bounce, and stop at the margin of object.  */
+} Etk_Scrolled_View_Bouncy_Policy;
+
 struct Etk_Scrolled_View_Mouse_Drag 
 {
    Etk_Position position;
@@ -71,7 +81,7 @@ struct Etk_Scrolled_View_Mouse_Drag
    Etk_Bool mouse_down;
    Etk_Bool bar_pressed;
    Etk_Bool dragable;
-   Etk_Bool bouncy;
+   Etk_Scrolled_View_Bouncy_Policy bouncy;
 };
 
 /**
@@ -108,8 +118,8 @@ void        etk_scrolled_view_policy_set(Etk_Scrolled_View *scrolled_view, Etk_S
 void        etk_scrolled_view_policy_get(Etk_Scrolled_View *scrolled_view, Etk_Scrolled_View_Policy *hpolicy, Etk_Scrolled_View_Policy *vpolicy);
 void        etk_scrolled_view_dragable_set(Etk_Scrolled_View *scrolled_view, Etk_Bool dragable);
 Etk_Bool    etk_scrolled_view_dragable_get(Etk_Scrolled_View *scrolled_view);
-void        etk_scrolled_view_drag_bouncy_set(Etk_Scrolled_View *scrolled_view, Etk_Bool bouncy);
-Etk_Bool    etk_scrolled_view_drag_bouncy_get(Etk_Scrolled_View *scrolled_view);
+void        etk_scrolled_view_drag_bouncy_set(Etk_Scrolled_View *scrolled_view, Etk_Scrolled_View_Bouncy_Policy bouncy);
+Etk_Scrolled_View_Bouncy_Policy etk_scrolled_view_drag_bouncy_get(Etk_Scrolled_View *scrolled_view);
 double      etk_scrolled_view_drag_sample_interval_set(Etk_Scrolled_View *scrolled_view, double interval);
 double      etk_scrolled_view_drag_sample_interval_get(Etk_Scrolled_View *scrolled_view);
 unsigned int etk_scrolled_view_drag_damping_set(Etk_Scrolled_View *scrolled_view, unsigned int damping);
@@ -119,7 +129,6 @@ int        etk_scrolled_view_extra_vmargin_get(Etk_Scrolled_View *scrolled_view)
 void        etk_scrolled_view_extra_hmargin_set(Etk_Scrolled_View *scrolled_view, int margin);
 int        etk_scrolled_view_extra_hmargin_get(Etk_Scrolled_View *scrolled_view);
 
-
 /** @} */
 
 #ifdef __cplusplus
diff --git a/etk/src/lib/etk_tree.c b/etk/src/lib/etk_tree.c
index 7b4c3d7..6edb0c9 100644
--- a/etk/src/lib/etk_tree.c
+++ b/etk/src/lib/etk_tree.c
@@ -2825,8 +2825,8 @@ static void _etk_tree_row_objects_update(Etk_Tree *tree, Etk_Geometry grid_geome
       return;
 
    depth = 0;
-   row_id = tree->scroll_y / tree->rows_height;
-   row_y = -(tree->scroll_y % tree->rows_height);
+   row_id = tree->scroll_y >= 0 ? tree->scroll_y / tree->rows_height: 0;
+   row_y = tree->scroll_y >= 0 ? -(tree->scroll_y % tree->rows_height) : -tree->scroll_y;
    for (row = tree->root.first_child, i = 0; i < row_id && row; i++)
       row = _etk_tree_row_next_to_render_get(row, &depth);
    show_expanders = (tree->expanders_visible && tree->total_rows > tree->root.num_children && first_visible_col);
diff --git a/etk/src/lib/etk_widget.c b/etk/src/lib/etk_widget.c
index c92c91a..dc224f3 100644
--- a/etk/src/lib/etk_widget.c
+++ b/etk/src/lib/etk_widget.c
@@ -2007,7 +2007,6 @@ static void _etk_widget_constructor(Etk_Widget *widget)
    widget->size_allocate = NULL;
    widget->theme_signal_emit = NULL;
    widget->scroll_size_get = NULL;
-   widget->scroll_margins_get = NULL;
    widget->scroll = NULL;
 
    widget->realized = ETK_FALSE;
diff --git a/etk/src/lib/etk_widget.h b/etk/src/lib/etk_widget.h
index 66e9a57..da7215f 100644
--- a/etk/src/lib/etk_widget.h
+++ b/etk/src/lib/etk_widget.h
@@ -128,7 +128,6 @@ struct Etk_Widget
    void (*theme_signal_emit)(Etk_Widget *widget, const char *signal, Etk_Bool size_recalc);
 
    void (*scroll_size_get)(Etk_Widget *widget, Etk_Size scrollview_size, Etk_Size scrollbar_size, Etk_Size *scroll_size);
-   void (*scroll_margins_get)(Etk_Widget *widget, Etk_Size *margin_size);
    void (*scroll)(Etk_Widget *widget, int x, int y);
 
    Etk_Bool (*shown_handler)(Etk_Widget *widget);
