We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
DragBehavior dispatching touch event incorrectly
<!--
The issue tracker is a tool to address bugs.
Please use the #kivy IRC channel on freenode or Stack Overflow for
support questions, more information at https://git.io/vM1yQ.

Before opening a new issue, make sure you do the following:
    * check that your issue isn't already filed: https://git.io/vM1iE
    * prepare a short, runnable example that reproduces the issue
    * reproduce the problem with the latest development version of Kivy
    * double-check that the issue is indeed a bug and not a support request
-->

### Versions

* Python: 3.6.0
* OS: Linux Mint ver17.3  (based on Ubuntu 14.04)
* Kivy: 1.10
* Kivy installation method: pip (using pyenv)

### Description

on_press() isn't called when holding down button A or B or D.

### Code and Logs

```python
from kivy.lang import Builder
from kivy.base import runTouchApp

root = Builder.load_string(r'''
<DraggableButton@DragBehavior+Button>:
    font_size: 40
    drag_rectangle: [*self.pos, *self.size, ]
    size_hint: None, None
    on_touch_down: print(self.text, 'on_touch_down')
    on_press: print(self.text, 'on_press')

GridLayout:
    on_touch_down: print('------------------------------------------')
    cols: 2
    RelativeLayout:
        DraggableButton:
            text: 'A'
    RelativeLayout:
        DraggableButton:
            text: 'B'
    RelativeLayout:
        DraggableButton:
            text: 'C'
    RelativeLayout:
        DraggableButton:
            text: 'D'
''')

runTouchApp(root)
```

##### hold down A

```text
------------------------------------------
D on_touch_down
C on_touch_down
B on_touch_down
A on_touch_down
```

##### hold down B

```text
------------------------------------------
D on_touch_down
C on_touch_down
B on_touch_down
```

##### hold down C

```text
------------------------------------------
D on_touch_down
C on_touch_down
C on_press
```

##### hold down D

```text
------------------------------------------
D on_touch_down
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kivy/uix/behaviors/drag.py`
Content:
```
1 """
2 Drag Behavior
3 =============
4 
5 The :class:`~kivy.uix.behaviors.drag.DragBehavior`
6 `mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides Drag behavior.
7 When combined with a widget, dragging in the rectangle defined by the
8 :attr:`~kivy.uix.behaviors.drag.DragBehavior.drag_rectangle` will drag the
9 widget.
10 
11 Example
12 -------
13 
14 The following example creates a draggable label::
15 
16     from kivy.uix.label import Label
17     from kivy.app import App
18     from kivy.uix.behaviors import DragBehavior
19     from kivy.lang import Builder
20 
21     # You could also put the following in your kv file...
22     kv = '''
23     <DragLabel>:
24         # Define the properties for the DragLabel
25         drag_rectangle: self.x, self.y, self.width, self.height
26         drag_timeout: 10000000
27         drag_distance: 0
28 
29     FloatLayout:
30         # Define the root widget
31         DragLabel:
32             size_hint: 0.25, 0.2
33             text: 'Drag me'
34     '''
35 
36 
37     class DragLabel(DragBehavior, Label):
38         pass
39 
40 
41     class TestApp(App):
42         def build(self):
43             return Builder.load_string(kv)
44 
45     TestApp().run()
46 
47 """
48 
49 __all__ = ('DragBehavior', )
50 
51 from kivy.clock import Clock
52 from kivy.properties import NumericProperty, ReferenceListProperty
53 from kivy.config import Config
54 from kivy.metrics import sp
55 from functools import partial
56 
57 # When we are generating documentation, Config doesn't exist
58 _scroll_timeout = _scroll_distance = 0
59 if Config:
60     _scroll_timeout = Config.getint('widgets', 'scroll_timeout')
61     _scroll_distance = Config.getint('widgets', 'scroll_distance')
62 
63 
64 class DragBehavior(object):
65     '''
66     The DragBehavior `mixin <https://en.wikipedia.org/wiki/Mixin>`_ provides
67     Drag behavior. When combined with a widget, dragging in the rectangle
68     defined by :attr:`drag_rectangle` will drag the widget. Please see
69     the :mod:`drag behaviors module <kivy.uix.behaviors.drag>` documentation
70     for more information.
71 
72     .. versionadded:: 1.8.0
73     '''
74 
75     drag_distance = NumericProperty(_scroll_distance)
76     '''Distance to move before dragging the :class:`DragBehavior`, in pixels.
77     As soon as the distance has been traveled, the :class:`DragBehavior` will
78     start to drag, and no touch event will be dispatched to the children.
79     It is advisable that you base this value on the dpi of your target device's
80     screen.
81 
82     :attr:`drag_distance` is a :class:`~kivy.properties.NumericProperty` and
83     defaults to the `scroll_distance` as defined in the user
84     :class:`~kivy.config.Config` (20 pixels by default).
85     '''
86 
87     drag_timeout = NumericProperty(_scroll_timeout)
88     '''Timeout allowed to trigger the :attr:`drag_distance`, in milliseconds.
89     If the user has not moved :attr:`drag_distance` within the timeout,
90     dragging will be disabled, and the touch event will be dispatched to the
91     children.
92 
93     :attr:`drag_timeout` is a :class:`~kivy.properties.NumericProperty` and
94     defaults to the `scroll_timeout` as defined in the user
95     :class:`~kivy.config.Config` (55 milliseconds by default).
96     '''
97 
98     drag_rect_x = NumericProperty(0)
99     '''X position of the axis aligned bounding rectangle where dragging
100     is allowed (in window coordinates).
101 
102     :attr:`drag_rect_x` is a :class:`~kivy.properties.NumericProperty` and
103     defaults to 0.
104     '''
105 
106     drag_rect_y = NumericProperty(0)
107     '''Y position of the axis aligned bounding rectangle where dragging
108     is allowed (in window coordinates).
109 
110     :attr:`drag_rect_Y` is a :class:`~kivy.properties.NumericProperty` and
111     defaults to 0.
112     '''
113 
114     drag_rect_width = NumericProperty(100)
115     '''Width of the axis aligned bounding rectangle where dragging is allowed.
116 
117     :attr:`drag_rect_width` is a :class:`~kivy.properties.NumericProperty` and
118     defaults to 100.
119     '''
120 
121     drag_rect_height = NumericProperty(100)
122     '''Height of the axis aligned bounding rectangle where dragging is allowed.
123 
124     :attr:`drag_rect_height` is a :class:`~kivy.properties.NumericProperty` and
125     defaults to 100.
126     '''
127 
128     drag_rectangle = ReferenceListProperty(drag_rect_x, drag_rect_y,
129                                            drag_rect_width, drag_rect_height)
130     '''Position and size of the axis aligned bounding rectangle where dragging
131     is allowed.
132 
133     :attr:`drag_rectangle` is a :class:`~kivy.properties.ReferenceListProperty`
134     of (:attr:`drag_rect_x`, :attr:`drag_rect_y`, :attr:`drag_rect_width`,
135     :attr:`drag_rect_height`) properties.
136     '''
137 
138     def __init__(self, **kwargs):
139         self._drag_touch = None
140         super(DragBehavior, self).__init__(**kwargs)
141 
142     def _get_uid(self, prefix='sv'):
143         return '{0}.{1}'.format(prefix, self.uid)
144 
145     def on_touch_down(self, touch):
146         xx, yy, w, h = self.drag_rectangle
147         x, y = touch.pos
148         if not self.collide_point(x, y):
149             touch.ud[self._get_uid('svavoid')] = True
150             return super(DragBehavior, self).on_touch_down(touch)
151         if self._drag_touch or ('button' in touch.profile and
152                                 touch.button.startswith('scroll')) or\
153                 not ((xx < x <= xx + w) and (yy < y <= yy + h)):
154             return super(DragBehavior, self).on_touch_down(touch)
155 
156         # no mouse scrolling, so the user is going to drag with this touch.
157         self._drag_touch = touch
158         uid = self._get_uid()
159         touch.grab(self)
160         touch.ud[uid] = {
161             'mode': 'unknown',
162             'dx': 0,
163             'dy': 0}
164         Clock.schedule_once(self._change_touch_mode,
165                             self.drag_timeout / 1000.)
166         return True
167 
168     def on_touch_move(self, touch):
169         if self._get_uid('svavoid') in touch.ud or\
170                 self._drag_touch is not touch:
171             return super(DragBehavior, self).on_touch_move(touch) or\
172                 self._get_uid() in touch.ud
173         if touch.grab_current is not self:
174             return True
175 
176         uid = self._get_uid()
177         ud = touch.ud[uid]
178         mode = ud['mode']
179         if mode == 'unknown':
180             ud['dx'] += abs(touch.dx)
181             ud['dy'] += abs(touch.dy)
182             if ud['dx'] > sp(self.drag_distance):
183                 mode = 'drag'
184             if ud['dy'] > sp(self.drag_distance):
185                 mode = 'drag'
186             ud['mode'] = mode
187         if mode == 'drag':
188             self.x += touch.dx
189             self.y += touch.dy
190         return True
191 
192     def on_touch_up(self, touch):
193         if self._get_uid('svavoid') in touch.ud:
194             return super(DragBehavior, self).on_touch_up(touch)
195 
196         if self._drag_touch and self in [x() for x in touch.grab_list]:
197             touch.ungrab(self)
198             self._drag_touch = None
199             ud = touch.ud[self._get_uid()]
200             if ud['mode'] == 'unknown':
201                 super(DragBehavior, self).on_touch_down(touch)
202                 Clock.schedule_once(partial(self._do_touch_up, touch), .1)
203         else:
204             if self._drag_touch is not touch:
205                 super(DragBehavior, self).on_touch_up(touch)
206         return self._get_uid() in touch.ud
207 
208     def _do_touch_up(self, touch, *largs):
209         super(DragBehavior, self).on_touch_up(touch)
210         # don't forget about grab event!
211         for x in touch.grab_list[:]:
212             touch.grab_list.remove(x)
213             x = x()
214             if not x:
215                 continue
216             touch.grab_current = x
217             super(DragBehavior, self).on_touch_up(touch)
218         touch.grab_current = None
219 
220     def _change_touch_mode(self, *largs):
221         if not self._drag_touch:
222             return
223         uid = self._get_uid()
224         touch = self._drag_touch
225         ud = touch.ud[uid]
226         if ud['mode'] != 'unknown':
227             return
228         touch.ungrab(self)
229         self._drag_touch = None
230         super(DragBehavior, self).on_touch_down(touch)
231         return
232
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kivy/uix/behaviors/drag.py b/kivy/uix/behaviors/drag.py
--- a/kivy/uix/behaviors/drag.py
+++ b/kivy/uix/behaviors/drag.py
@@ -227,5 +227,8 @@
             return
         touch.ungrab(self)
         self._drag_touch = None
+        touch.push()
+        touch.apply_transform_2d(self.parent.to_widget)
         super(DragBehavior, self).on_touch_down(touch)
+        touch.pop()
         return

{"golden_diff": "diff --git a/kivy/uix/behaviors/drag.py b/kivy/uix/behaviors/drag.py\n--- a/kivy/uix/behaviors/drag.py\n+++ b/kivy/uix/behaviors/drag.py\n@@ -227,5 +227,8 @@\n             return\n         touch.ungrab(self)\n         self._drag_touch = None\n+        touch.push()\n+        touch.apply_transform_2d(self.parent.to_widget)\n         super(DragBehavior, self).on_touch_down(touch)\n+        touch.pop()\n         return\n", "issue": "DragBehavior dispatching touch event incorrectly\n<!--\r\nThe issue tracker is a tool to address bugs.\r\nPlease use the #kivy IRC channel on freenode or Stack Overflow for\r\nsupport questions, more information at https://git.io/vM1yQ.\r\n\r\nBefore opening a new issue, make sure you do the following:\r\n    * check that your issue isn't already filed: https://git.io/vM1iE\r\n    * prepare a short, runnable example that reproduces the issue\r\n    * reproduce the problem with the latest development version of Kivy\r\n    * double-check that the issue is indeed a bug and not a support request\r\n-->\r\n\r\n### Versions\r\n\r\n* Python: 3.6.0\r\n* OS: Linux Mint ver17.3  (based on Ubuntu 14.04)\r\n* Kivy: 1.10\r\n* Kivy installation method: pip (using pyenv)\r\n\r\n### Description\r\n\r\non_press() isn't called when holding down button A or B or D.\r\n\r\n### Code and Logs\r\n\r\n```python\r\nfrom kivy.lang import Builder\r\nfrom kivy.base import runTouchApp\r\n\r\nroot = Builder.load_string(r'''\r\n<DraggableButton@DragBehavior+Button>:\r\n    font_size: 40\r\n    drag_rectangle: [*self.pos, *self.size, ]\r\n    size_hint: None, None\r\n    on_touch_down: print(self.text, 'on_touch_down')\r\n    on_press: print(self.text, 'on_press')\r\n\r\nGridLayout:\r\n    on_touch_down: print('------------------------------------------')\r\n    cols: 2\r\n    RelativeLayout:\r\n        DraggableButton:\r\n            text: 'A'\r\n    RelativeLayout:\r\n        DraggableButton:\r\n            text: 'B'\r\n    RelativeLayout:\r\n        DraggableButton:\r\n            text: 'C'\r\n    RelativeLayout:\r\n        DraggableButton:\r\n            text: 'D'\r\n''')\r\n\r\nrunTouchApp(root)\r\n```\r\n\r\n##### hold down A\r\n\r\n```text\r\n------------------------------------------\r\nD on_touch_down\r\nC on_touch_down\r\nB on_touch_down\r\nA on_touch_down\r\n```\r\n\r\n##### hold down B\r\n\r\n```text\r\n------------------------------------------\r\nD on_touch_down\r\nC on_touch_down\r\nB on_touch_down\r\n```\r\n\r\n##### hold down C\r\n\r\n```text\r\n------------------------------------------\r\nD on_touch_down\r\nC on_touch_down\r\nC on_press\r\n```\r\n\r\n##### hold down D\r\n\r\n```text\r\n------------------------------------------\r\nD on_touch_down\r\n```\n", "before_files": [{"content": "\"\"\"\nDrag Behavior\n=============\n\nThe :class:`~kivy.uix.behaviors.drag.DragBehavior`\n`mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides Drag behavior.\nWhen combined with a widget, dragging in the rectangle defined by the\n:attr:`~kivy.uix.behaviors.drag.DragBehavior.drag_rectangle` will drag the\nwidget.\n\nExample\n-------\n\nThe following example creates a draggable label::\n\n    from kivy.uix.label import Label\n    from kivy.app import App\n    from kivy.uix.behaviors import DragBehavior\n    from kivy.lang import Builder\n\n    # You could also put the following in your kv file...\n    kv = '''\n    <DragLabel>:\n        # Define the properties for the DragLabel\n        drag_rectangle: self.x, self.y, self.width, self.height\n        drag_timeout: 10000000\n        drag_distance: 0\n\n    FloatLayout:\n        # Define the root widget\n        DragLabel:\n            size_hint: 0.25, 0.2\n            text: 'Drag me'\n    '''\n\n\n    class DragLabel(DragBehavior, Label):\n        pass\n\n\n    class TestApp(App):\n        def build(self):\n            return Builder.load_string(kv)\n\n    TestApp().run()\n\n\"\"\"\n\n__all__ = ('DragBehavior', )\n\nfrom kivy.clock import Clock\nfrom kivy.properties import NumericProperty, ReferenceListProperty\nfrom kivy.config import Config\nfrom kivy.metrics import sp\nfrom functools import partial\n\n# When we are generating documentation, Config doesn't exist\n_scroll_timeout = _scroll_distance = 0\nif Config:\n    _scroll_timeout = Config.getint('widgets', 'scroll_timeout')\n    _scroll_distance = Config.getint('widgets', 'scroll_distance')\n\n\nclass DragBehavior(object):\n    '''\n    The DragBehavior `mixin <https://en.wikipedia.org/wiki/Mixin>`_ provides\n    Drag behavior. When combined with a widget, dragging in the rectangle\n    defined by :attr:`drag_rectangle` will drag the widget. Please see\n    the :mod:`drag behaviors module <kivy.uix.behaviors.drag>` documentation\n    for more information.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    drag_distance = NumericProperty(_scroll_distance)\n    '''Distance to move before dragging the :class:`DragBehavior`, in pixels.\n    As soon as the distance has been traveled, the :class:`DragBehavior` will\n    start to drag, and no touch event will be dispatched to the children.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    :attr:`drag_distance` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to the `scroll_distance` as defined in the user\n    :class:`~kivy.config.Config` (20 pixels by default).\n    '''\n\n    drag_timeout = NumericProperty(_scroll_timeout)\n    '''Timeout allowed to trigger the :attr:`drag_distance`, in milliseconds.\n    If the user has not moved :attr:`drag_distance` within the timeout,\n    dragging will be disabled, and the touch event will be dispatched to the\n    children.\n\n    :attr:`drag_timeout` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to the `scroll_timeout` as defined in the user\n    :class:`~kivy.config.Config` (55 milliseconds by default).\n    '''\n\n    drag_rect_x = NumericProperty(0)\n    '''X position of the axis aligned bounding rectangle where dragging\n    is allowed (in window coordinates).\n\n    :attr:`drag_rect_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    drag_rect_y = NumericProperty(0)\n    '''Y position of the axis aligned bounding rectangle where dragging\n    is allowed (in window coordinates).\n\n    :attr:`drag_rect_Y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    drag_rect_width = NumericProperty(100)\n    '''Width of the axis aligned bounding rectangle where dragging is allowed.\n\n    :attr:`drag_rect_width` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 100.\n    '''\n\n    drag_rect_height = NumericProperty(100)\n    '''Height of the axis aligned bounding rectangle where dragging is allowed.\n\n    :attr:`drag_rect_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 100.\n    '''\n\n    drag_rectangle = ReferenceListProperty(drag_rect_x, drag_rect_y,\n                                           drag_rect_width, drag_rect_height)\n    '''Position and size of the axis aligned bounding rectangle where dragging\n    is allowed.\n\n    :attr:`drag_rectangle` is a :class:`~kivy.properties.ReferenceListProperty`\n    of (:attr:`drag_rect_x`, :attr:`drag_rect_y`, :attr:`drag_rect_width`,\n    :attr:`drag_rect_height`) properties.\n    '''\n\n    def __init__(self, **kwargs):\n        self._drag_touch = None\n        super(DragBehavior, self).__init__(**kwargs)\n\n    def _get_uid(self, prefix='sv'):\n        return '{0}.{1}'.format(prefix, self.uid)\n\n    def on_touch_down(self, touch):\n        xx, yy, w, h = self.drag_rectangle\n        x, y = touch.pos\n        if not self.collide_point(x, y):\n            touch.ud[self._get_uid('svavoid')] = True\n            return super(DragBehavior, self).on_touch_down(touch)\n        if self._drag_touch or ('button' in touch.profile and\n                                touch.button.startswith('scroll')) or\\\n                not ((xx < x <= xx + w) and (yy < y <= yy + h)):\n            return super(DragBehavior, self).on_touch_down(touch)\n\n        # no mouse scrolling, so the user is going to drag with this touch.\n        self._drag_touch = touch\n        uid = self._get_uid()\n        touch.grab(self)\n        touch.ud[uid] = {\n            'mode': 'unknown',\n            'dx': 0,\n            'dy': 0}\n        Clock.schedule_once(self._change_touch_mode,\n                            self.drag_timeout / 1000.)\n        return True\n\n    def on_touch_move(self, touch):\n        if self._get_uid('svavoid') in touch.ud or\\\n                self._drag_touch is not touch:\n            return super(DragBehavior, self).on_touch_move(touch) or\\\n                self._get_uid() in touch.ud\n        if touch.grab_current is not self:\n            return True\n\n        uid = self._get_uid()\n        ud = touch.ud[uid]\n        mode = ud['mode']\n        if mode == 'unknown':\n            ud['dx'] += abs(touch.dx)\n            ud['dy'] += abs(touch.dy)\n            if ud['dx'] > sp(self.drag_distance):\n                mode = 'drag'\n            if ud['dy'] > sp(self.drag_distance):\n                mode = 'drag'\n            ud['mode'] = mode\n        if mode == 'drag':\n            self.x += touch.dx\n            self.y += touch.dy\n        return True\n\n    def on_touch_up(self, touch):\n        if self._get_uid('svavoid') in touch.ud:\n            return super(DragBehavior, self).on_touch_up(touch)\n\n        if self._drag_touch and self in [x() for x in touch.grab_list]:\n            touch.ungrab(self)\n            self._drag_touch = None\n            ud = touch.ud[self._get_uid()]\n            if ud['mode'] == 'unknown':\n                super(DragBehavior, self).on_touch_down(touch)\n                Clock.schedule_once(partial(self._do_touch_up, touch), .1)\n        else:\n            if self._drag_touch is not touch:\n                super(DragBehavior, self).on_touch_up(touch)\n        return self._get_uid() in touch.ud\n\n    def _do_touch_up(self, touch, *largs):\n        super(DragBehavior, self).on_touch_up(touch)\n        # don't forget about grab event!\n        for x in touch.grab_list[:]:\n            touch.grab_list.remove(x)\n            x = x()\n            if not x:\n                continue\n            touch.grab_current = x\n            super(DragBehavior, self).on_touch_up(touch)\n        touch.grab_current = None\n\n    def _change_touch_mode(self, *largs):\n        if not self._drag_touch:\n            return\n        uid = self._get_uid()\n        touch = self._drag_touch\n        ud = touch.ud[uid]\n        if ud['mode'] != 'unknown':\n            return\n        touch.ungrab(self)\n        self._drag_touch = None\n        super(DragBehavior, self).on_touch_down(touch)\n        return\n", "path": "kivy/uix/behaviors/drag.py"}], "after_files": [{"content": "\"\"\"\nDrag Behavior\n=============\n\nThe :class:`~kivy.uix.behaviors.drag.DragBehavior`\n`mixin <https://en.wikipedia.org/wiki/Mixin>`_ class provides Drag behavior.\nWhen combined with a widget, dragging in the rectangle defined by the\n:attr:`~kivy.uix.behaviors.drag.DragBehavior.drag_rectangle` will drag the\nwidget.\n\nExample\n-------\n\nThe following example creates a draggable label::\n\n    from kivy.uix.label import Label\n    from kivy.app import App\n    from kivy.uix.behaviors import DragBehavior\n    from kivy.lang import Builder\n\n    # You could also put the following in your kv file...\n    kv = '''\n    <DragLabel>:\n        # Define the properties for the DragLabel\n        drag_rectangle: self.x, self.y, self.width, self.height\n        drag_timeout: 10000000\n        drag_distance: 0\n\n    FloatLayout:\n        # Define the root widget\n        DragLabel:\n            size_hint: 0.25, 0.2\n            text: 'Drag me'\n    '''\n\n\n    class DragLabel(DragBehavior, Label):\n        pass\n\n\n    class TestApp(App):\n        def build(self):\n            return Builder.load_string(kv)\n\n    TestApp().run()\n\n\"\"\"\n\n__all__ = ('DragBehavior', )\n\nfrom kivy.clock import Clock\nfrom kivy.properties import NumericProperty, ReferenceListProperty\nfrom kivy.config import Config\nfrom kivy.metrics import sp\nfrom functools import partial\n\n# When we are generating documentation, Config doesn't exist\n_scroll_timeout = _scroll_distance = 0\nif Config:\n    _scroll_timeout = Config.getint('widgets', 'scroll_timeout')\n    _scroll_distance = Config.getint('widgets', 'scroll_distance')\n\n\nclass DragBehavior(object):\n    '''\n    The DragBehavior `mixin <https://en.wikipedia.org/wiki/Mixin>`_ provides\n    Drag behavior. When combined with a widget, dragging in the rectangle\n    defined by :attr:`drag_rectangle` will drag the widget. Please see\n    the :mod:`drag behaviors module <kivy.uix.behaviors.drag>` documentation\n    for more information.\n\n    .. versionadded:: 1.8.0\n    '''\n\n    drag_distance = NumericProperty(_scroll_distance)\n    '''Distance to move before dragging the :class:`DragBehavior`, in pixels.\n    As soon as the distance has been traveled, the :class:`DragBehavior` will\n    start to drag, and no touch event will be dispatched to the children.\n    It is advisable that you base this value on the dpi of your target device's\n    screen.\n\n    :attr:`drag_distance` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to the `scroll_distance` as defined in the user\n    :class:`~kivy.config.Config` (20 pixels by default).\n    '''\n\n    drag_timeout = NumericProperty(_scroll_timeout)\n    '''Timeout allowed to trigger the :attr:`drag_distance`, in milliseconds.\n    If the user has not moved :attr:`drag_distance` within the timeout,\n    dragging will be disabled, and the touch event will be dispatched to the\n    children.\n\n    :attr:`drag_timeout` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to the `scroll_timeout` as defined in the user\n    :class:`~kivy.config.Config` (55 milliseconds by default).\n    '''\n\n    drag_rect_x = NumericProperty(0)\n    '''X position of the axis aligned bounding rectangle where dragging\n    is allowed (in window coordinates).\n\n    :attr:`drag_rect_x` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    drag_rect_y = NumericProperty(0)\n    '''Y position of the axis aligned bounding rectangle where dragging\n    is allowed (in window coordinates).\n\n    :attr:`drag_rect_Y` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 0.\n    '''\n\n    drag_rect_width = NumericProperty(100)\n    '''Width of the axis aligned bounding rectangle where dragging is allowed.\n\n    :attr:`drag_rect_width` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 100.\n    '''\n\n    drag_rect_height = NumericProperty(100)\n    '''Height of the axis aligned bounding rectangle where dragging is allowed.\n\n    :attr:`drag_rect_height` is a :class:`~kivy.properties.NumericProperty` and\n    defaults to 100.\n    '''\n\n    drag_rectangle = ReferenceListProperty(drag_rect_x, drag_rect_y,\n                                           drag_rect_width, drag_rect_height)\n    '''Position and size of the axis aligned bounding rectangle where dragging\n    is allowed.\n\n    :attr:`drag_rectangle` is a :class:`~kivy.properties.ReferenceListProperty`\n    of (:attr:`drag_rect_x`, :attr:`drag_rect_y`, :attr:`drag_rect_width`,\n    :attr:`drag_rect_height`) properties.\n    '''\n\n    def __init__(self, **kwargs):\n        self._drag_touch = None\n        super(DragBehavior, self).__init__(**kwargs)\n\n    def _get_uid(self, prefix='sv'):\n        return '{0}.{1}'.format(prefix, self.uid)\n\n    def on_touch_down(self, touch):\n        xx, yy, w, h = self.drag_rectangle\n        x, y = touch.pos\n        if not self.collide_point(x, y):\n            touch.ud[self._get_uid('svavoid')] = True\n            return super(DragBehavior, self).on_touch_down(touch)\n        if self._drag_touch or ('button' in touch.profile and\n                                touch.button.startswith('scroll')) or\\\n                not ((xx < x <= xx + w) and (yy < y <= yy + h)):\n            return super(DragBehavior, self).on_touch_down(touch)\n\n        # no mouse scrolling, so the user is going to drag with this touch.\n        self._drag_touch = touch\n        uid = self._get_uid()\n        touch.grab(self)\n        touch.ud[uid] = {\n            'mode': 'unknown',\n            'dx': 0,\n            'dy': 0}\n        Clock.schedule_once(self._change_touch_mode,\n                            self.drag_timeout / 1000.)\n        return True\n\n    def on_touch_move(self, touch):\n        if self._get_uid('svavoid') in touch.ud or\\\n                self._drag_touch is not touch:\n            return super(DragBehavior, self).on_touch_move(touch) or\\\n                self._get_uid() in touch.ud\n        if touch.grab_current is not self:\n            return True\n\n        uid = self._get_uid()\n        ud = touch.ud[uid]\n        mode = ud['mode']\n        if mode == 'unknown':\n            ud['dx'] += abs(touch.dx)\n            ud['dy'] += abs(touch.dy)\n            if ud['dx'] > sp(self.drag_distance):\n                mode = 'drag'\n            if ud['dy'] > sp(self.drag_distance):\n                mode = 'drag'\n            ud['mode'] = mode\n        if mode == 'drag':\n            self.x += touch.dx\n            self.y += touch.dy\n        return True\n\n    def on_touch_up(self, touch):\n        if self._get_uid('svavoid') in touch.ud:\n            return super(DragBehavior, self).on_touch_up(touch)\n\n        if self._drag_touch and self in [x() for x in touch.grab_list]:\n            touch.ungrab(self)\n            self._drag_touch = None\n            ud = touch.ud[self._get_uid()]\n            if ud['mode'] == 'unknown':\n                super(DragBehavior, self).on_touch_down(touch)\n                Clock.schedule_once(partial(self._do_touch_up, touch), .1)\n        else:\n            if self._drag_touch is not touch:\n                super(DragBehavior, self).on_touch_up(touch)\n        return self._get_uid() in touch.ud\n\n    def _do_touch_up(self, touch, *largs):\n        super(DragBehavior, self).on_touch_up(touch)\n        # don't forget about grab event!\n        for x in touch.grab_list[:]:\n            touch.grab_list.remove(x)\n            x = x()\n            if not x:\n                continue\n            touch.grab_current = x\n            super(DragBehavior, self).on_touch_up(touch)\n        touch.grab_current = None\n\n    def _change_touch_mode(self, *largs):\n        if not self._drag_touch:\n            return\n        uid = self._get_uid()\n        touch = self._drag_touch\n        ud = touch.ud[uid]\n        if ud['mode'] != 'unknown':\n            return\n        touch.ungrab(self)\n        self._drag_touch = None\n        touch.push()\n        touch.apply_transform_2d(self.parent.to_widget)\n        super(DragBehavior, self).on_touch_down(touch)\n        touch.pop()\n        return\n", "path": "kivy/uix/behaviors/drag.py"}]}