Repository: kivy/kivy

Issue:
Nested ScrollView touch transformation is broken for horizontal scrollbars
If you have a nested horizontal ScrollView which uses bars as scroll type, inside a vertical ScrollView, then the touch transformation is broken for the horizontal scroll-bar inside the horizontal ScrollView. It is only noticeable though, if the vertical ScrollView is not starting at `x=0` in window coordinates.

I have added a code snippet to reproduce the error (see below). It is based on kived's nested ScrollView example ([from here](https://gist.github.com/kived/2aa1b6814979340598a7)).

What I also found out was:
- The issue does not occur if the horizontal ScrollView is using content as scroll type.
- The issue does not appear (as already mentioned above) if the vertical ScrollView is starting at `x=0` in window coordinates
- Also the issue does not appear on Kivy 1.8.0. On 1.9.0 and 1.9.1 it appears. (Thanks @bionoid for hinting me to test the different versions.)

```
import kivy

from kivy.app import App
from kivy.lang import Builder

import sys

if 'horizontal' in sys.argv:
    sys.argv.remove('horizontal')
    fmt = {
        'horizontal': 'vertical',
        'x': 'y',
        'y': 'x',
        'width': 'height',
        'height': 'width',
        'col': 'row',
        'row': 'col',
    }
else:
    fmt = {
        'horizontal': 'horizontal',
        'x': 'x',
        'y': 'y',
        'width': 'width',
        'height': 'height',
        'col': 'col',
        'row': 'row',
    }

root = Builder.load_string('''
BoxLayout:
    orientation: 'horizontal'
    BoxLayout:
        orientation: 'horizontal'
        size_hint_x: None
        width: 150
        canvas.before:
            Color:
                rgba: 0, 0, 1, 1
            Rectangle:
                pos: self.pos
                size: self.size
        Label:
            text: "I mess up the nested horizontal scrollbar."
            size_hint_x: None
            width: self.parent.width
            text_size: self.parent.width, None
            max_lines: 5
    BoxLayout:
        orientation: '{horizontal}'
        BoxLayout:
            orientation: '{horizontal}'
            size_hint_{x}: None
            {width}: 0
            Widget:
                id: quarter
            Widget
            Widget
            BoxLayout:
                orientation: '{horizontal}'
                Widget:
                    id: eighth
                Widget
        ScrollView:
            canvas.before:
                Color:
                    rgba: 1, 1, 1, 0.3
                Rectangle:
                    pos: self.pos
                    size: self.size
            scroll_type: ['bars']
            bar_width: 50
            GridLayout:
                {col}s: 1
                size_hint_{y}: None
                {height}: self.minimum_{height}
                {row}_default_{height}: quarter.{height}
                {row}_force_default: True
                Widget
                BoxLayout:
                    orientation: '{horizontal}'
                    canvas.before:
                        Color:
                            rgba: 1, 0, 0, 0.5
                        Rectangle:
                            pos: self.pos
                            size: self.size
                    Widget
                    ScrollView:
                        scroll_type: ['bars']
                        bar_width: 50
                        GridLayout:
                            {col}s: 1
                            size_hint_{y}: None
                            size_hint_{x}: 2.0
                            {height}: self.minimum_{height}
                            {row}_default_{height}: eighth.{height}
                            {row}_force_default: True
                            canvas.before:
                                Color:
                                    rgba: 1, 1, 1, 1
                                Rectangle:
                                    pos: self.pos
                                    size: self.size
                            Widget
                            Label:
                                text: 'Hi!'
                                canvas.before:
                                    Color:
                                        rgba: 0, 0, 1, 0.5
                                    Rectangle:
                                        pos: self.pos
                                        size: self.size
                            Widget
                    Widget
                Widget
'''.format(**fmt))

class TestApp(App):
    def build(self):
        return root

if __name__ == '__main__':
    TestApp().run()
```



Discussion:
Hi All,

Have bumped into this issue also. In my case it's a nested Vertical Scroll View inside another Vertical Scroll View. Wondering what the progression on fixing this bug is?
It's something I'm willing to take a look at fixing, although I'm fairly new to kivy. What would be the best next steps to see a solution come about?
Hard to say something about the progress, but I don't see any active related branch to this issue, so... yeah. But to make it easier, there probably was something similar with `Scatter`(https://github.com/kivy/kivy/commit/fad2f9ce9b3b03bddacf50e0248ccddf2b971bf6), so I'd definitely look at that thing too after reading/understanding how the `ScrollView` works. ^^
Thank you! Will have a look.

Resolving patch:
diff --git a/kivy/uix/scrollview.py b/kivy/uix/scrollview.py
--- a/kivy/uix/scrollview.py
+++ b/kivy/uix/scrollview.py
@@ -600,7 +600,6 @@ def simulate_touch_down(self, touch):
     def on_touch_down(self, touch):
         if self.dispatch('on_scroll_start', touch):
             self._touch = touch
-            touch.grab(self)
             return True
 
     def _touch_in_handle(self, pos, size, touch):
@@ -609,6 +608,7 @@ def _touch_in_handle(self, pos, size, touch):
         return x <= touch.x <= x + width and y <= touch.y <= y + height
 
     def on_scroll_start(self, touch, check_children=True):
+        touch.grab(self)
         if check_children:
             touch.push()
             touch.apply_transform_2d(self.to_local)


Test patch: