diff --git a/python_payload/apps/demo_worms4.py b/python_payload/apps/demo_worms4.py new file mode 100644 index 0000000000000000000000000000000000000000..dfba5f02059185145b6597c19d0c8dc4aaf491d7 --- /dev/null +++ b/python_payload/apps/demo_worms4.py @@ -0,0 +1,139 @@ +# python imports +import random +import time +import math + +# flow3r imports +from st3m import event, ui +from st4m import application +from st4m import Ctx, InputState + + +tau = 2 * math.pi + + +# Subclass Application +class AppWorms(application.Application): + def __init__(self, name): + super().__init__(name) + + # HACK: we work against double buffering by keeping note of how many + # times on_draw got called. + # + # We know there's two buffers, so if we render the same state twice in a + # row we'll be effectively able to keep a persistent framebuffer, like + # with the old API. + # + # When bufn is in [0, 1] we render the background image. + # When bufn is in [2, ...) we render the worms. + # When bufn is > 3, we enable updating the worm state. + # + # TODO(q3k): allow apps to request single-buffered graphics for + # persistent framebuffers. + self.bufn = 0 + + self.worms = [] + for i in range(0): + self.worms.append(Worm()) + + self.just_shown = True + + def on_enter(self): + # print("on foreground") + self.just_shown = True + + def draw(self, ctx): + if self.bufn == 0 or self.bufn == 1: + ctx.rgb(*ui.BLUE).rectangle( + -ui.WIDTH / 2, -ui.HEIGHT / 2, ui.WIDTH, ui.HEIGHT + ).fill() + ctx.text_align = ctx.CENTER + ctx.text_baseline = ctx.MIDDLE + ctx.move_to(0, 0).rgb(*ui.WHITE).text("touch me :)") + self.bufn += 1 + + return + + for w in self.worms: + w.draw(ctx) + self.bufn += 1 + + def think(self, ins: InputState, delta_ms: int) -> None: + super().think(ins, delta_ms) + + # Simulation is currently locked to FPS. + if self.bufn > 3: + for w in self.worms: + w.move() + self.bufn = 2 + for index, petal in enumerate(self.input.captouch.petals): + if petal.pressed or petal.repeated: + self.worms.append(Worm(tau * index / 10 + math.pi)) + + def handle_input(self, data): + worms = self.worms + worms.append(Worm(data.get("index", 0) * 2 * math.pi / 10 + math.pi)) + if len(worms) > 10: + worms.pop(0) + + +class Worm: + def __init__(self, direction=None): + self.color = ui.randrgb() + + if direction: + self.direction = direction + else: + self.direction = random.random() * math.pi * 2 + + self.size = 50 + self.speed = self.size / 5 + (x, y) = ui.xy_from_polar(100, self.direction) + self.x = x + self.y = y + # (self.dx,self.dy) = xy_from_polar(1,self.direction) + self._lastdist = 0.0 + + def draw(self, ctx): + ctx.rgb(*self.color) + ctx.round_rectangle( + self.x - self.size / 2, + self.y - self.size / 2, + self.size, + self.size, + self.size // 2, + ).fill() + + def mutate(self): + self.color = [ + max(0, min(1, x + ((random.random() - 0.5) * 0.3))) for x in self.color + ] + + def move(self): + dist = math.sqrt(self.x**2 + self.y**2) + target_size = (130 - dist) / 3 + + if self.size > target_size: + self.size -= 1 + + if self.size < target_size: + self.size += 1 + + self.speed = self.size / 5 + + self.direction += (random.random() - 0.5) * math.pi / 4 + + (dx, dy) = ui.xy_from_polar(self.speed, self.direction) + self.x += dx + self.y += dy + + if dist > 120 - self.size / 2 and dist > self._lastdist: + polar_position = math.atan2(self.y, self.x) + dx = dx * -abs(math.cos(polar_position)) + dy = dy * -abs(math.sin(polar_position)) + self.direction = -math.atan2(dy, dx) + self.mutate() + self._lastdist = dist + + +app = AppWorms("worms") diff --git a/python_payload/main.py b/python_payload/main.py index fcd8a927efe1d2258fa74074aeeede13e2563209..51a3ec2b667a2120c499ed4d317dee6130fa290e 100644 --- a/python_payload/main.py +++ b/python_payload/main.py @@ -46,11 +46,14 @@ menu_music = SimpleMenu( vm, ) +from apps.demo_worms4 import app as worms + +worms._view_manager = vm menu_apps = SimpleMenu( [ MenuItemBack(), MenuItemNoop("captouch"), - MenuItemNoop("worms"), + MenuItemForeground("worms", worms), ], vm, ) @@ -58,7 +61,7 @@ menu_apps = SimpleMenu( menu_main = FlowerMenu( [ - MenuItemForeground("MUsic", menu_music), + MenuItemForeground("Music", menu_music), MenuItemForeground("Apps", menu_apps), MenuItemNoop("Settings"), ], diff --git a/python_payload/st4m/application.py b/python_payload/st4m/application.py new file mode 100644 index 0000000000000000000000000000000000000000..dcb44fcadfb13036113c545a558718e5684c972b --- /dev/null +++ b/python_payload/st4m/application.py @@ -0,0 +1,15 @@ +from st4m.ui.view import ViewWithInputState, ViewTransitionSwipeRight + + +class Application(ViewWithInputState): + def __init__(self, name: str = __name__): + self._name = name + self._view_manager = None + super().__init__() + + def think(self, ins: InputState, delta_ms: int) -> None: + super().think(ins, delta_ms) + + if self.input.left_shoulder.middle.pressed: + if self._view_manager is not None: + self._view_manager.pop(ViewTransitionSwipeRight()) diff --git a/python_payload/st4m/ui/elements/visuals.py b/python_payload/st4m/ui/elements/visuals.py index 244ae3036fdef667b65cd4cd0e5e04a2ec847b6d..43236a4411a94076ba4b53100bdcb2f009f13cef 100644 --- a/python_payload/st4m/ui/elements/visuals.py +++ b/python_payload/st4m/ui/elements/visuals.py @@ -84,7 +84,6 @@ class GroupRing(Responder): ctx.rotate(-angle).translate(0, self.r).rotate(math.pi) item.draw(ctx) ctx.restore() - # ctx.restore() class FlowerIcon(Responder): @@ -103,7 +102,7 @@ class FlowerIcon(Responder): self.highlighted = False self.rotation_time = 0.0 - self.petal_count = random.randint(2, 3) + self.petal_count = random.randint(3, 5) self.petal_color = (random.random(), random.random(), random.random()) self.phi_offset = random.random() self.size_offset = random.randint(0, 20) @@ -127,11 +126,13 @@ class FlowerIcon(Responder): ctx.text_baseline = ctx.MIDDLE ctx.font_size = self.size / 3 ctx.line_width = 5 + ctx.font = ctx.get_font_name(6) if self.rotation_time: phi_rotate = tau * ((self.ts % self.rotation_time) / self.rotation_time) else: phi_rotate = 0 for i in range(self.petal_count): + # continue # ctx.save() phi = (tau / self.petal_count * i + self.phi_offset + phi_rotate) % tau @@ -158,21 +159,20 @@ class FlowerIcon(Responder): # label # y += self.size / 3 + w = max(self.size, ctx.text_width(self.label) + 10) h = self.size / 3 + 8 - if False and self.highlighted: - ctx.rgb(*BLACK).move_to(x, y - height / 2).round_rectangle( - x - width / 2, y - height / 2, width, height, width // 2 - ).fill() - ctx.rgb(*GO_GREEN).move_to(x, y).text(self.label) + # ctx.save() + ctx.translate(0, self.size / 3) + + if self.highlighted: + bg = BLACK + fg = GO_GREEN else: - ctx.save() - ctx.translate(0, self.size / 3) - ctx.rgb(*PUSH_RED).round_rectangle( - x - w / 2, y - h / 2, w, h, w // 2 - ).fill() + bg = PUSH_RED + fg = BLACK - ctx.rgb(*BLACK).move_to(x, y).text(self.label) - ctx.restore() + ctx.rgb(*bg).round_rectangle(x - w / 2, y - h / 2, w, h, w // 2).fill() + ctx.rgb(*fg).move_to(x, y).text(self.label) ctx.restore()