Repository: kivy/kivy

Issue:
ScrollView Scroll Throws Bug IndexError
**Software Versions**
* Python: 3.7.6
* OS:
* Kivy: 2.0.0rc4
* Kivy installation method:

**Describe the bug**
This was NOT a Bug in Kivy 2.0.0rc3 but appeared in Kivy 2.0.0rc4.  I have created a List of items with ScrollView.  I had the option to scroll my list with either the slider or touching the list with your finger.
self.FoodList.scroll_type = ['bars','content']
But this will throw an error the moment you touch the Slider Bar and say:
IndexError: List Index out of Range.

if you just make the scroll_type
self.FoodList.scroll_type = ['bars']
bars ONLY without the content part, it works and does not throw an error.
This used to work with both types but now doesn't.

The part of the code that throws the error is:
/kivy/uix/scrollview.py   line 903
if self.scroll_type != ['bars']:



The issue tracker is a tool to address **bugs only** (search known bugs: https://git.io/vM1iE).
Please use the #support Discord channel at https://chat.kivy.org/ or Stack Overflow for
support questions, more information at https://git.io/vM1yQ.

**Expected behavior**
I used to be able to scroll this list on the screen either by sliding the slider bar and/or just touching the list anywhere inside the list and scrolling it.

**To Reproduce**
A short, *runnable* example that reproduces the issue with *latest kivy master*.

**Code and Logs and screenshots**
```python
// REPLACE ME: Paste your code and logs here, a template can be found at https://git.io/vM1id.
```

**Additional context**
Add any other context about the problem here.



Discussion:
Please provide a full error log and a **minimally** reproducible example showing the issue.
I made a small python program in a public github repository that shows this error.

https://github.com/edwit1971/ListScroll

In the code on Line-42 you will see
self.List_Scr.scroll_type = ['content', 'bars']

When you grab the Slider to scroll an error is thrown:
Traceback (most recent call last):
   File "main.py", line 66, in <module>
     ListScrollApp().run()
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/app.py", line 950, in run
     runTouchApp()
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/base.py", line 582, in runTouchApp
     EventLoop.mainloop()
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/base.py", line 347, in mainloop
     self.idle()
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/base.py", line 391, in idle
     self.dispatch_input()
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/base.py", line 342, in dispatch_input
     post_dispatch_input(*pop(0))
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/base.py", line 301, in post_dispatch_input
     wid.dispatch('on_touch_move', me)
   File "kivy/_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/uix/scrollview.py", line 851, in on_touch_move
     if self.dispatch('on_scroll_move', touch):
   File "kivy/_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/uix/scrollview.py", line 904, in on_scroll_move
     self.effect_x.update(touch.x)
   File "/home/edwit3/anaconda3/envs/myenv/lib/python3.8/site-packages/kivy/effects/scroll.py", line 116, in update
     self.displacement += abs(val - self.history[-1][1])
 IndexError: list index out of range



But when you make line-42 just
self.List_Scr.scroll_type = ['bars']
then NO ERROR is thrown and this works.  Kivy no longer allows the dual scrolling of using either the contents or the sliding bar.  Just one or the other.
I just discovered if you CLICK on any of the List Items first, before you try sliding the BAR, for some reason no IndexError is thrown.  The IndexError only happens if you attempt to slide the list BAR first, before touching the list.

But keep in mind, the IndexError only happens when scroll_type = ['bar', 'content']

if you just say scroll_type = ['bar'] then you don't get the IndexError ever.

Resolving patch:
diff --git a/kivy/uix/scrollview.py b/kivy/uix/scrollview.py
--- a/kivy/uix/scrollview.py
+++ b/kivy/uix/scrollview.py
@@ -895,6 +895,9 @@ def on_scroll_move(self, touch):
                 ud['mode'] = 'scroll'
 
         if ud['mode'] == 'scroll':
+            not_in_bar = not touch.ud.get('in_bar_x', False) and \
+                not touch.ud.get('in_bar_y', False)
+
             if not touch.ud['sv.handled']['x'] and self.do_scroll_x \
                     and self.effect_x:
                 width = self.width
@@ -903,9 +906,9 @@ def on_scroll_move(self, touch):
                         dx = touch.dx / float(width - width * self.hbar[1])
                         self.scroll_x = min(max(self.scroll_x + dx, 0.), 1.)
                         self._trigger_update_from_scroll()
-                else:
-                    if self.scroll_type != ['bars']:
-                        self.effect_x.update(touch.x)
+                elif not_in_bar:
+                    self.effect_x.update(touch.x)
+
                 if self.scroll_x < 0 or self.scroll_x > 1:
                     rv = False
                 else:
@@ -919,9 +922,9 @@ def on_scroll_move(self, touch):
                     dy = touch.dy / float(height - height * self.vbar[1])
                     self.scroll_y = min(max(self.scroll_y + dy, 0.), 1.)
                     self._trigger_update_from_scroll()
-                else:
-                    if self.scroll_type != ['bars']:
-                        self.effect_y.update(touch.y)
+                elif not_in_bar:
+                    self.effect_y.update(touch.y)
+
                 if self.scroll_y < 0 or self.scroll_y > 1:
                     rv = False
                 else:
@@ -973,14 +976,12 @@ def on_scroll_stop(self, touch, check_children=True):
         self._touch = None
         uid = self._get_uid()
         ud = touch.ud[uid]
-        if self.do_scroll_x and self.effect_x:
-            if not touch.ud.get('in_bar_x', False) and\
-                    self.scroll_type != ['bars']:
-                self.effect_x.stop(touch.x)
-        if self.do_scroll_y and self.effect_y and\
-                self.scroll_type != ['bars']:
-            if not touch.ud.get('in_bar_y', False):
-                self.effect_y.stop(touch.y)
+        not_in_bar = not touch.ud.get('in_bar_x', False) and \
+            not touch.ud.get('in_bar_y', False)
+        if self.do_scroll_x and self.effect_x and not_in_bar:
+            self.effect_x.stop(touch.x)
+        if self.do_scroll_y and self.effect_y and not_in_bar:
+            self.effect_y.stop(touch.y)
         if ud['mode'] == 'unknown':
             # we must do the click at least..
             # only send the click if it was not a click to stop


Test patch: