/kivy/tests/test_uix_scrollview.py

https://github.com/akshayaurora/kivy · Python · 358 lines · 270 code · 69 blank · 19 comment · 12 complexity · 3c9846877c073546e8dcafe8f06dd790 MD5 · raw file

  1. from kivy.tests.common import GraphicUnitTest
  2. from kivy.uix.gridlayout import GridLayout
  3. from kivy.uix.scrollview import ScrollView
  4. from kivy.uix.label import Label
  5. from kivy.base import EventLoop
  6. from kivy.clock import Clock
  7. from kivy.tests.common import UTMotionEvent
  8. from time import sleep
  9. from itertools import count
  10. DEBUG = False
  11. touch_id = count()
  12. class _TestGrid(GridLayout):
  13. def __init__(self, **kwargs):
  14. kwargs['cols'] = 1
  15. kwargs['spacing'] = 10
  16. kwargs['size_hint'] = (None, None)
  17. super(_TestGrid, self).__init__(**kwargs)
  18. self.bind(minimum_height=self.setter('height'))
  19. self.bind(minimum_width=self.setter('width'))
  20. for i in range(10):
  21. self.add_widget(Label(
  22. size_hint=(None, None),
  23. height=100, width=1000,
  24. text=str(i)
  25. ))
  26. class _TestScrollbarHorizontal(ScrollView):
  27. def __init__(self, **kwargs):
  28. kwargs['scroll_type'] = ["bars"]
  29. kwargs['bar_width'] = 20
  30. kwargs['do_scroll_y'] = False
  31. super(_TestScrollbarHorizontal, self).__init__(**kwargs)
  32. class _TestScrollbarVertical(ScrollView):
  33. def __init__(self, **kwargs):
  34. kwargs['scroll_type'] = ["bars"]
  35. kwargs['bar_width'] = 20
  36. kwargs['do_scroll_x'] = False
  37. super(_TestScrollbarVertical, self).__init__(**kwargs)
  38. class _TestScrollbarBoth(ScrollView):
  39. def __init__(self, **kwargs):
  40. kwargs['scroll_type'] = ["bars"]
  41. kwargs['bar_width'] = 20
  42. super(_TestScrollbarBoth, self).__init__(**kwargs)
  43. class _TestScrollbarHorizontalMargin(ScrollView):
  44. def __init__(self, **kwargs):
  45. kwargs['scroll_type'] = ["bars"]
  46. kwargs['bar_margin'] = 40
  47. kwargs['bar_width'] = 20
  48. kwargs['do_scroll_y'] = False
  49. super(_TestScrollbarHorizontalMargin, self).__init__(**kwargs)
  50. class _TestScrollbarVerticalMargin(ScrollView):
  51. def __init__(self, **kwargs):
  52. kwargs['scroll_type'] = ["bars"]
  53. kwargs['bar_margin'] = 40
  54. kwargs['bar_width'] = 20
  55. kwargs['do_scroll_x'] = False
  56. super(_TestScrollbarVerticalMargin, self).__init__(**kwargs)
  57. class _TestScrollbarBothMargin(ScrollView):
  58. def __init__(self, **kwargs):
  59. kwargs['scroll_type'] = ["bars"]
  60. kwargs['bar_margin'] = 40
  61. kwargs['bar_width'] = 20
  62. super(_TestScrollbarBothMargin, self).__init__(**kwargs)
  63. class ScrollViewTestCase(GraphicUnitTest):
  64. framecount = 0
  65. def process_points(self, scroll, points):
  66. win = EventLoop.window
  67. dt = 0.02
  68. for point in points:
  69. if DEBUG:
  70. print('point:', point, scroll.scroll_x, scroll.scroll_y)
  71. Clock.schedule_once(lambda *dt: sleep(0.5), 0)
  72. self.render(scroll)
  73. x, y, nx, ny, pos_x, pos_y, border_check = point
  74. scroll.bar_pos = (pos_x, pos_y)
  75. touch = UTMotionEvent("unittest", next(touch_id), {
  76. "x": x / float(win.width),
  77. "y": y / float(win.height),
  78. })
  79. # we start with the default top-left corner
  80. self.assertAlmostEqual(scroll.scroll_x, 0.0, delta=dt)
  81. self.assertAlmostEqual(scroll.scroll_y, 1.0, delta=dt)
  82. # check the collision with the margin empty area
  83. if border_check:
  84. EventLoop.post_dispatch_input("begin", touch)
  85. touch.move({
  86. "x": nx / float(win.width),
  87. "y": ny / float(win.height)
  88. })
  89. EventLoop.post_dispatch_input("update", touch)
  90. EventLoop.post_dispatch_input("end", touch)
  91. self.assertAlmostEqual(scroll.scroll_x, 0.0, delta=dt)
  92. self.assertAlmostEqual(scroll.scroll_y, 1.0, delta=dt)
  93. return
  94. EventLoop.post_dispatch_input("begin", touch)
  95. touch.move({
  96. "x": nx / float(win.width),
  97. "y": ny / float(win.height)
  98. })
  99. EventLoop.post_dispatch_input("update", touch)
  100. EventLoop.post_dispatch_input("end", touch)
  101. if DEBUG:
  102. print(scroll.scroll_x, scroll.scroll_y)
  103. Clock.schedule_once(lambda *dt: sleep(0.5), 0)
  104. self.render(scroll)
  105. # check the scroll position
  106. self.assertAlmostEqual(
  107. scroll.scroll_x, 0.0 if x == nx else 1.0,
  108. delta=dt
  109. )
  110. self.assertAlmostEqual(
  111. scroll.scroll_y, 1.0 if y == ny else 0.0,
  112. delta=dt
  113. )
  114. # reset scroll to original state
  115. scroll.scroll_x = 0.0
  116. scroll.scroll_y = 1.0
  117. def test_scrollbar_horizontal(self):
  118. EventLoop.ensure_window()
  119. win = EventLoop.window
  120. grid = _TestGrid()
  121. scroll = _TestScrollbarHorizontal()
  122. scroll.add_widget(grid)
  123. win.add_widget(scroll)
  124. # get widgets ready
  125. EventLoop.idle()
  126. left, right = scroll.to_window(scroll.x, scroll.right)
  127. bottom, top = scroll.to_window(scroll.y, scroll.top)
  128. points = [
  129. [left, bottom, right, bottom, 'bottom', 'right', False],
  130. [left, top, right, top, 'top', 'right', False]
  131. ]
  132. self.process_points(scroll, points)
  133. self.render(scroll)
  134. def test_scrollbar_vertical(self):
  135. EventLoop.ensure_window()
  136. win = EventLoop.window
  137. grid = _TestGrid()
  138. scroll = _TestScrollbarVertical()
  139. scroll.add_widget(grid)
  140. win.add_widget(scroll)
  141. # get widgets ready
  142. EventLoop.idle()
  143. left, right = scroll.to_window(scroll.x, scroll.right)
  144. bottom, top = scroll.to_window(scroll.y, scroll.top)
  145. points = [
  146. [right, top, right, bottom, 'bottom', 'right', False],
  147. [left, top, left, bottom, 'bottom', 'left', False]
  148. ]
  149. self.process_points(scroll, points)
  150. self.render(scroll)
  151. def test_scrollbar_both(self):
  152. EventLoop.ensure_window()
  153. win = EventLoop.window
  154. grid = _TestGrid()
  155. scroll = _TestScrollbarBoth()
  156. scroll.add_widget(grid)
  157. win.add_widget(scroll)
  158. # get widgets ready
  159. EventLoop.idle()
  160. left, right = scroll.to_window(scroll.x, scroll.right)
  161. bottom, top = scroll.to_window(scroll.y, scroll.top)
  162. points = [
  163. [left, bottom, right, bottom, 'bottom', 'right', False],
  164. [left, top, right, top, 'top', 'right', False],
  165. [right, top, right, bottom, 'bottom', 'right', False],
  166. [left, top, left, bottom, 'bottom', 'left', False]
  167. ]
  168. self.process_points(scroll, points)
  169. self.render(scroll)
  170. def test_scrollbar_horizontal_margin(self):
  171. EventLoop.ensure_window()
  172. win = EventLoop.window
  173. grid = _TestGrid()
  174. scroll = _TestScrollbarHorizontalMargin()
  175. margin = scroll.bar_margin
  176. scroll.add_widget(grid)
  177. win.add_widget(scroll)
  178. # get widgets ready
  179. EventLoop.idle()
  180. left, right = scroll.to_window(scroll.x, scroll.right)
  181. bottom, top = scroll.to_window(scroll.y, scroll.top)
  182. # touch in the half of the bar
  183. m = margin + scroll.bar_width / 2.0
  184. points = [
  185. [left, bottom + m, right, bottom + m, 'bottom', 'right', False],
  186. [left, top - m, right, top - m, 'top', 'right', False],
  187. [left, bottom, right, bottom, 'bottom', 'right', True],
  188. [left, top, right, top, 'top', 'right', True]
  189. ]
  190. self.process_points(scroll, points)
  191. self.render(scroll)
  192. def test_scrollbar_vertical_margin(self):
  193. EventLoop.ensure_window()
  194. win = EventLoop.window
  195. grid = _TestGrid()
  196. scroll = _TestScrollbarVerticalMargin()
  197. margin = scroll.bar_margin
  198. scroll.add_widget(grid)
  199. win.add_widget(scroll)
  200. # get widgets ready
  201. EventLoop.idle()
  202. left, right = scroll.to_window(scroll.x, scroll.right)
  203. bottom, top = scroll.to_window(scroll.y, scroll.top)
  204. # touch in the half of the bar
  205. m = margin + scroll.bar_width / 2.0
  206. points = [
  207. [right - m, top, right - m, bottom, 'bottom', 'right', False],
  208. [left + m, top, left + m, bottom, 'bottom', 'left', False],
  209. [right, top, right, bottom, 'bottom', 'right', True],
  210. [left, top, left, bottom, 'bottom', 'left', True]
  211. ]
  212. self.process_points(scroll, points)
  213. self.render(scroll)
  214. def test_scrollbar_both_margin(self):
  215. EventLoop.ensure_window()
  216. win = EventLoop.window
  217. grid = _TestGrid()
  218. scroll = _TestScrollbarBothMargin()
  219. margin = scroll.bar_margin
  220. scroll.add_widget(grid)
  221. win.add_widget(scroll)
  222. # get widgets ready
  223. EventLoop.idle()
  224. left, right = scroll.to_window(scroll.x, scroll.right)
  225. bottom, top = scroll.to_window(scroll.y, scroll.top)
  226. # touch in the half of the bar
  227. m = margin + scroll.bar_width / 2.0
  228. points = [
  229. [left, bottom + m, right, bottom + m, 'bottom', 'right', False],
  230. [left, top - m, right, top - m, 'top', 'right', False],
  231. [right - m, top, right - m, bottom, 'bottom', 'right', False],
  232. [left + m, top, left + m, bottom, 'bottom', 'left', False],
  233. [left, bottom, right, bottom, 'bottom', 'right', True],
  234. [left, top, right, top, 'top', 'right', True],
  235. [right, top, right, bottom, 'bottom', 'right', True],
  236. [left, top, left, bottom, 'bottom', 'left', True]
  237. ]
  238. self.process_points(scroll, points)
  239. self.render(scroll)
  240. def test_smooth_scroll_end(self):
  241. EventLoop.ensure_window()
  242. win = EventLoop.window
  243. grid = _TestGrid()
  244. scroll = ScrollView(smooth_scroll_end=10)
  245. assert scroll.smooth_scroll_end == 10
  246. scroll.add_widget(grid)
  247. # XXX this shouldn't be needed, but previous tests apparently
  248. # don't cleanup
  249. while win.children:
  250. win.remove_widget(win.children[0])
  251. win.add_widget(scroll)
  252. # get widgets ready
  253. EventLoop.idle()
  254. e = scroll.effect_y
  255. assert e.velocity == 0
  256. touch = UTMotionEvent("unittest", next(touch_id), {
  257. "x": scroll.center_x / float(win.width),
  258. "y": scroll.center_y / float(win.height),
  259. })
  260. touch.profile.append('button')
  261. touch.button = 'scrollup'
  262. EventLoop.post_dispatch_input("begin", touch)
  263. # EventLoop.post_dispatch_input("update", touch)
  264. assert e.velocity == 10 * scroll.scroll_wheel_distance
  265. EventLoop.idle()
  266. assert 0 < e.velocity < 10 * scroll.scroll_wheel_distance
  267. EventLoop.post_dispatch_input("end", touch)
  268. EventLoop.idle()
  269. assert 0 < e.velocity < 10 * scroll.scroll_wheel_distance
  270. # wait for velocity to die off
  271. while e.velocity:
  272. EventLoop.idle()
  273. touch = UTMotionEvent("unittest", next(touch_id), {
  274. "x": scroll.center_x / float(win.width),
  275. "y": scroll.center_y / float(win.height),
  276. })
  277. touch.profile.append('button')
  278. touch.button = 'scrolldown'
  279. EventLoop.post_dispatch_input("begin", touch)
  280. # EventLoop.post_dispatch_input("update", touch)
  281. assert e.velocity == -10 * scroll.scroll_wheel_distance
  282. EventLoop.idle()
  283. assert 0 > e.velocity > -10 * scroll.scroll_wheel_distance
  284. EventLoop.post_dispatch_input("end", touch)
  285. EventLoop.idle()
  286. assert 0 > e.velocity > -10 * scroll.scroll_wheel_distance
  287. if __name__ == '__main__':
  288. import unittest
  289. unittest.main()