diff --git a/python_payload/control.py b/python_payload/control.py new file mode 100644 index 0000000000000000000000000000000000000000..897f1bc03f9474eef6e5a8c3043b1c86b9394d4f --- /dev/null +++ b/python_payload/control.py @@ -0,0 +1,46 @@ +import ui + +class ControlKnob(): + def __init__(self,name,action=None,default=0.5): + #TODO inheritance from Control() + self.name=name + self.action=action + self.value = default + self.ui = ui.IconValue(label=self.name,size=60, value=self.value) + + def draw(self): + self.ui.draw() + + def enter(self,data={}): + self.value = 0.8 + self.ui.value = self.value + if self.action: + self.action(self.value) + + def scroll(self,delta): + self.value = max(0,min(1,self.value+delta*0.05)) + self.ui.value = self.value + print (self.value) + self.draw() + if self.action: + self.action(self.value) + +class ControlSwitch(): + def __init__(self,name,action,default): + #TODO inheritance from Control() + self.name=name + self.action=action + self.value = default + self.ui = ui.IconValue(label=self.name,size=60, value=self.value) + + def draw(self): + self.ui.draw() + + def enter(self): + self.value = not self.value + self.ui.value = self.value + if self.action: + self.action(self.value) + + def scroll(self,delta): + pass diff --git a/python_payload/demo_menu.py b/python_payload/demo_menu.py index e3c5e62590b9199133db1efb23cda1e6156f9ac2..522c758f31ffad47382a7724f33c354f5e113643 100644 --- a/python_payload/demo_menu.py +++ b/python_payload/demo_menu.py @@ -1,8 +1,14 @@ import menu import event import hardware +import control -import demo_worms,demo_sparabo +import demo_worms,demo_sparabo,cap_touch_demo, melodic_demo, harmonic_demo +import menu_settings,menu_tinysynth + +import time + +hardware.captouch_autocalib() def start_worms(action): menu.menu_stack.append(menu.active_menu) @@ -14,6 +20,41 @@ def start_sparabo(action): menu.active_menu=None demo_sparabo.run() +def start_captouch(action): + armed = False + while True: + cap_touch_demo.run() + time.sleep_ms(10) + if hardware.get_button(1) == 0: + armed = True + if armed and hardware.get_button(1) == 2: + break + +def start_melodic(action): + armed = False + melodic_demo.init() + hardware.set_global_volume_dB(20) + hardware.display_fill(0) + while True: + melodic_demo.run() + time.sleep_ms(10) + if hardware.get_button(1) == 0: + armed = True + if armed and hardware.get_button(1) == 2: + break + +def start_harmonic(action): + armed = False + harmonic_demo.init() + hardware.set_global_volume_dB(20) + hardware.display_fill(0) + while True: + harmonic_demo.run() + time.sleep_ms(10) + if hardware.get_button(1) == 0: + armed = True + if armed and hardware.get_button(1) == 2: + break menu_demo = menu.Menu("demo") item_worms = menu.MenuItem("worms") item_worms.action = start_worms @@ -23,6 +64,13 @@ item_abo = menu.MenuItem("abo") item_abo.action = start_sparabo menu_demo.add(item_abo) +item_cap = menu.MenuItem("captouch") +item_cap.action = start_captouch +menu_demo.add(item_cap) + +menu_demo.add(menu.MenuItem("melodic", action=start_melodic)) +menu_demo.add(menu.MenuItem("harmonic", action=start_harmonic)) + testmenu = menu.Menu("test") item_add = menu.MenuItem("+") @@ -39,10 +87,10 @@ testmenu.add(item_add) menu_main = menu.Menu("main",has_back=False) menu_main.add(menu.MenuItemSubmenu(testmenu)) menu_main.add(menu.MenuItemSubmenu(menu_demo)) -menu_main.add(menu.MenuItem("nix")) +menu_main.add(menu.MenuItemSubmenu(menu_settings.get_menu())) +menu_main.add(menu.MenuItemSubmenu(menu_tinysynth.get_menu())) menu.set_active_menu(menu_main) menu.render() - event.the_engine.eventloop() diff --git a/python_payload/demo_sparabo.py b/python_payload/demo_sparabo.py index 50b6d465821a491425b2df0aa793d44951b00107..4bbf4f1e76b93c902e971d677dd27eeba752b492 100644 --- a/python_payload/demo_sparabo.py +++ b/python_payload/demo_sparabo.py @@ -38,9 +38,15 @@ def on_step(data): hardware.display_update() def handle_input(data={}): + print("removed") + + sequencer.remove() ev.remove() + #TODO this is a bad hack! + event.the_engine.events_timed=[] + def init(): ctx.text_align = ctx.CENTER diff --git a/python_payload/menu.py b/python_payload/menu.py index 4e44a2b7d7088a23808918ef0e97a6d5363fd0cf..e4ec935f5610b0fa0ba480b15e379e4e11e5966c 100644 --- a/python_payload/menu.py +++ b/python_payload/menu.py @@ -87,9 +87,9 @@ class Menu(): class MenuItem(): - def __init__(self,name="item"): + def __init__(self,name="item",action=None): self.name= name - self.action= None + self.action= action self.ui = ui.Icon(label=name) def __repr__(self): @@ -118,16 +118,45 @@ class MenuItemBack(MenuItem): def enter(self,data={}): menu_back() +class MenuItemControl(MenuItem): + def __init__(self,name,control): + super().__init__(name=name) + self.control=control + self.ui=control.ui + + def enter(self): + print("menu enter") + self.control.enter() + + def scroll(self,delta): + self.control.scroll(delta) + def on_scroll(d): if active_menu is None: return - if active_menu.angle_step<0.5: - active_menu.angle_step+=0.025 - if d["value"] == -1: - active_menu.rotate_steps(-1) - elif d["value"] == 1: - active_menu.rotate_steps(1) + if d["index"]==0:#right button + hovered=active_menu.get_hovered_item() + if hasattr(hovered, "scroll"): + hovered.scroll(d["value"]) + + else: #index=1, #left button + if active_menu.angle_step<0.5: + active_menu.angle_step+=0.025 + if d["value"] == -1: + active_menu.rotate_steps(-1) + elif d["value"] == 1: + active_menu.rotate_steps(1) + + render() + +def on_scroll_captouch(d): + if active_menu is None: + return + if abs(d["radius"]) < 10000: + return + print(d["angle"]) + active_menu.rotate_to(d["angle"]+math.pi) render() def on_release(d): @@ -145,17 +174,22 @@ def on_enter(d): else: active_menu.get_hovered_item().enter() -event.Event(name="menu rotation", +event.Event(name="menu rotation button",group_id="menu", condition=lambda e: e["type"] =="button" and not e["change"] and abs(e["value"])==1 , action=on_scroll ) -event.Event(name="menu rotation release", +event.Event(name="menu rotation captouch",group_id="menu", + condition=lambda e: e["type"] =="captouch" and not e["change"] and abs(e["value"])==1 and e["index"]==2, + action=on_scroll_captouch +) + +event.Event(name="menu rotation button release",group_id="menu", condition=lambda e: e["type"] =="button" and e["change"] and e["value"] ==0, action=on_release ) -event.Event(name="menu enter", +event.Event(name="menu button enter",group_id="menu", condition=lambda e: e["type"] =="button" and e["change"] and e["value"] == 2, action=on_enter ) @@ -166,7 +200,7 @@ def render(): return hardware.get_ctx().rectangle(-120,-120,240,240).rgb(0,0,0).fill() active_menu.draw() - hardware.display_update() + #hardware.display_update() def set_active_menu(menu): global active_menu diff --git a/python_payload/menu_settings.py b/python_payload/menu_settings.py new file mode 100644 index 0000000000000000000000000000000000000000..860c7e1a75b91a74ab3739ec3d285e47565e7614 --- /dev/null +++ b/python_payload/menu_settings.py @@ -0,0 +1,51 @@ +import menu +import event +import control +import ui +import hardware + + +ui_input = ui.Icon("") + +def render_input_data(data): + ui_input.label = str(data["angle"]) + print("xxx") + ui_input.draw() + +def set_controls_overlay(value): + print ("set_controls_overlay") + if value: + event_input_overlay = event.Event( + name="show input overlay", group_id="input-overlay", + #condition=lambda d: d['type'] in ["captouch","button"], + condition=lambda d: d['type'] in ["captouch"] and d['value']==1, + action=render_input_data + ) + else: + print("REMOVE") + event.the_engine.remove("input-overlay") + +def set_volume(value): + db = int(value*60-40) + print("DB",db) + hardware.set_global_volume_dB(db) + + +def get_menu(): + m = menu.Menu("settings") + + control_debug_input=control.ControlSwitch( + name="show inputs", + action=set_controls_overlay, + default=False + ) + + item_input_overlay = menu.MenuItemControl("input overlay", control_debug_input) + m.add(item_input_overlay) + + c = control.ControlKnob(name="Volume",default=0.5,action=set_volume) + m.add(menu.MenuItemControl("volume",c)) + + return m + +m = get_menu() \ No newline at end of file diff --git a/python_payload/menu_tinysynth.py b/python_payload/menu_tinysynth.py new file mode 100644 index 0000000000000000000000000000000000000000..0d012b44429cdb59b5235dd916f09114b7aab4b8 --- /dev/null +++ b/python_payload/menu_tinysynth.py @@ -0,0 +1,45 @@ +from synth import tinysynth + +import menu +import event +import control +import ui +import hardware + + +ui_input = ui.Icon("") + + +def set_play(value): + print ("set_controls_overlay") + if value: + synth.start() + else: + synth.stop() + +def set_volume(value): + db = int(value*60-40) + print("DB",db) + hardware.set_global_volume_dB(db) + +def set_frequency(value): + f = 440+value*440 + synth.freq(f) + + +def get_menu(): + m = menu.Menu("tinysynth") + + freq=control.ControlKnob(name="freq",action=set_frequency,default=0.0) + m.add(menu.MenuItemControl("freq",freq)) + + vol = control.ControlKnob(name="vol",action=set_volume,default=0.0) + m.add(menu.MenuItemControl("volume",vol)) + + play = control.ControlSwitch(name="play",action=set_play,default=False) + m.add(menu.MenuItemControl("play",play)) + return m + +synth = tinysynth(440,0) + +m = get_menu() \ No newline at end of file diff --git a/python_payload/ui.py b/python_payload/ui.py index 48fb0eed34f2e8cc036e8be73a9ffef82c0ee226..c47d5baae43856a24e5c38b6498bc78d3e2567cc 100644 --- a/python_payload/ui.py +++ b/python_payload/ui.py @@ -2,6 +2,12 @@ import hardware import random import math import time +from math import sin,cos,pi + + +GO_GREEN = (63/255,255/255,33/53) +PUSH_RED = (251/255,72/255,196/255) + class UIElement(): def __init__(self,origin=(0,0)): @@ -17,7 +23,6 @@ class UIElement(): child.draw(pos) def _draw(self,pos): - #print(pos) pass def add(self, child): @@ -40,15 +45,14 @@ class Icon(UIElement): self.bg_b = random.random() self.fg = 0 self.label=label - self.size = size + self.size=size self.has_highlight = False super().__init__() def _draw(self,pos): x = int(pos[0]) y = int(pos[1]) - width = 55 - height = 40 + self.ctx.text_align = self.ctx.CENTER self.ctx.text_baseline = self.ctx.MIDDLE @@ -59,12 +63,32 @@ class Icon(UIElement): y-hs/2, hs,hs,hs//2 ).fill() - self.ctx.move_to(x,y-self.size/2).rgb(self.bg_r,self.bg_g,self.bg_b).round_rectangle( - x-self.size/2, - y-self.size/2, - self.size,self.size,self.size//2 - ).fill() + self.ctx.move_to(x,y).rgb(self.bg_r,self.bg_g,self.bg_b).arc(x,y,self.size/2,-math.pi,math.pi,True).fill() + #self.ctx.move_to(x,y-self.size/2).rgb(self.bg_r,self.bg_g,self.bg_b). + #.round_rectangle( + # x-self.size/2, + # y-self.size/2, + # self.size,self.size,self.size//2 + #).fill() self.ctx.rgb(1,1,1).move_to(x,y).text(self.label) + +class IconValue(Icon): + def __init__(self, value=0, *args, **kwargs): + super().__init__(*args, **kwargs) + self.value = value + + def _draw(self,pos): + (x,y) = pos + + if self.has_highlight: + self.ctx.move_to(x,y).rgb(*GO_GREEN).arc(x,y,self.size/2+5,-pi,pi,True).fill() + + self.ctx.move_to(x,y).rgb(*PUSH_RED).arc(x,y,self.size/2,-pi,pi,True).fill() + self.ctx.move_to(x,y).rgb(*GO_GREEN).arc(x,y,self.size/2-5,2*pi*self.value,0,1).fill() + self.ctx.rgb(0,0,0).move_to(x,y).text(self.label) + + + class GroupStackedVertical(UIElement): pass