diff --git a/python_payload/apps/widgets_demo/__init__.py b/python_payload/apps/widgets_demo/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..beb490a0e2d37574ad20e6a4876194e697b78ca5 --- /dev/null +++ b/python_payload/apps/widgets_demo/__init__.py @@ -0,0 +1,246 @@ +import captouch +import leds +import math, cmath, time +from st3m.ui import colours, widgets +from st3m.application import Application + + +class Screen: + def __init__(self): + self.captouch_config = captouch.Config.empty() + self.widgets = [] + + def on_enter(self): + for widget in self.widgets: + widget.on_enter() + self.captouch_config.apply() + self.full_redraw = True + + def on_exit(self): + for widget in self.widgets: + widget.on_exit() + + def think(self, ins, delta_ms): + for widget in self.widgets: + widget.think(ins, delta_ms) + + +class SensorScreen(Screen): + def __init__(self): + super().__init__() + + self.inc = widgets.Inclinometer() + self.alt = widgets.Altimeter() + self.big_slider = widgets.BigSlider(self.captouch_config) + + self.widgets = [self.big_slider, self.inc, self.alt] + + self.coords = [[0, -60], [50, 30], [-50, 30]] + self.labels = ["big slider", "tilt", "altitude"] + + def draw(self, ctx): + if self.full_redraw: + ctx.gray(0.1).rectangle(-120, -120, 240, 240).fill() + ctx.gray(1) + ctx.text_align = ctx.CENTER + ctx.font_size = 16 + for k in range(3): + x, y = self.coords[k] + ctx.move_to(x, y + 45) + ctx.text(self.labels[k]) + + for k in range(3): + ctx.save() + ctx.translate(*self.coords[k]) + self.widgets[k].draw(ctx) + ctx.restore() + + +# class PoolScreen(Screen): +# def __init__(self): +# super().__init__() +# +# arena = widgets.constraints.Ellipse(105) +# self.pool = widgets.Pool( +# self.captouch_config, +# petal=8, +# gain=40 * captouch.PETAL_ANGLES[8], +# constraint=arena, +# ) +# self.scroller = widgets.Scroller( +# self.captouch_config, +# petal=2, +# gain=40 * captouch.PETAL_ANGLES[2], +# constraint=arena, +# ) +# +# self.widgets = [self.pool, self.scroller] +# +# def draw(self, ctx): +# ctx.rgb(1, 1, 1).rectangle(-120, -120, 240, 240).fill() +# self.pool.draw(ctx) +# self.scroller.draw(ctx, draw_background=False) + + +class SliderScreen(Screen): + def __init__(self): + super().__init__() + self.widgets += [ + widgets.Slider(self.captouch_config, petal=x) for x in range(10) + ] + self.widget_styles = [widgets.WidgetStyle() for x in range(10)] + self.hues = [None] * 40 + self.sats = [None] * 40 + self.vals = [None] * 40 + + def think(self, delta_ms, ins): + super().think(delta_ms, ins) + for x in range(0, 10, 2): + self.hues[x * 4] = cmath.phase(self.widgets[x].pos) + self.sats[x * 4] = abs(self.widgets[x].pos) + + for x in range(1, 10, 2): + self.vals[x * 4] = (self.widgets[x].pos.real + 1) / 2 + + # get intermediate hue + for x in range(0, 40, 8): + a = self.hues[x] + b = self.hues[(x + 8) % 40] + if a - b > math.pi: + a -= math.tau + elif a - b < -math.pi: + a += math.tau + for y in range(1, 8): + self.hues[x + y] = (a * (8 - y) + b * y) / 8 + + # get intermediate sat + for x in range(0, 40, 8): + a = self.sats[x] + b = self.sats[(x + 8) % 40] + for y in range(1, 8): + self.sats[x + y] = (a * (8 - y) + b * y) / 8 + + # get intermediate val + for x in range(4, 44, 8): + a = self.vals[x % 40] + b = self.vals[(x + 8) % 40] + for y in range(1, 8): + self.vals[(x + y) % 40] = (a * (8 - y) + b * y) / 8 + + for x in range(40): + leds.set_rgb( + x, *colours.hsv_to_rgb(self.hues[x], self.sats[x], self.vals[x]) + ) + leds.update() + + def draw(self, ctx): + if self.full_redraw: + ctx.gray(0.1) + ctx.rectangle(-120, -120, 240, 240).fill() + + for x in range(0, 10, 2): + if self.hues[x * 4]: + col = colours.hsv_to_rgb(self.hues[x * 4], self.sats[x * 4], 1) + self.widget_styles[x].marker_col = col + self.widget_styles[x].marker_col_inactive = col + + for widget in self.widgets: + ctx.save() + ctx.rotate(cmath.phase(captouch.PETAL_ANGLES[widget.petal])) + ctx.translate(80, 0) + widget.draw( + ctx, self.widget_styles[widget.petal], full_redraw=self.full_redraw + ) + ctx.restore() + + self.full_redraw = False + + +class XeyesScreen(Screen): + def __init__(self): + super().__init__() + constraint = widgets.constraints.Ellipse(1.4 + 1j) + self.widgets += [ + widgets.Scroller( + self.captouch_config, petal=x, constraint=constraint, friction=0.5 + ) + for x in range(0, 10, 2) + ] + self.widget_style = widgets.WidgetStyle( + widget_scale=18, + outline_width=7, + outline_col=(0, 0, 0), + marker_padding=0, + marker_col=(0, 0, 0), + marker_col_inactive=(0, 0, 0), + background_col=(1, 1, 1), + ) + + def draw(self, ctx): + if self.full_redraw: + ctx.rgb(0.3, 0.2, 0.4) + ctx.rectangle(-120, -120, 240, 240).fill() + + for widget in self.widgets: + ctx.save() + ctx.rotate(cmath.phase(captouch.PETAL_ANGLES[widget.petal])) + ctx.translate(67, 0) + widget.draw(ctx, self.widget_style) + ctx.restore() + + self.full_redraw = False + + +class App(Application): + def __init__(self, app_ctx): + super().__init__(app_ctx) + self._screens = [ + SliderScreen(), + SensorScreen(), + XeyesScreen(), + # PoolScreen(), + ] + self._screen_index = 0 + self.active_screen = self._screens[self._screen_index] + self.full_redraw = True + + def think(self, ins, delta_ms): + super().think(ins, delta_ms) + self.active_screen.think(ins, delta_ms) + + button = self.input.buttons.app + lr_dir = button.right.pressed - button.left.pressed + if lr_dir: + self.active_screen.on_exit() + self._screen_index += lr_dir + self._screen_index %= len(self._screens) + self.active_screen = self._screens[self._screen_index] + self.active_screen.on_enter() + + def on_enter(self, vm): + super().on_enter(vm) + self.active_screen.on_enter() + self.always_full_redraw = True + + def on_enter_done(self): + self.always_full_redraw = False + + def on_exit(self): + self.always_full_redraw = True + self.active_screen.on_exit() + + def on_exit_done(self): + self.always_full_redraw = False + + def draw(self, ctx): + if self.always_full_redraw: + self.full_redraw = True + self.active_screen.full_redraw |= self.full_redraw + self.active_screen.draw(ctx) + self.full_redraw = False + + +if __name__ == "__main__": + import st3m.run + + st3m.run.run_app(App) diff --git a/python_payload/apps/widgets_demo/flow3r.toml b/python_payload/apps/widgets_demo/flow3r.toml new file mode 100644 index 0000000000000000000000000000000000000000..ee8547a2e0cb718f75fd2e2125cbda15efba3068 --- /dev/null +++ b/python_payload/apps/widgets_demo/flow3r.toml @@ -0,0 +1,8 @@ +[app] +name = "widgets demo" +category = "Apps" + +[metadata] +author = "Flow3r Badge Authors" +license = "LGPL-3.0-only" +url = "https://git.flow3r.garden/flow3r/flow3r-firmware"