Skip to content

ratio系のメソッドを無限ループするようにし、引数durationをbaseに置き換え #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "asyncgui-ext-clock"
version = "0.4.0"
version = "0.5.0.dev0"
description = "An event scheduler for asyncgui programs"
authors = ["Nattōsai Mitō <[email protected]>"]
license = "MIT"
Expand Down
87 changes: 53 additions & 34 deletions src/asyncgui_ext/clock.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,16 +210,19 @@ def callback(dt):

async def anim_with_et(self, *, step=0) -> AsyncIterator[TimeUnit]:
'''
Same as :meth:`anim_with_dt` except this one generates the total elapsed time of the loop instead of the elapsed
time between frames.

.. code-block::

timeout = ...
async for et in clock.anim_with_et():
...
if et > timeout:
break
print(et)

The code above is equivalent to the below.

.. code-block::

et = 0
async for dt in clock.anim_with_dt():
et += dt
print(et)
'''
et = 0
async with _repeat_sleeping(self, step) as sleep:
Expand All @@ -243,54 +246,62 @@ async def anim_with_dt_et(self, *, step=0) -> AsyncIterator[tuple[TimeUnit, Time
et += dt
yield dt, et

async def anim_with_ratio(self, *, duration, step=0) -> AsyncIterator[float]:
async def anim_with_ratio(self, *, base, step=0) -> AsyncIterator[float]:
'''
Same as :meth:`anim_with_et` except this one generates the total progression ratio of the loop.

.. code-block::

async for p in self.anim_with_ratio(duration=...):
async for p in clock.anim_with_ratio(base=100):
print(p * 100, "%")

The code above is equivalent to the below.

.. code-block::

base = 100
async for et in clock.anim_with_et():
print(et / base * 100, "%")

If you want to progress at a non-consistant rate, you may find the
`source code <https://github.com/kivy/kivy/blob/master/kivy/animation.py>`__
of the :class:`kivy.animation.AnimationTransition` helpful.

.. code-block::

async for p in clock.anim_with_ratio(duration=...):
async for p in clock.anim_with_ratio(base=...):
p = p * p # quadratic
print(p * 100, "%")

.. versionchanged:: 0.5.0

The ``duration`` parameter was replaced with the ``base`` parameter.
The loop no longer stops when the progression reaches 1.0.
'''
if not duration:
await self.sleep(step)
yield 1.0
return
et = 0
async with _repeat_sleeping(self, step) as sleep:
while et < duration:
while True:
et += await sleep()
yield et / duration
yield et / base

async def anim_with_dt_et_ratio(self, *, duration, step=0) -> AsyncIterator[tuple[TimeUnit, TimeUnit, float]]:
async def anim_with_dt_et_ratio(self, *, base, step=0) -> AsyncIterator[tuple[TimeUnit, TimeUnit, float]]:
'''
:meth:`anim_with_dt`, :meth:`anim_with_et` and :meth:`anim_with_ratio` combined.

.. code-block::

async for dt, et, p in clock.anim_with_dt_et_ratio(...):
...

.. versionchanged:: 0.5.0

The ``duration`` parameter was replaced with the ``base`` parameter.
The loop no longer stops when the progression reaches 1.0.
'''
async with _repeat_sleeping(self, step) as sleep:
if not duration:
dt = await sleep()
yield dt, dt, 1.0
return
et = 0.
while et < duration:
while True:
dt = await sleep()
et += dt
yield dt, et, et / duration
yield dt, et, et / base

def _linear(p):
return p
Expand All @@ -316,10 +327,13 @@ async def interpolate_scalar(self, start, end, *, duration, step=0, transition=_
'''
slope = end - start
yield transition(0.) * slope + start
async for p in self.anim_with_ratio(step=step, duration=duration):
if p >= 1.0:
break
yield transition(p) * slope + start
if duration:
async for p in self.anim_with_ratio(step=step, base=duration):
if p >= 1.0:
break
yield transition(p) * slope + start
else:
await self.sleep(0)
yield transition(1.) * slope + start

async def interpolate_sequence(self, start, end, *, duration, step=0, transition=_linear, output_type=tuple) -> AsyncIterator:
Expand Down Expand Up @@ -347,15 +361,20 @@ async def interpolate_sequence(self, start, end, *, duration, step=0, transition
p = transition(0.)
yield output_type(p * slope_elem + start_elem for slope_elem, start_elem in zip_(slope, start))

async for p in self.anim_with_ratio(step=step, duration=duration):
if p >= 1.0:
break
p = transition(p)
yield output_type(p * slope_elem + start_elem for slope_elem, start_elem in zip_(slope, start))
if duration:
async for p in self.anim_with_ratio(step=step, base=duration):
if p >= 1.0:
break
p = transition(p)
yield output_type(p * slope_elem + start_elem for slope_elem, start_elem in zip_(slope, start))
else:
await self.sleep(0)

p = transition(1.)
yield output_type(p * slope_elem + start_elem for slope_elem, start_elem in zip_(slope, start))

interpolate_seq = interpolate_sequence

async def run_in_thread(self, func, *, daemon=None, polling_interval) -> Awaitable:
'''
Creates a new thread, runs a function within it, then waits for the completion of that function.
Expand Down
33 changes: 21 additions & 12 deletions tests/clock/test_anim_with_xxx.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import pytest


def test_anim_with_dt(clock):
from asyncgui import start
dt_list = []
Expand Down Expand Up @@ -50,8 +53,10 @@ def test_anim_with_ratio(clock):
p_list = []

async def async_fn():
async for p in clock.anim_with_ratio(step=10, duration=100):
async for p in clock.anim_with_ratio(step=10, base=100):
p_list.append(p)
if p >= 1:
break

task = start(async_fn())
assert p_list == []
Expand All @@ -70,21 +75,22 @@ async def async_fn():
assert task.finished


def test_anim_with_ratio_zero_duration(clock):
def test_anim_with_ratio_zero_base(clock):
from asyncgui import start
p_list = []

async def async_fn():
async for p in clock.anim_with_ratio(step=10, duration=0):
async for p in clock.anim_with_ratio(step=10, base=0):
p_list.append(p)

task = start(async_fn())
assert p_list == []
clock.tick(6)
assert p_list == []
clock.tick(6)
assert p_list == [1.0, ]
assert task.finished
with pytest.raises(ZeroDivisionError):
clock.tick(6)
assert p_list == []
assert task.cancelled


def test_anim_with_dt_et(clock):
Expand Down Expand Up @@ -117,8 +123,10 @@ def test_anim_with_dt_et_ratio(clock):
values = []

async def async_fn():
async for v in clock.anim_with_dt_et_ratio(step=10, duration=100):
async for v in clock.anim_with_dt_et_ratio(step=10, base=100):
values.extend(v)
if values[2] >= 1:
break

task = start(async_fn())
assert values == []
Expand Down Expand Up @@ -146,18 +154,19 @@ async def async_fn():
assert task.finished


def test_anim_with_dt_et_ratio_zero_duration(clock):
def test_anim_with_dt_et_ratio_zero_base(clock):
from asyncgui import start
values = []

async def async_fn():
async for v in clock.anim_with_dt_et_ratio(step=10, duration=0):
async for v in clock.anim_with_dt_et_ratio(step=10, base=0):
values.extend(v)

task = start(async_fn())
assert values == []
clock.tick(6)
assert values == []
clock.tick(6)
assert values == [12, 12, 1.0]
assert task.finished
with pytest.raises(ZeroDivisionError):
clock.tick(6)
assert values == []
assert task.cancelled
Loading