fix nested scrollviews

Make `ScrollView` interaction work when nested (#2370). Scrolling should work like it does in most applications; when the inner `ScrollView` has reached its limit, it cancels scrolling and allows the containing `ScrollView` to take over.

To implement this, I added functionality to `EventDispatcher` for handling generic events. This allowed me to add `on_scroll_start`, `on_scroll_move`, and `on_scroll_up` events to `ScrollView` and dispatch them through the child tree without adding those events to every `Widget`. Any events which a given `Widget` does not register will be silently ignored instead of throwing a `KeyError`. I figured this could be a useful addition, but I can easily remove that part and add a local method to `ScrollView` for dispatching these events instead.

My test code:

````python
import kivy
kivy.require('1.8.1')

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}: 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
		
		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:
					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()
````