From 6d320927d0fef76d358fd466e1bd6c07a1eb5b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Natt=C5=8Dsai=20Mit=C5=8D?= Date: Wed, 16 Oct 2024 10:30:30 +0900 Subject: [PATCH] edit examples --- examples/06_full_blown_app_structure.py | 41 +++--- examples/_uix/anchor_layout.py | 59 ++------- examples/_uix/modal_dialog.py | 89 +++++++------ examples/_uix/progress_spinner.py | 2 +- examples/_uix/ripple_button.py | 159 ++++++++++-------------- examples/_uix_anchor_layout.py | 14 +-- examples/_uix_ripple_button.py | 20 ++- examples/asking_question.py | 19 +-- examples/network_io.py | 60 --------- examples/network_io_with_animation.py | 70 +++++++---- 10 files changed, 224 insertions(+), 309 deletions(-) delete mode 100644 examples/network_io.py diff --git a/examples/06_full_blown_app_structure.py b/examples/06_full_blown_app_structure.py index a6bb3bd..8564420 100644 --- a/examples/06_full_blown_app_structure.py +++ b/examples/06_full_blown_app_structure.py @@ -9,8 +9,8 @@ import asyncpygame as apg from asyncpygame.scene_switcher import SceneSwitcher, FadeTransition from _uix.touch_indicator import touch_indicator -from _uix.anchor_layout import AnchorLayout -from _uix.ripple_button import RippleButton +from _uix.anchor_layout import anchor_layout +from _uix.ripple_button import ripple_button from _uix.modal_dialog import ask_yes_no_question @@ -47,17 +47,20 @@ async def title_scene(*, scene_switcher, userdata, **kwargs: Unpack[apg.CommonPa target_rect = draw_target.get_rect() font = userdata['font'] async with apg.open_nursery() as nursery: - AnchorLayout( - nursery, + e_start = apg.Event() + s = nursery.start + s(anchor_layout( font.render("", True, "white", userdata["bgcolor"]).convert(draw_target), target_rect.scale_by(1.0, 0.5).move_to(y=target_rect.y), - priority=0x100, **kwargs) - start_button = RippleButton( - nursery, + priority=0x100, + **kwargs)) + s(ripple_button( button_image := font.render("Start", True, "white").convert_alpha(), button_image.get_rect(center=target_rect.scale_by(1.0, 0.5).move_to(bottom=target_rect.bottom).center).inflate(80, 80), - priority=0x100, **kwargs) - await start_button.to_be_clicked() + on_click=e_start.fire, + priority=0x100, + **kwargs)) + await e_start.wait() scene_switcher.switch_to(menu_scene, FadeTransition()) await apg.sleep_forever() @@ -67,20 +70,20 @@ async def menu_scene(*, scene_switcher, userdata, **kwargs: Unpack[apg.CommonPar target_rect = draw_target.get_rect() font = userdata['font'] async with apg.open_nursery() as nursery: - play_button = RippleButton( - nursery, + e_play = apg.Event() + e_back = apg.Event() + s = nursery.start + s(ripple_button( button_image := font.render("Play Game", True, "white").convert_alpha(), button_image.get_rect(center=target_rect.scale_by(1.0, 0.5).move_to(y=target_rect.y).center).inflate(80, 80), - priority=0x100, **kwargs) - back_button = RippleButton( - nursery, + on_click=e_play.fire, + priority=0x100, **kwargs)) + s(ripple_button( button_image := font.render("Back to Title", True, "white").convert_alpha(), button_image.get_rect(center=target_rect.scale_by(1.0, 0.5).move_to(bottom=target_rect.bottom).center).inflate(80, 80), - priority=0x100, **kwargs) - tasks = await apg.wait_any( - play_button.to_be_clicked(), - back_button.to_be_clicked(), - ) + on_click=e_back.fire, + priority=0x100, **kwargs)) + tasks = await apg.wait_any(e_play.wait(), e_back.wait()) next_scene = title_scene if tasks[1].finished else game_scene scene_switcher.switch_to(next_scene, FadeTransition()) await apg.sleep_forever() diff --git a/examples/_uix/anchor_layout.py b/examples/_uix/anchor_layout.py index cbb0586..58437ff 100644 --- a/examples/_uix/anchor_layout.py +++ b/examples/_uix/anchor_layout.py @@ -1,65 +1,30 @@ -__all__ = ('AnchorLayout', ) +__all__ = ('anchor_layout', ) -from typing import Self from functools import partial -from asyncgui import Nursery, sleep_forever +import asyncgui from pygame import Surface, Rect -class AnchorLayout: +async def anchor_layout( + image: Surface, dest: Rect, priority, *, anchor_image="center", anchor_dest="center", + executor, draw_target, **__): ''' .. code-block:: async with asyncpygame.open_nursery() as nursery: image = Surface(...) dest = Rect(...) - layout = AnchorLayout(nursery, image, dest, **common_params) - # Aligns the right edge of the image with the right edge of the layout. - layout.anchor_src = "right" - layout.anchor_dest = "right" - - # Aligns the center of the image with the midtop of the layout. - layout.anchor_src = "center" - layout.anchor_dest = "midtop" - - # You can change its image anytime. - layout.image = another_image - - # You can move or resize the layout by updating the ``dest``. - dest.right = ... - dest.width = ... - - # but you cannot assign another Rect instance to the layout. - layout.dest = another_rect # NOT ALLOWED + nursery.start(anchor_layout(image, dest, priority=..., **common_params)) ''' - def __init__(self, owner: Nursery, image: Surface, dest: Rect, - *, anchor_src="center", anchor_dest="center", **common_params): - ''' - :param owner: AnchorLayout cannot outlive its owner. When the owner is closed, the sprite is destroyed. - :param anchor_src: This must be any of the ``Rect``s positional attribute names. (e.g. "topleft", "bottomleft", ...) - :param anchor_dest: Same as ``anchor_src``. - ''' - self._dest = dest - self.image = image - self.anchor_src = anchor_src - self.anchor_dest = anchor_dest - self._main_task = owner.start(self._main(**common_params), daemon=True) - - def kill(self): - self._main_task.cancel() + with executor.register(partial(_draw, draw_target.blit, image, image.get_rect(), dest, anchor_image, anchor_dest), priority): + await asyncgui.sleep_forever() - @property - def dest(self) -> Rect: - return self._dest - async def _main(self, *, priority, draw_target, executor, **unused): - with executor.register(partial(self._draw, draw_target.blit, self._dest, self), priority=priority): - await sleep_forever() +def _draw(getattr, setattr, blit, image, src: Rect, dest: Rect, anchor_image, anchor_dest): + setattr(src, anchor_image, getattr(dest, anchor_dest)) + blit(image, src) - def _draw(getattr, blit, dest, self: Self): - image = self.image - blit(image, image.get_rect(**{self.anchor_src: getattr(dest, self.anchor_dest)})) - _draw = partial(_draw, getattr) +_draw = partial(_draw, getattr, setattr) diff --git a/examples/_uix/modal_dialog.py b/examples/_uix/modal_dialog.py index f0c18b1..8071aa8 100644 --- a/examples/_uix/modal_dialog.py +++ b/examples/_uix/modal_dialog.py @@ -5,20 +5,20 @@ from functools import partial import asyncgui -from pygame import Rect +from pygame.colordict import THECOLORS +from pygame import Rect, Surface from pygame.font import SysFont from asyncpygame import CommonParams, block_input_events, Clock -from _uix.ripple_button import RippleButton -from _uix.anchor_layout import AnchorLayout +from _uix.ripple_button import ripple_button +from _uix.anchor_layout import anchor_layout @asynccontextmanager async def darken(*, priority, **kwargs: Unpack[CommonParams]): interpolate = kwargs["clock"].interpolate_scalar draw_target = kwargs["draw_target"] - overlay_surface = draw_target.copy() - overlay_surface.fill("black") + overlay_surface = Surface(draw_target.size) set_alpha = overlay_surface.set_alpha with kwargs["executor"].register(partial(draw_target.blit, overlay_surface), priority): async for v in interpolate(0, 180, duration=200): @@ -28,7 +28,7 @@ async def darken(*, priority, **kwargs: Unpack[CommonParams]): set_alpha(v) -async def translate_rects_vertically(clock: Clock, rects, movement, duration): +async def move_rects_vertically(clock: Clock, rects, movement, duration): org_ys = tuple(rect.y for rect in rects) async for v in clock.interpolate_scalar(0, movement, duration=duration): for rect, org_y in zip(rects, org_ys): @@ -36,14 +36,14 @@ async def translate_rects_vertically(clock: Clock, rects, movement, duration): async def show_messagebox( - message, *, dialog_size: Rect=None, font=None, text_ok='OK', - priority, **kwargs: Unpack[CommonParams]) -> bool: + message, priority, *, dialog_size: Rect=None, font=None, text_ok='OK', + **kwargs: Unpack[CommonParams]) -> bool: ''' .. code-block:: await show_messagebox("Hello World", priority=0xFFFFFA00, **kwargs) ''' - bgcolor = "grey90" + bgcolor = THECOLORS["grey90"] clock = kwargs["clock"] draw_target = kwargs["draw_target"] if font is None: @@ -56,33 +56,37 @@ async def show_messagebox( dialog_size = target_rect.inflate(-100, 0) dialog_size.height = dialog_size.width // 2 dialog_dest = dialog_size.move_to(bottom=target_rect.top) + e_ok = asyncgui.Event() with kwargs["executor"].register(partial(draw_target.fill, bgcolor, dialog_dest), priority=priority + 1): - label = AnchorLayout( - nursery, + s = nursery.start + s(anchor_layout( font.render(message, True, "black", bgcolor).convert(draw_target), - dialog_dest.scale_by(1.0, 0.7).move_to(top=dialog_dest.top).inflate(-10, -10), - priority=priority + 2, **kwargs) - ok_button = RippleButton( - nursery, + label_dest := dialog_dest.scale_by(1.0, 0.7).move_to(top=dialog_dest.top).inflate(-10, -10), + priority + 2, + **kwargs), daemon=True) + s(ripple_button( font.render(text_ok, True, "white"), - dialog_dest.scale_by(0.5, 0.3).move_to(midbottom=dialog_dest.midbottom).inflate(-20, -20), - priority=priority + 2, **kwargs) - rects = (dialog_dest, label.dest, ok_button.dest, ) + button_dest := dialog_dest.scale_by(0.5, 0.3).move_to(midbottom=dialog_dest.midbottom).inflate(-20, -20), + priority + 2, + on_click=e_ok.fire, + **kwargs), daemon=True) + rects = (dialog_dest, label_dest, button_dest, ) y_movement = target_rect.centery - dialog_dest.centery - await translate_rects_vertically(clock, rects, y_movement, duration=200) - await ok_button.to_be_clicked() - await translate_rects_vertically(clock, rects, -y_movement, duration=200) + await move_rects_vertically(clock, rects, y_movement, duration=200) + await e_ok.wait() + await move_rects_vertically(clock, rects, -y_movement, duration=200) + return async def ask_yes_no_question( - question, *, dialog_size: Rect=None, font=None, text_yes='Yes', text_no='No', - priority, **kwargs: Unpack[CommonParams]) -> bool: + question, priority, *, dialog_size: Rect=None, font=None, text_yes='Yes', text_no='No', + **kwargs: Unpack[CommonParams]) -> bool: ''' .. code-block:: result = await ask_yes_no_question("Do you like PyGame?", priority=0xFFFFFA00, **kwargs) ''' - bgcolor = "grey90" + bgcolor = THECOLORS["grey90"] clock = kwargs["clock"] draw_target = kwargs["draw_target"] if font is None: @@ -95,25 +99,30 @@ async def ask_yes_no_question( dialog_size = target_rect.inflate(-100, 0) dialog_size.height = dialog_size.width // 2 dialog_dest = dialog_size.move_to(bottom=target_rect.top) + e_yes = asyncgui.Event() + e_no = asyncgui.Event() with kwargs["executor"].register(partial(draw_target.fill, bgcolor, dialog_dest), priority=priority + 1): - label = AnchorLayout( - nursery, + s = nursery.start + s(anchor_layout( font.render(question, True, "black", bgcolor).convert(draw_target), - dialog_dest.scale_by(1.0, 0.5).move_to(top=dialog_dest.top).inflate(-10, -10), - priority=priority + 2, **kwargs) - yes_button = RippleButton( - nursery, + label_dest := dialog_dest.scale_by(1.0, 0.5).move_to(top=dialog_dest.top).inflate(-10, -10), + priority + 2, + **kwargs), daemon=True) + s(ripple_button( font.render(text_yes, True, "white"), - dialog_dest.scale_by(0.5, 0.5).move_to(bottomright=dialog_dest.bottomright).inflate(-20, -20), - priority=priority + 2, **kwargs) - no_button = RippleButton( - nursery, + yes_button_dest := dialog_dest.scale_by(0.5, 0.5).move_to(bottomright=dialog_dest.bottomright).inflate(-20, -20), + priority + 2, + on_click=e_yes.fire, + **kwargs), daemon=True) + s(ripple_button( font.render(text_no, True, "white"), - dialog_dest.scale_by(0.5, 0.5).move_to(bottomleft=dialog_dest.bottomleft).inflate(-20, -20), - priority=priority + 2, **kwargs) - rects = (dialog_dest, label.dest, yes_button.dest, no_button.dest, ) + no_button_dest := dialog_dest.scale_by(0.5, 0.5).move_to(bottomleft=dialog_dest.bottomleft).inflate(-20, -20), + priority + 2, + on_click=e_no.fire, + **kwargs), daemon=True) + rects = (dialog_dest, label_dest, yes_button_dest, no_button_dest, ) y_movement = target_rect.centery - dialog_dest.centery - await translate_rects_vertically(clock, rects, y_movement, duration=200) - tasks = await asyncgui.wait_any(yes_button.to_be_clicked(), no_button.to_be_clicked()) - await translate_rects_vertically(clock, rects, -y_movement, duration=200) + await move_rects_vertically(clock, rects, y_movement, duration=200) + tasks = await asyncgui.wait_any(e_yes.wait(), e_no.wait()) + await move_rects_vertically(clock, rects, -y_movement, duration=200) return tasks[0].finished diff --git a/examples/_uix/progress_spinner.py b/examples/_uix/progress_spinner.py index b41ae7d..92c8740 100644 --- a/examples/_uix/progress_spinner.py +++ b/examples/_uix/progress_spinner.py @@ -23,7 +23,7 @@ def _draw(pygame_draw_arc, draw_target, color, rect, line_width, self: Self): _draw = partial(_draw, pygame.draw.arc) -async def progress_spinner(dest: Rect, *, color="white", line_width=20, min_arc_angle=0.3, speed=1.0, priority, **kwargs): +async def progress_spinner(dest: Rect, priority, *, color="white", line_width=20, min_arc_angle=0.3, speed=1.0, **kwargs): R1 = 0.4 R2 = math.tau - min_arc_angle * 2 next_start = itertools.accumulate(itertools.cycle((R1, R1, R1 + R2, R1, )), initial=0).__next__ diff --git a/examples/_uix/ripple_button.py b/examples/_uix/ripple_button.py index 35a9cdd..322979e 100644 --- a/examples/_uix/ripple_button.py +++ b/examples/_uix/ripple_button.py @@ -1,14 +1,13 @@ -__all__ = ('RippleButton', ) +__all__ = ('ripple_button', ) from typing import Self, ContextManager from contextlib import contextmanager from functools import partial -from collections.abc import Awaitable import math -from asyncgui import Nursery, Event, run_as_main +import asyncgui from pygame import Surface, Rect, Color -from pygame import constants as C +import pygame.constants as C import pygame.draw @@ -20,11 +19,11 @@ def out_quad(p): @contextmanager -def clip(surface, rect): +def tmp_clip(surface, rect): ''' .. code-block:: - with clip(surface, rect): + with tmp_clip(surface, rect): ... ''' prev = surface.get_clip() @@ -73,108 +72,80 @@ def block_touch_down_events(sdlevent, priority, *, filter=lambda e: True) -> Con class RippleEffect: __slots__ = ('radius', 'draw', ) - def __init__(self, pos, radius, color): + def __init__(self): + self.draw = do_nothing + + def enable(self, draw_target, pos, radius, color): self.radius = radius - self.draw = partial(self._draw, color, pos, self) + self.draw = partial(self._draw, draw_target, pos, color, self) + + def disable(self): + self.draw = do_nothing - def _draw(pygame_draw_circle, color, pos, self: Self, draw_target): + def _draw(pygame_draw_circle, draw_target, pos, color, self: Self): pygame_draw_circle(draw_target, color, pos, self.radius) _draw = partial(_draw, pygame.draw.circle) -class RippleButton: +def do_nothing(*args, **kwargs): + pass + + +async def ripple_button( + image: Surface, dest: Rect, priority, *, bgcolor="fuchsia", ripple_color=(80, 80, 80, 0), + on_click=do_nothing, executor, sdlevent, clock, draw_target, **__): ''' .. code-block:: async with asyncpygame.open_nursery() as nursery: image = Surface(...) dest = Rect(...) - button = RippleButton(nursery, image, dest, **common_params) + click_event = asyncpygame.Event() - # Waits for the button to be clicked. - await button.to_be_clicked() - - # You can change its image anytime. - button.image = another_image + nursery.start(ripple_button(image, dest, priority=..., on_click=click_event.fire, **common_params)) - # You can move or resize the button by updating the ``dest``. - dest.width = ... - dest.right = ... - - # but you cannot assign another Rect instance to the button. - button.dest = another_rect # NOT ALLOWED + # Waits for the button to be clicked. + args, kwargs = await click_event.wait() + # The events that caused the button to be clicked. These are either a pair of FINGERDOWN + # and FINGERUP events or a pair of MOUSEBUTTONDOWN and MOUSEBUTTONUP events. + e_down, e_up = args ''' - def __init__(self, owner: Nursery, image: Surface, dest: Rect, - *, bgcolor="fuchsia", ripple_color=(80, 80, 80, 0), **common_params): - ''' - :param owner: RippleButton cannot outlive its owner. When the owner is closed, the button is destroyed. - ''' - self._click_event = Event() - self._draw_ripple_effect = None - self._dest = dest - self.image = image - self._main_task = owner.start(self._main(bgcolor, ripple_color, **common_params), daemon=True) - - def kill(self): - self._main_task.cancel() - - @property - def dest(self) -> Rect: - return self._dest - - async def to_be_clicked(self) -> Awaitable[tuple[Event, Event]]: - ''' - Waits for the button to be clicked. - - .. code-block:: - - e_down, e_up = await button.to_be_clicked() - - The ``e_down`` and ``e_up`` above are :class:`pygame.event.Event` instances that caused the click, and - they are either a pair of ``MOUSEBUTTONDOWN`` and ``MOUSEBUTTONUP`` or a pair of ``FINGERDOWN`` and ``FINGERUP``. - ''' - return (await self._click_event.wait())[0] - - async def _main(self, bgcolor, ripple_color, *, priority, draw_target, executor, clock, sdlevent, **unused): - bgcolor = Color(bgcolor) - ripple_color = Color(ripple_color) + Color(bgcolor) - dest = self._dest - click_event = self._click_event - - touch_down = partial( - sdlevent.wait, C.MOUSEBUTTONDOWN, C.FINGERDOWN, priority=priority + 1, consume=True, - filter=lambda e, getattr=getattr, dest=dest: (not getattr(e, 'touch', False)) and dest.collidepoint(e.pos)) - mouse_button_up = partial( - sdlevent.wait, C.MOUSEBUTTONUP, priority=priority + 1, consume=True, - filter=lambda e: e.button == e_down.button) - finger_up = partial( - sdlevent.wait, C.FINGERUP, priority=priority + 1, consume=True, - filter=lambda e: e.finger_id == e_down.finger_id) - - with ( - executor.register(partial(self._draw, bgcolor, draw_target, dest, self), priority=priority), - block_touch_down_events(sdlevent, priority, filter=lambda e, dest=dest: dest.collidepoint(e.pos)), - ): - while True: - e_down = await touch_down() - effect = RippleEffect(e_down.pos, 0, ripple_color) - self._draw_ripple_effect = effect.draw - touch_up = mouse_button_up if e_down.type == C.MOUSEBUTTONDOWN else finger_up - async with run_as_main(touch_up()) as touch_up_tracker: - await clock.anim_attrs(effect, radius=calc_minimum_enclosing_circle_radius(e_down.pos, dest), duration=600, transition=out_quad) - e_up = touch_up_tracker.result - if dest.collidepoint(e_up.pos): - click_event.fire(e_down, e_up) - self._draw_ripple_effect = None - - def _draw(clip, bgcolor, draw_target, dest, self: Self): - image = self.image - with clip(draw_target, dest): - draw_target.fill(bgcolor) - if (draw := self._draw_ripple_effect) is not None: - draw(draw_target) - draw_target.blit(image, image.get_rect(center=dest.center)) - - _draw = partial(_draw, clip) + bgcolor = Color(bgcolor) + ripple_color = Color(ripple_color) + Color(bgcolor) + collidepoint = dest.collidepoint + effect = RippleEffect() + + touch_down = partial( + sdlevent.wait, C.MOUSEBUTTONDOWN, C.FINGERDOWN, priority=priority + 1, consume=True, + filter=lambda e: (not getattr(e, 'touch', False)) and collidepoint(e.pos)) + mouse_button_up = partial( + sdlevent.wait, C.MOUSEBUTTONUP, priority=priority + 1, consume=True, + filter=lambda e: e.button == e_down.button) + finger_up = partial( + sdlevent.wait, C.FINGERUP, priority=priority + 1, consume=True, + filter=lambda e: e.finger_id == e_down.finger_id) + + with ( + executor.register(partial(_draw, tmp_clip, image, image.get_rect(), bgcolor, draw_target, dest, effect), priority), + block_touch_down_events(sdlevent, priority, filter=lambda e: collidepoint(e.pos)), + ): + while True: + e_down = await touch_down() + effect.enable(draw_target, e_down.pos, 0, ripple_color) + touch_up = mouse_button_up if e_down.type == C.MOUSEBUTTONDOWN else finger_up + async with asyncgui.run_as_main(touch_up()) as touch_up_tracker: + await clock.anim_attrs(effect, radius=calc_minimum_enclosing_circle_radius(e_down.pos, dest), duration=600, transition=out_quad) + e_up = touch_up_tracker.result + if collidepoint(e_up.pos): + on_click(e_down, e_up) + effect.disable() + + +def _draw(tmp_clip, image, image_rect, bgcolor, draw_target, dest, effect): + with tmp_clip(draw_target, dest): + draw_target.fill(bgcolor) + effect.draw() + image_rect.center = dest.center + draw_target.blit(image, image_rect) diff --git a/examples/_uix_anchor_layout.py b/examples/_uix_anchor_layout.py index 4664123..55ff7a4 100644 --- a/examples/_uix_anchor_layout.py +++ b/examples/_uix_anchor_layout.py @@ -6,7 +6,7 @@ from pygame.colordict import THECOLORS import asyncpygame as apg -from _uix.anchor_layout import AnchorLayout +from _uix.anchor_layout import anchor_layout async def main(**kwargs: Unpack[apg.CommonParams]): @@ -19,13 +19,11 @@ async def main(**kwargs: Unpack[apg.CommonParams]): r(partial(screen.fill, THECOLORS["black"]), priority=0) r(pygame.display.flip, priority=0xFFFFFF00) - async with apg.open_nursery() as nursery: - dest = screen.get_rect().inflate(-20, -20) - for anchor in "topleft midtop topright midleft center midright bottomleft midbottom bottomright".split(): - AnchorLayout( - nursery, font.render(anchor, True, "white"), dest, - anchor_src=anchor, anchor_dest=anchor, priority=0x100, **kwargs) - await apg.sleep_forever() + dest = screen.get_rect().inflate(-20, -20) + await apg.wait_all(*( + anchor_layout(font.render(anchor, True, "white"), dest, priority=0x100, anchor_image=anchor, anchor_dest=anchor, **kwargs) + for anchor in "topleft midtop topright midleft center midright bottomleft midbottom bottomright".split() + )) if __name__ == "__main__": diff --git a/examples/_uix_ripple_button.py b/examples/_uix_ripple_button.py index 2598443..cc94e5d 100644 --- a/examples/_uix_ripple_button.py +++ b/examples/_uix_ripple_button.py @@ -7,7 +7,7 @@ from pygame import Rect import asyncpygame as apg -from _uix.ripple_button import RippleButton +from _uix.ripple_button import ripple_button async def main(**kwargs: Unpack[apg.CommonParams]): @@ -20,10 +20,20 @@ async def main(**kwargs: Unpack[apg.CommonParams]): r(partial(screen.fill, THECOLORS["black"]), priority=0) r(pygame.display.flip, priority=0xFFFFFF00) - async with apg.open_nursery() as nursery: - RippleButton(nursery, font.render("PyGame", True, "white"), Rect(100, 100, 300, 200), priority=0x100, **kwargs) - RippleButton(nursery, font.render("Python", True, "white"), Rect(280, 240, 300, 200), priority=0x200, bgcolor="darkgreen", **kwargs) - await apg.sleep_forever() + await apg.wait_all( + ripple_button( + font.render("PyGame", True, "white"), + Rect(100, 100, 300, 200), + on_click=lambda *_: print("PyGame"), + priority=0x100, **kwargs), + ripple_button( + font.render("Python", True, "white"), + Rect(280, 240, 300, 200), + on_click=lambda *_: print("Python"), + bgcolor="darkgreen", + priority=0x200, + **kwargs), + ) if __name__ == "__main__": diff --git a/examples/asking_question.py b/examples/asking_question.py index 5f40a8e..9f654bd 100644 --- a/examples/asking_question.py +++ b/examples/asking_question.py @@ -7,7 +7,7 @@ import asyncpygame as apg from _uix.touch_indicator import touch_indicator -from _uix.ripple_button import RippleButton +from _uix.ripple_button import ripple_button from _uix.modal_dialog import ask_yes_no_question, show_messagebox @@ -23,15 +23,18 @@ async def main(**kwargs: Unpack[apg.CommonParams]): r(pygame.display.flip, priority=0xFFFFFF00) async with apg.open_nursery() as nursery: - nursery.start(touch_indicator(color="darkgreen", priority=0xFFFFFE00, **kwargs)) - button = RippleButton( - nursery, - button_image := button_font.render("open dialog", True, THECOLORS["white"]).convert_alpha(), - button_image.get_rect(centerx=screen_rect.centerx).inflate(40, 40).move_to(bottom=screen_rect.bottom - 20), - priority=0x100, **kwargs) + e_open = apg.Event() + s = nursery.start + s(touch_indicator(color="darkgreen", priority=0xFFFFFE00, **kwargs)) + s(ripple_button( + image := button_font.render("open dialog", True, THECOLORS["white"]).convert_alpha(), + image.get_rect(centerx=screen_rect.centerx).inflate(40, 40).move_to(bottom=screen_rect.bottom - 20), + priority=0x100, + on_click=e_open.fire, + **kwargs)) while True: - await button.to_be_clicked() + await e_open.wait() answer = await ask_yes_no_question("Do you like PyGame?", priority=0xFFFFFA00, **kwargs) await show_messagebox(f"You answered '{'Yes' if answer else 'No'}'.", priority=0xFFFFFA00, **kwargs) diff --git a/examples/network_io.py b/examples/network_io.py deleted file mode 100644 index 268ce9d..0000000 --- a/examples/network_io.py +++ /dev/null @@ -1,60 +0,0 @@ -from typing import Unpack -from functools import partial - -import pygame -import pygame.font -from pygame.colordict import THECOLORS -from pygame import Rect -import asyncpygame as apg -import requests - -from _uix.touch_indicator import touch_indicator -from _uix.ripple_button import RippleButton -from _uix.anchor_layout import AnchorLayout - - -async def main(**kwargs: Unpack[apg.CommonParams]): - pygame.init() - pygame.display.set_caption("Network I/O") - kwargs["draw_target"] = screen = pygame.display.set_mode((600, 800)) - font = pygame.font.SysFont(None, 50) - bgcolor = THECOLORS["black"] - fgcolor = THECOLORS["white"] - - r = kwargs["executor"].register - r(partial(screen.fill, bgcolor), priority=0) - r(pygame.display.flip, priority=0xFFFFFF00) - del r - - async with apg.open_nursery() as nursery: - nursery.start(touch_indicator(color=fgcolor, priority=0xFFFFFE00, **kwargs)) - button = RippleButton( - nursery, - font.render("start", True, fgcolor).convert_alpha(), - Rect(0, 600, 600, 200).inflate(-40, -40), - priority=0x100, **kwargs) - await button.to_be_clicked() - - label = AnchorLayout( - nursery, - font.render("waiting for the server to respond", True, fgcolor, bgcolor).convert(screen), - Rect(0, 0, 600, 200).inflate(-40, -40), - priority=0x100, **kwargs) - button.image = font.render("cancel", True, fgcolor).convert_alpha() - tasks = await apg.wait_any( - kwargs["clock"].run_in_thread(lambda: requests.get("https://httpbin.org/delay/4"), polling_interval=200), - button.to_be_clicked(), - ) - - if tasks[0].finished: - text = tasks[0].result.json()['headers']['User-Agent'] - else: - text = "cancelled" - label.image = font.render(text, True, fgcolor, bgcolor).convert(screen) - button.image = font.render("Quit the App", True, fgcolor).convert_alpha() - await button.to_be_clicked() - apg.quit() - - -if __name__ == "__main__": - apg.run(main) diff --git a/examples/network_io_with_animation.py b/examples/network_io_with_animation.py index c4587ad..c3671bc 100644 --- a/examples/network_io_with_animation.py +++ b/examples/network_io_with_animation.py @@ -10,13 +10,13 @@ from _uix.touch_indicator import touch_indicator from _uix.progress_spinner import progress_spinner -from _uix.ripple_button import RippleButton -from _uix.anchor_layout import AnchorLayout +from _uix.ripple_button import ripple_button +from _uix.anchor_layout import anchor_layout async def main(**kwargs: Unpack[apg.CommonParams]): pygame.init() - pygame.display.set_caption("Network I/O with Animation") + pygame.display.set_caption("Network I/O + Animation") kwargs["draw_target"] = screen = pygame.display.set_mode((600, 800)) font = pygame.font.SysFont(None, 50) bgcolor = THECOLORS["black"] @@ -25,38 +25,54 @@ async def main(**kwargs: Unpack[apg.CommonParams]): r = kwargs["executor"].register r(partial(screen.fill, bgcolor), priority=0) r(pygame.display.flip, priority=0xFFFFFF00) + del r - async with apg.open_nursery() as nursery: - nursery.start(touch_indicator(color=fgcolor, priority=0xFFFFFE00, **kwargs)) - button = RippleButton( - nursery, - font.render("start", True, fgcolor).convert_alpha(), - Rect(0, 600, 600, 200).inflate(-40, -40), - priority=0x100, **kwargs) - await button.to_be_clicked() + async with apg.run_as_main(touch_indicator(color=fgcolor, priority=0xFFFFFE00, **kwargs)): + e_click = apg.Event() + await apg.wait_any( + e_click.wait(), + ripple_button( + font.render("start", True, fgcolor).convert_alpha(), + button_dest := Rect(0, 600, 600, 200).inflate(-40, -40), + priority=0x100, on_click=e_click.fire, **kwargs), + ) - async with apg.run_as_daemon(progress_spinner( - Rect(0, 0, 400, 400).move_to(center=screen.get_rect().center), - color=fgcolor, priority=0x100, **kwargs, - )): - label = AnchorLayout( - nursery, + tasks = await apg.wait_any( + kwargs["clock"].run_in_thread( + lambda: requests.get("https://httpbin.org/delay/4"), + polling_interval=200, daemon=True), + e_click.wait(), + progress_spinner( + Rect(0, 0, 400, 400).move_to(center=screen.get_rect().center), + color=fgcolor, + priority=0x100, **kwargs), + ripple_button( + font.render("cancel", True, fgcolor).convert_alpha(), + button_dest, + on_click=e_click.fire, + priority=0x100, **kwargs), + anchor_layout( font.render("waiting for the server to respond", True, fgcolor, bgcolor).convert(screen), - Rect(0, 0, 600, 200).inflate(-40, -40), + label_dest := Rect(0, 0, 600, 200).inflate(-40, -40), priority=0x100, **kwargs) - button.image = font.render("cancel", True, fgcolor).convert_alpha() - tasks = await apg.wait_any( - kwargs["clock"].run_in_thread(lambda: requests.get("https://httpbin.org/delay/4"), polling_interval=200), - button.to_be_clicked(), - ) - + ) if tasks[0].finished: text = tasks[0].result.json()['headers']['User-Agent'] else: text = "cancelled" - label.image = font.render(text, True, fgcolor, bgcolor).convert(screen) - button.image = font.render("Quit the App", True, fgcolor).convert_alpha() - await button.to_be_clicked() + + await apg.wait_any( + e_click.wait(), + ripple_button( + font.render("Quit the App", True, fgcolor).convert_alpha(), + button_dest, + on_click=e_click.fire, + priority=0x100, **kwargs), + anchor_layout( + font.render(text, True, fgcolor, bgcolor).convert(screen), + label_dest, + priority=0x100, **kwargs) + ) apg.quit()