def test_the_touch_that_might_already_ended(actually_ended):
    import time
    from kivy.clock import Clock
    from kivy.uix.widget import Widget
    from kivy.tests.common import UnitTestTouch
    import asynckivy as ak
    from asynckivy.exceptions import MotionEventAlreadyEndedError
    Clock.tick()

    async def job(w, t):
        if actually_ended:
            with pytest.raises(MotionEventAlreadyEndedError):
                async for __ in ak.rest_of_touch_moves(w, t):
                    pass
        else:
            async for __ in ak.rest_of_touch_moves(w, t):
                pass

    w = Widget()
    t = UnitTestTouch(0, 0)
    t.time_end = 1  # something other than -1
    task = ak.start(job(w, t))

    if actually_ended:
        time.sleep(2.)
        Clock.tick()
    else:
        t.grab_current = None
        w.dispatch('on_touch_up', t)
        t.grab_current = w
        w.dispatch('on_touch_up', t)
    assert task.done
def test_a_number_of_on_touch_moves_fired(touch_cls, n_touch_moves):
    from time import perf_counter
    from kivy.uix.widget import Widget
    import asynckivy as ak

    async def _test(w, t):
        n = 0
        async for __ in ak.rest_of_touch_moves(w, t):
            n += 1
        assert n == n_touch_moves
        nonlocal done
        done = True

    done = False
    w = Widget()
    t = touch_cls()
    ak.start(_test(w, t))
    for __ in range(n_touch_moves):
        t.grab_current = None
        w.dispatch('on_touch_move', t)
        t.grab_current = w
        w.dispatch('on_touch_move', t)
    t.grab_current = None
    w.dispatch('on_touch_up', t)
    t.grab_current = w
    w.dispatch('on_touch_up', t)
    assert done
def test_break_during_a_for_loop(touch_cls, holds_a_ref):
    from kivy.uix.widget import Widget
    import asynckivy as ak

    async def _test(w, t):
        import weakref
        nonlocal n_touch_moves
        weak_w = weakref.ref(w)
        assert weak_w not in t.grab_list
        if holds_a_ref:
            agen = ak.rest_of_touch_moves(w, t)
            async for __ in agen:
                assert weak_w in t.grab_list
                n_touch_moves += 1
                if n_touch_moves == 2:
                    break
        else:
            async for __ in ak.rest_of_touch_moves(w, t):
                assert weak_w in t.grab_list
                n_touch_moves += 1
                if n_touch_moves == 2:
                    break
        assert weak_w not in t.grab_list  # fails if holds_a_ref is True
        await ak.event(w, 'on_touch_up')
        nonlocal done
        done = True

    n_touch_moves = 0
    done = False
    w = Widget()
    t = touch_cls()
    ak.start(_test(w, t))
    for expected in (
            1,
            2,
            2,
    ):
        t.grab_current = None
        w.dispatch('on_touch_move', t)
        t.grab_current = w
        w.dispatch('on_touch_move', t)
        assert n_touch_moves == expected
        assert not done
    t.grab_current = None
    w.dispatch('on_touch_up', t)
    t.grab_current = w
    w.dispatch('on_touch_up', t)
    assert n_touch_moves == 2
    assert done
def test_eat_touch_events(touch_cls, eat_touch, expectation):
    from kivy.uix.widget import Widget
    import asynckivy as ak

    async def _test(parent, t):
        async for __ in ak.rest_of_touch_moves(parent, t, eat_touch=eat_touch):
            pass
        nonlocal done
        done = True

    done = False

    n_touches = {
        'move': 0,
        'up': 0,
    }

    def on_touch_move(*args):
        n_touches['move'] += 1

    def on_touch_up(*args):
        n_touches['up'] += 1

    parent = Widget()
    child = Widget(
        on_touch_move=on_touch_move,
        on_touch_up=on_touch_up,
    )
    parent.add_widget(child)
    t = touch_cls()
    ak.start(_test(parent, t))

    for i in range(2):
        t.grab_current = None
        parent.dispatch('on_touch_move', t)
        t.grab_current = parent
        parent.dispatch('on_touch_move', t)
        assert n_touches['move'] == expectation[i]
    t.grab_current = None
    parent.dispatch('on_touch_up', t)
    t.grab_current = parent
    parent.dispatch('on_touch_up', t)
    assert n_touches['up'] == expectation[2]
    assert done
def test_stop_dispatching(stop_dispatching, expectation):
    from kivy.uix.widget import Widget
    from kivy.tests.common import UnitTestTouch
    import asynckivy as ak

    async def _test(parent, t):
        async for __ in ak.rest_of_touch_moves(
                parent, t, stop_dispatching=stop_dispatching):
            pass

    n_touches = {
        'move': 0,
        'up': 0,
    }

    def on_touch_move(*args):
        n_touches['move'] += 1

    def on_touch_up(*args):
        n_touches['up'] += 1

    parent = Widget()
    child = Widget(
        on_touch_move=on_touch_move,
        on_touch_up=on_touch_up,
    )
    parent.add_widget(child)
    t = UnitTestTouch(0, 0)
    task = ak.start(_test(parent, t))

    for i in range(2):
        t.grab_current = None
        parent.dispatch('on_touch_move', t)
        t.grab_current = parent
        parent.dispatch('on_touch_move', t)
        assert n_touches['move'] == expectation[i]
    t.grab_current = None
    parent.dispatch('on_touch_up', t)
    t.grab_current = parent
    parent.dispatch('on_touch_up', t)
    assert n_touches['up'] == expectation[2]
    assert task.done
def test_break_during_a_for_loop():
    from kivy.uix.widget import Widget
    from kivy.tests.common import UnitTestTouch
    import asynckivy as ak

    async def _test(w, t):
        import weakref
        nonlocal n_touch_moves
        weak_w = weakref.ref(w)
        assert weak_w not in t.grab_list
        async for __ in ak.rest_of_touch_moves(w, t):
            assert weak_w in t.grab_list
            n_touch_moves += 1
            if n_touch_moves == 2:
                break
        assert weak_w not in t.grab_list
        await ak.event(w, 'on_touch_up')

    n_touch_moves = 0
    w = Widget()
    t = UnitTestTouch(0, 0)
    task = ak.start(_test(w, t))
    for expected in (
            1,
            2,
            2,
    ):
        t.grab_current = None
        w.dispatch('on_touch_move', t)
        t.grab_current = w
        w.dispatch('on_touch_move', t)
        assert n_touch_moves == expected
        assert not task.done
    t.grab_current = None
    w.dispatch('on_touch_up', t)
    t.grab_current = w
    w.dispatch('on_touch_up', t)
    assert n_touch_moves == 2
    assert task.done
def test_a_number_of_on_touch_moves_fired(n_touch_moves):
    from kivy.uix.widget import Widget
    from kivy.tests.common import UnitTestTouch
    import asynckivy as ak

    async def _test(w, t):
        n = 0
        async for __ in ak.rest_of_touch_moves(w, t):
            n += 1
        assert n == n_touch_moves

    w = Widget()
    t = UnitTestTouch(0, 0)
    task = ak.start(_test(w, t))
    for __ in range(n_touch_moves):
        t.grab_current = None
        w.dispatch('on_touch_move', t)
        t.grab_current = w
        w.dispatch('on_touch_move', t)
    t.grab_current = None
    w.dispatch('on_touch_up', t)
    t.grab_current = w
    w.dispatch('on_touch_up', t)
    assert task.done
예제 #8
0
class Replay(App):
    """A widget that replays a game from a log file captured by Logger

    Replay monkeypatches kivy.clock.time to fire events read from the log
    file.

    Touching the replay will change the replay speed based on the y (up/down)
    -coordinate of the touch, from 50% to 200%. (NB. every clock tick is still
    processed, so speedups might not actually be that big).

    This is more of a dirty hack than other parts of the code.
    """
    def __init__(self, log_filename):
        super(Replay, self).__init__()
        self.log_filename = log_filename
        kivy.clock.time = self.time
        self.stream = gzip.GzipFile(fileobj=open(self.log_filename, 'rb'))
        self.first_tick = time()
        self.last_tick = time()
        self.time_elapsed = 0
        self.stream_time = 0
        self.next_id = 0
        self.clock_speed = 1
        self.running = True

    def build(self):
        self.top_widget = Widget()
        self.content_widget = Widget()
        self.top_widget.add_widget(self.content_widget)
        self.top_widget.add_widget(SpeedAdjuster(self))
        return self.top_widget

    def time(self):
        """Like time.time(), but handles events from the log file
        """
        current = time()
        self.time_elapsed += (current - self.last_tick) * self.clock_speed
        self.last_tick = current
        if not self.running:
            return self.last_tick
        while self.stream and self.time_elapsed > self.stream_time:
            try:
                rec = pickle.load(self.stream)
            except EOFError:
                self.handle__end()
                self.running = False
                break
            else:
                getattr(self, 'handle_' + rec[0])(*rec[1:])
                if rec[0] == 'dt':
                    # Ensure every tick gets handled
                    break
        return self.first_tick + self.stream_time

    def handle__end(self):
        parent = self.top_widget.get_parent_window()
        with self.top_widget.canvas:
            Color(0, 0, 0.2, 0.5)
            Rectangle(size=(parent.width, 40),
                    pos=(0, parent.height / 2 - 20))
        self.top_widget.add_widget(Label(text='Replay finished',
                width=self.top_widget.get_parent_window().width,
                pos=(0, parent.height / 2 - 5), height=10, color=(1, 1, 1, 1)))

    # Handlers for events from the log file:

    def handle_random(self, state):
        """Set the random state"""
        random.setstate(state)

    def handle_add_widget(self, cls):
        """Add a child widget"""
        self.content_widget.add_widget(cls())

    def handle_dt(self, dt):
        """Tick the clock"""
        self.stream_time += dt

    def handle_down(self, attrs):
        """Generate a touch-down event"""
        self.handle__touch_event(attrs, 'on_touch_down')

    def handle_move(self, attrs):
        """Generate a touch-move event"""
        self.handle__touch_event(attrs, 'on_touch_move')

    def handle_up(self, attrs):
        """Generate a touch-up event"""
        self.handle__touch_event(attrs, 'on_touch_up')

    def handle__touch_event(self, attrs, event):
        """Generate any touch-down event"""
        touch = ReplayMotionEvent(None, attrs['id'], attrs)
        for name, value in attrs.items():
            setattr(touch, name, value)
        self.content_widget.dispatch(event, touch)

    def handle_window_size(self, width, height):
        print width, height
        children_to_do = set([self.content_widget])
        children_done = set()
        while children_to_do:
            child = children_to_do.pop()
            child.window_width = width
            child.window_height = height
            children_done.add(child)
            children_to_do.update(child.children)
            children_to_do.difference_update(children_done)
        self.content_widget.canvas.before.clear()
        with self.content_widget.canvas.before:
            PushMatrix()
            win = self.content_widget.get_parent_window()
            window_width = win.width
            window_height = win.height
            the_min = min(window_width / width, window_height / height)
            Scale(the_min)
        self.content_widget.canvas.after.clear()
        with self.content_widget.canvas.after:
            PopMatrix()
예제 #9
0
class Replay(App):
    """A widget that replays a game from a log file captured by Logger

    Replay monkeypatches kivy.clock.time to fire events read from the log
    file.

    Touching the replay will change the replay speed based on the y (up/down)
    -coordinate of the touch, from 50% to 200%. (NB. every clock tick is still
    processed, so speedups might not actually be that big).

    This is more of a dirty hack than other parts of the code.
    """
    def __init__(self, log_filename):
        super(Replay, self).__init__()
        self.log_filename = log_filename
        kivy.clock.time = self.time
        self.stream = gzip.GzipFile(fileobj=open(self.log_filename, 'rb'))
        self.first_tick = time()
        self.last_tick = time()
        self.time_elapsed = 0
        self.stream_time = 0
        self.next_id = 0
        self.clock_speed = 1
        self.running = True

    def build(self):
        self.top_widget = Widget()
        self.content_widget = Widget()
        self.top_widget.add_widget(self.content_widget)
        self.top_widget.add_widget(SpeedAdjuster(self))
        return self.top_widget

    def time(self):
        """Like time.time(), but handles events from the log file
        """
        current = time()
        self.time_elapsed += (current - self.last_tick) * self.clock_speed
        self.last_tick = current
        if not self.running:
            return self.last_tick
        while self.stream and self.time_elapsed > self.stream_time:
            try:
                rec = pickle.load(self.stream)
            except EOFError:
                self.handle__end()
                self.running = False
                break
            else:
                getattr(self, 'handle_' + rec[0])(*rec[1:])
                if rec[0] == 'dt':
                    # Ensure every tick gets handled
                    break
        return self.first_tick + self.stream_time

    def handle__end(self):
        parent = self.top_widget.get_parent_window()
        with self.top_widget.canvas:
            Color(0, 0, 0.2, 0.5)
            Rectangle(size=(parent.width, 40), pos=(0, parent.height / 2 - 20))
        self.top_widget.add_widget(
            Label(text='Replay finished',
                  width=self.top_widget.get_parent_window().width,
                  pos=(0, parent.height / 2 - 5),
                  height=10,
                  color=(1, 1, 1, 1)))

    # Handlers for events from the log file:

    def handle_random(self, state):
        """Set the random state"""
        random.setstate(state)

    def handle_add_widget(self, cls):
        """Add a child widget"""
        self.content_widget.add_widget(cls())

    def handle_dt(self, dt):
        """Tick the clock"""
        self.stream_time += dt

    def handle_down(self, attrs):
        """Generate a touch-down event"""
        self.handle__touch_event(attrs, 'on_touch_down')

    def handle_move(self, attrs):
        """Generate a touch-move event"""
        self.handle__touch_event(attrs, 'on_touch_move')

    def handle_up(self, attrs):
        """Generate a touch-up event"""
        self.handle__touch_event(attrs, 'on_touch_up')

    def handle__touch_event(self, attrs, event):
        """Generate any touch-down event"""
        touch = ReplayMotionEvent(None, attrs['id'], attrs)
        for name, value in attrs.items():
            setattr(touch, name, value)
        self.content_widget.dispatch(event, touch)

    def handle_window_size(self, width, height):
        print width, height
        children_to_do = set([self.content_widget])
        children_done = set()
        while children_to_do:
            child = children_to_do.pop()
            child.window_width = width
            child.window_height = height
            children_done.add(child)
            children_to_do.update(child.children)
            children_to_do.difference_update(children_done)
        self.content_widget.canvas.before.clear()
        with self.content_widget.canvas.before:
            PushMatrix()
            win = self.content_widget.get_parent_window()
            window_width = win.width
            window_height = win.height
            the_min = min(window_width / width, window_height / height)
            Scale(the_min)
        self.content_widget.canvas.after.clear()
        with self.content_widget.canvas.after:
            PopMatrix()