Skip to content

Commit

Permalink
1st impl
Browse files Browse the repository at this point in the history
  • Loading branch information
gottadiveintopython committed Dec 23, 2023
1 parent befd086 commit bf2b4fd
Show file tree
Hide file tree
Showing 13 changed files with 45 additions and 69 deletions.
2 changes: 1 addition & 1 deletion examples/coundown.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def draw(draw_target: pygame.Surface):

with ap.DrawingRequest(draw):
for i in range(count_from, -1, -1):
img = font.render(str(i), True, fg_color)
img = font.render(str(i), True, fg_color).convert_alpha()
await ap.sleep(1000)
await ap.sleep_forever()

Expand Down
2 changes: 1 addition & 1 deletion examples/move_on_after.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

async def main(draw_target):
font = pygame.font.SysFont(None, 40)
img = font.render("This animation will be interrupted in 6 seconds", True, pygame.Color("white"))
img = font.render("This animation will be interrupted in 6 seconds", True, pygame.Color("white")).convert_alpha()
dst_rect = draw_target.get_rect()
img_rect = img.get_rect()
img_rect.centerx = dst_rect.centerx
Expand Down
2 changes: 1 addition & 1 deletion examples/overlapping_buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def draw(draw_target: pygame.Surface):

with ap.DrawingRequest(draw):
while True:
button_press_event = await ap.sdl_event_pro(priority=zorder, filter=partial(button_press_filter, dst))
button_press_event = await ap.sdl_event(priority=zorder, filter=partial(button_press_filter, dst))
final_img.set_alpha(150)
print(f"'{text}' pressed")
await ap.sdl_event(priority=zorder, filter=partial(button_release_filter, button_press_event.button))
Expand Down
4 changes: 2 additions & 2 deletions src/asyncpygame/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__all__ = (
'init',
'DEFAULT_PRIORITY', 'DEFAULT_ZORDER',
'DEFAULT_PRIORITY', 'DEFAULT_ZORDER', 'STOP_DISPATCHING',
'sleep', 'move_on_after',
'anim_with_dt', 'anim_with_dt_et', 'anim_with_et', 'anim_with_ratio', 'anim_with_dt_et_ratio',
'run_in_thread', 'run_in_executor',
Expand All @@ -9,7 +9,7 @@
)

from asyncgui import *
from ._api_impl.constants import DEFAULT_PRIORITY, DEFAULT_ZORDER
from ._api_impl.constants import DEFAULT_PRIORITY, DEFAULT_ZORDER, STOP_DISPATCHING
from ._api_facade import (
sleep, move_on_after,
anim_with_dt, anim_with_dt_et, anim_with_et, anim_with_ratio, anim_with_dt_et_ratio,
Expand Down
27 changes: 6 additions & 21 deletions src/asyncpygame/_api_facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

EventFilter: TypeAlias = Callable[[Event], bool]
EventFilterPro: TypeAlias = Callable[[Event], tuple[bool, bool]]
FuncDraw: TypeAlias = Callable[[Surface], None]
DrawFunc: TypeAlias = Callable[[Surface], None]


def sleep(duration: TimeUnit) -> Awaitable[None]:
Expand Down Expand Up @@ -182,21 +182,6 @@ def sdl_event(*, priority=DEFAULT_PRIORITY, filter: EventFilter=_accept_any) ->
'''


def sdl_event_pro(*, priority=DEFAULT_PRIORITY, filter: EventFilterPro) -> Awaitable[Event]:
'''
:func:`sdl_event` にイベントの伝搬を拒む機能を加えた物。
このAPIの目的は
* ボタンが重なっている時に下にある物にマウスやタッチ操作を伝えたくない
* ダイアログを開いている時に下にある全ての物にイベントを伝えたくない
といった事の実現にあります。
:func:`sdl_event` とは違って ``filter`` 引数は真偽値2つからなるタプルを返す必要がある。
1つ目の真偽値は :func:`sdl_event` の ``filter`` と同じで
'''


def sdl_frequent_event(*, priority=DEFAULT_PRIORITY, filter: EventFilter=_accept_any) -> \
AbstractAsyncContextManager[Callable[[], Awaitable[Event]]]:
'''
Expand Down Expand Up @@ -252,23 +237,23 @@ def draw(draw_target: Surface):
req = DrawingRequest(draw, zorder=200)
``active`` は勿論 ``zorder`` と ``func_draw`` も後からいつでも変更可です。
``active`` は勿論 ``zorder`` と ``draw_func`` も後からいつでも変更可です。
.. code-block::
req.zorder = 100
req.func_draw = another_func
req.draw_func = another_func
req.active = False
またwith文にも利用でき、withブロックを抜ける時に自動で ``active`` が偽になります。
.. code-block::
with DrawingRequest(func_draw, zorder=200):
with DrawingRequest(draw_func, zorder=200):
...
'''

def __init__(self, func_draw: FuncDraw, /, *, zorder=DEFAULT_ZORDER, active=True):
def __init__(self, draw_func: DrawFunc, /, *, zorder=DEFAULT_ZORDER, active=True):
...

@property
Expand All @@ -278,7 +263,7 @@ def zorder(self) -> int:
'''

@property
def func_draw(self) -> FuncDraw:
def draw_func(self) -> DrawFunc:
'''
実際に描画を行う関数。
'''
Expand Down
4 changes: 2 additions & 2 deletions src/asyncpygame/_api_impl/_all.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .constants import DEFAULT_PRIORITY, STOP_DISPATCHING
from .constants import DEFAULT_PRIORITY, DEFAULT_ZORDER, STOP_DISPATCHING
from .timer import Timer, sleep, repeat_sleeping, move_on_after, TimeUnit
from .priority_dispatcher import PriorityDispatcher
from .priority_drawing import Drawer, DrawingRequest
from .animation import anim_with_dt, anim_with_dt_et, anim_with_et, anim_with_ratio, anim_with_dt_et_ratio
from .sdl_event import sdl_event, sdl_event_pro, sdl_frequent_event, sdl_frequent_event_pro
from .sdl_event import sdl_event, sdl_frequent_event
from .threads import run_in_thread, run_in_executor
1 change: 1 addition & 0 deletions src/asyncpygame/_api_impl/constants.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
DEFAULT_PRIORITY = 0
DEFAULT_ZORDER = 0
STOP_DISPATCHING = "STOP_DISPATCHING"
5 changes: 3 additions & 2 deletions src/asyncpygame/_api_impl/priority_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from heapq import merge as heapq_merge


from .constants import DEFAULT_PRIORITY
from .constants import DEFAULT_PRIORITY, STOP_DISPATCHING


@dataclass(slots=True)
Expand Down Expand Up @@ -102,14 +102,15 @@ def dispatch(self, *args):
sub_iter = iter(subs)
del subs_tba

STOP_DISPATCHING_ = STOP_DISPATCHING
subs2 = self._subs_2
subs2_append = subs2.append
try:
for sub in sub_iter:
if sub._cancelled:
continue
subs2_append(sub)
if sub.callback(*args):
if sub.callback(*args) is STOP_DISPATCHING_:
subs2.extend(sub_iter)
return
finally:
Expand Down
30 changes: 15 additions & 15 deletions src/asyncpygame/_api_impl/priority_drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@


class Request:
__slots__ = ('zorder', 'func_draw', 'cancelled', )
__slots__ = ('zorder', 'draw_func', 'cancelled', )

def __init__(self, zorder, func_draw):
def __init__(self, zorder, draw_func):
self.zorder = zorder
self.func_draw = func_draw
self.draw_func = draw_func
self.cancelled = False

def cancel(self):
Expand Down Expand Up @@ -66,24 +66,24 @@ def draw(self, draw_target: Surface):
if req.cancelled:
continue
reqs2_append(req)
req.func_draw(draw_target)
req.draw_func(draw_target)
finally:
reqs.clear()
self._reqs = reqs2
self._reqs_2 = reqs

def add_request(self, func_draw, zorder) -> Request:
req = Request(zorder, func_draw)
def add_request(self, draw_func, zorder) -> Request:
req = Request(zorder, draw_func)
self._reqs_to_be_added.append(req)
return req


class DrawingRequest:
__slots__ = ('_add_request', '_req', )

def __init__(self, add_request, func_draw, *, zorder=DEFAULT_ZORDER, active=True):
def __init__(self, add_request, draw_func, *, zorder=DEFAULT_ZORDER, active=True):
self._add_request = add_request
self._req = add_request(func_draw, zorder)
self._req = add_request(draw_func, zorder)
self.active = active

@property
Expand All @@ -99,15 +99,15 @@ def zorder(self, zorder):
req.zorder = zorder
else:
req.cancel()
self._req = self._add_request(req.func_draw, zorder)
self._req = self._add_request(req.draw_func, zorder)

@property
def func_draw(self):
return self._req.func_draw
def draw_func(self):
return self._req.draw_func

@func_draw.setter
def func_draw(self, func_draw):
self._req.func_draw = func_draw
@draw_func.setter
def draw_func(self, draw_func):
self._req.draw_func = draw_func

@property
def active(self) -> bool:
Expand All @@ -119,7 +119,7 @@ def active(self, active):
if req.cancelled is (not active):
return
if req.cancelled:
self._req = self._add_request(req.func_draw, req.zorder)
self._req = self._add_request(req.draw_func, req.zorder)
else:
req.cancel()

Expand Down
29 changes: 9 additions & 20 deletions src/asyncpygame/_api_impl/sdl_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,10 @@


def _resume_task(task_step, filter, event):
if filter(event):
r = filter(event)
if r:
task_step(event)


def _resume_task_pro(task_step, filter, event):
resume_task, stop_dispatching = filter(event)
if resume_task:
task_step(event)
return stop_dispatching
return r


def _accept_any(event):
Expand All @@ -24,7 +19,7 @@ def _accept_any(event):


@types.coroutine
def _sdl_event(resume_task, subscribe, *, priority=DEFAULT_PRIORITY, filter=_accept_any):
def sdl_event(partial, resume_task, subscribe, *, priority=DEFAULT_PRIORITY, filter=_accept_any):
task = (yield _current_task)[0][0]
sub = subscribe(partial(resume_task, task._step, filter), priority)
try:
Expand All @@ -33,15 +28,13 @@ def _sdl_event(resume_task, subscribe, *, priority=DEFAULT_PRIORITY, filter=_acc
sub.cancel()


sdl_event = partial(_sdl_event, _resume_task)
sdl_event_pro = partial(_sdl_event, _resume_task_pro)
sdl_event = partial(sdl_event, partial, _resume_task)


class _sdl_frequent_event:
__slots__ = ('_resume_task', '_subscribe', '_filter', '_priority', '_sub', )
class sdl_frequent_event:
__slots__ = ('_subscribe', '_filter', '_priority', '_sub', )

def __init__(self, resume_task, subscribe, *, filter=_accept_any, priority=DEFAULT_PRIORITY):
self._resume_task = resume_task
def __init__(self, subscribe, *, filter=_accept_any, priority=DEFAULT_PRIORITY):
self._subscribe = subscribe
self._filter = filter
self._priority = priority
Expand All @@ -55,14 +48,10 @@ def _wait_for_an_event_to_occur(_sleep_forever=_sleep_forever):
def __aenter__(self):
task = (yield _current_task)[0][0]
self._sub = self._subscribe(
partial(self._resume_task, task._step, self._filter),
partial(_resume_task, task._step, self._filter),
self._priority,
)
return self._wait_for_an_event_to_occur

async def __aexit__(self, *args):
self._sub.cancel()


sdl_frequent_event = partial(_sdl_frequent_event, _resume_task)
sdl_frequent_event_pro = partial(_sdl_frequent_event, _resume_task_pro)
2 changes: 1 addition & 1 deletion src/asyncpygame/_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def init() -> Runner:

dispatcher = _all.PriorityDispatcher()
event_apis = (
'sdl_event', 'sdl_event_pro', 'sdl_frequent_event', 'sdl_frequent_event_pro',
'sdl_event', 'sdl_frequent_event',
)
for name in event_apis:
setattr_(asyncpygame, name, partial(getattr_(_all, name), dispatcher.add_subscriber))
Expand Down
4 changes: 2 additions & 2 deletions tests/_api_impl/test_priority_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ def test_various_priorities():


def test_stop_dispatching():
from asyncpygame._api_impl.priority_dispatcher import PriorityDispatcher
from asyncpygame._api_impl.priority_dispatcher import PriorityDispatcher, STOP_DISPATCHING

d = PriorityDispatcher()
value_list = []
d.add_subscriber(value_list.append, priority=0)
d.add_subscriber(value_list.append, priority=2)
d.dispatch('A')
assert value_list == ['A', 'A']
s = d.add_subscriber(lambda v: True, priority=1)
s = d.add_subscriber(lambda v: STOP_DISPATCHING, priority=1)
d.dispatch('B')
assert value_list == ['A', 'A', 'B', ]
s.cancel()
Expand Down
2 changes: 1 addition & 1 deletion tests/_api_impl/test_priority_drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def test_various_zorders():
d.draw('D')
assert value_list == ['d', 'DD', 'D', ]
value_list.clear()
req.draw = lambda v: value_list.append(v + v + v)
req.draw_func = lambda v: value_list.append(v + v + v)
d.draw('E')
assert value_list == ['EEE', 'EE', 'E', ]

Expand Down

0 comments on commit bf2b4fd

Please sign in to comment.