From 179d0f24d6da794e71f46f91ee66ea6a7c0041f0 Mon Sep 17 00:00:00 2001 From: iggy <iggy@muc.ccc.de> Date: Wed, 7 Jun 2023 02:36:39 +0200 Subject: [PATCH] py: menu_tinysynth and menu_settings use the new audio api; controls; icons and general ui styling --- python_payload/control.py | 50 ++++++++++++++++--- python_payload/demo_menu.py | 12 ++--- python_payload/menu.py | 5 +- python_payload/menu_settings.py | 81 +++++++++++++++++++++++++++++- python_payload/menu_tinysynth.py | 6 ++- python_payload/ui.py | 85 +++++++++++++++++++++++--------- 6 files changed, 197 insertions(+), 42 deletions(-) diff --git a/python_payload/control.py b/python_payload/control.py index c3660aa77c..3f6b5ae6ab 100644 --- a/python_payload/control.py +++ b/python_payload/control.py @@ -1,26 +1,43 @@ import ui class Control(): - def __init__(self,name, default=0, on_set=None): + def __init__(self,name, default=0, on_set=None, on_get=None, on_mod=None): #TODO inheritance from Control() self.name=name self.on_set = on_set - self._value = default + self.on_get = on_get + self.on_mod = on_mod + + if not self.on_get: + self._value = default self.ui = ui.IconValue(label=self.name,size=60, value=self.get_value()) + self.ui.get_value = self.get_normal_value def draw(self): + self.ui.value = self.get_value() + print("draw: value", self.get_value()) self.ui.draw() - def get_value(self): + def get_normal_value(self): + v = self.get_value() + n = min(1,max(0,v)) + return n + + def get_value(self,update=True): + if update and self.on_get: + self._value = self.on_get() return self._value def set_value(self, value, do_trigger=True): self._value = value - self.ui.value = value if do_trigger: if self.on_set: self.on_set(value) + def mod_value(self,delta): + self._value = self.on_mod(delta) + + def enter(self): pass @@ -33,6 +50,10 @@ class Control(): class ControlSwitch(Control): def enter(self): self.set_value(not self.get_value()) + self.draw() + + def scroll(self,delta): + self.enter() class ControlFloat(Control): def __init__(self, min=0.0,max=1.0,step=0.1, *args, **kwargs): @@ -41,15 +62,28 @@ class ControlFloat(Control): self.step=step super().__init__(*args, **kwargs) + def get_normal_value(self): + v = self.get_value() + n = (v-self.min)/(self.max-self.min) + #print("normal:",v,n) + return n + class ControlKnob(ControlFloat): def enter(self): #repeat action with current value self.set_value(self.get_value()) + self.draw() def scroll(self,delta): - v = self.get_value() - v_new = max(self.min,min(self.max,v+delta*self.step)) - self.set_value(v_new) + if self.on_mod: + #print("control: on mod") + self.on_mod(delta) + + elif self.on_set: + v = self.get_value() + v_new = max(self.min,min(self.max,v+delta*self.step)) + self.set_value(v_new) + self.draw() class ControlSlide(ControlFloat): def __init__(self, do_reset=True, *args, **kwargs): @@ -67,4 +101,4 @@ class ControlSlide(ControlFloat): if z<0: #Release if self.do_reset: self.set_value(self._saved_value) - \ No newline at end of file + self.draw() \ No newline at end of file diff --git a/python_payload/demo_menu.py b/python_payload/demo_menu.py index b72d86be4d..84974dd652 100644 --- a/python_payload/demo_menu.py +++ b/python_payload/demo_menu.py @@ -5,7 +5,7 @@ import control import audio import application -#import demo_worms,demo_sparabo,cap_touch_demo, melodic_demo, harmonic_demo +import demo_worms,demo_sparabo,cap_touch_demo, melodic_demo, harmonic_demo import menu_settings,menu_tinysynth import time @@ -19,11 +19,11 @@ menu_apps = menu.Menu("apps") menu_music = menu.Menu("music") -#for app_module in [demo_sparabo,melodic_demo,harmonic_demo]: -# menu_music.add(menu.MenuItemApp(app_module.app)) +for app_module in [demo_sparabo,melodic_demo,harmonic_demo]: + menu_music.add(menu.MenuItemApp(app_module.app)) -#for app_module in [demo_worms,cap_touch_demo,]: -# menu_apps.add(menu.MenuItemApp(app_module.app)) +for app_module in [demo_worms,cap_touch_demo,]: + menu_apps.add(menu.MenuItemApp(app_module.app)) testmenu = menu.Menu("test") @@ -40,11 +40,11 @@ testmenu.add(item_add) menu_badge.add(menu.MenuItemSubmenu(testmenu)) -menu_badge.add(menu.MenuItemSubmenu(menu_settings.get_menu())) menu_main.add(menu.MenuItemSubmenu(menu_badge)) menu_main.add(menu.MenuItemSubmenu(menu_apps)) menu_main.add(menu.MenuItemSubmenu(menu_music)) +menu_main.add(menu.MenuItemSubmenu(menu_settings.get_menu())) menu_music.add(menu.MenuItemSubmenu(menu_tinysynth.get_menu())) diff --git a/python_payload/menu.py b/python_payload/menu.py index a5aafda483..ab88d6ca60 100644 --- a/python_payload/menu.py +++ b/python_payload/menu.py @@ -127,7 +127,8 @@ class MenuItemSubmenu(MenuItem): class MenuItemBack(MenuItem): def __init__(self): - super().__init__(name="<-") + super().__init__(name="") + self.ui = ui.IconLabel(label="back") def enter(self,data={}): menu_back() @@ -252,7 +253,7 @@ def render(): if active_menu is None: return - ui.the_ctx.rectangle(-120,-120,240,240).rgb(*ui.GO_GREEN).fill() + ui.the_ctx.rectangle(-120,-120,240,240).rgb(*ui.BLACK).fill() active_menu.draw() #hardware.display_update() diff --git a/python_payload/menu_settings.py b/python_payload/menu_settings.py index c99e3c80c3..aa74f8ddac 100644 --- a/python_payload/menu_settings.py +++ b/python_payload/menu_settings.py @@ -44,8 +44,85 @@ def get_menu(): item_input_overlay = menu.MenuItemControl("input overlay", control_debug_input) m.add(item_input_overlay) - c = control.ControlKnob(name="Volume",default=0.5,on_set=set_volume) - m.add(menu.MenuItemControl("volume",c)) + + + m_audio = menu.Menu("audio") + m_speaker = menu.Menu("speaker") + m_head = menu.Menu("headphones") + + vol = control.ControlKnob(name="vol", + on_mod=audio.adjust_volume_dB, + on_get=audio.get_volume_relative + ) + m_audio.add(menu.MenuItemControl("volume",vol)) + m_head.add(menu.MenuItemControl("vol head",control.ControlKnob( + name="vol", + on_mod=audio.headphones_adjust_volume_dB, + on_get=audio.headphones_get_volume_relative + ))) + + m_speaker.add(menu.MenuItemControl("vol speaker",control.ControlKnob( + name="vol", + on_mod=audio.speaker_adjust_volume_dB, + on_get=audio.speaker_get_volume_relative + ))) + + m_audio.add(menu.MenuItemControl("mute",control.ControlSwitch( + name="mute", + on_set=audio.set_mute, + on_get=audio.get_mute + ))) + + m_head.add(menu.MenuItemControl("mute head",control.ControlSwitch( + name="mute", + on_set=audio.headphones_set_mute, + on_get=audio.headphones_get_mute + ))) + + m_head.add(menu.MenuItemControl("detected headphones",control.ControlSwitch( + name="connected?", + on_get=audio.headphones_are_connected + ))) + + + m_speaker.add(menu.MenuItemControl("mute speaker",control.ControlSwitch( + name="mute", + on_set=audio.speaker_set_mute, + on_get=audio.speaker_get_mute + ))) + + m_speaker.add(menu.MenuItemControl("min vol speaker",control.ControlKnob( + name="min", + min = -40, max =14, step=1, + on_set=audio.speaker_set_minimum_volume_dB, + on_get=audio.speaker_get_minimum_volume_dB + ))) + + m_speaker.add(menu.MenuItemControl("max vol speaker",control.ControlKnob( + name="max", + min = -40, max =14, step=1, + on_set=audio.speaker_set_maximum_volume_dB, + on_get=audio.speaker_get_maximum_volume_dB + ))) + + m_head.add(menu.MenuItemControl("min vol headphones",control.ControlKnob( + name="min", + min = -40, max =14, step=1, + on_set=audio.headphones_set_minimum_volume_dB, + on_get=audio.headphones_get_minimum_volume_dB + ))) + + m_head.add(menu.MenuItemControl("max vol headphones",control.ControlKnob( + name="max", + min = -40, max =14, step=1, + on_set=audio.headphones_set_maximum_volume_dB, + on_get=audio.headphones_get_maximum_volume_dB + ))) + + m.add(menu.MenuItemSubmenu(m_audio)) + m_audio.add(menu.MenuItemSubmenu(m_speaker)) + m_audio.add(menu.MenuItemSubmenu(m_head)) + return m diff --git a/python_payload/menu_tinysynth.py b/python_payload/menu_tinysynth.py index 3f2d95b418..f186c5ab8a 100644 --- a/python_payload/menu_tinysynth.py +++ b/python_payload/menu_tinysynth.py @@ -42,7 +42,11 @@ def get_menu(): pitch = control.ControlSlide(name="pitch",on_set=set_frequency,default=0) m.add(menu.MenuItemControl("pitch",pitch)) - vol = control.ControlKnob(name="vol",on_set=set_volume,default=0.0) + vol = control.ControlKnob(name="vol", + #on_set=set_volume + on_mod=audio.adjust_volume_dB, + on_get=audio.get_volume_relative + ) m.add(menu.MenuItemControl("volume",vol)) play = control.ControlSwitch(name="play",on_set=set_play,default=False) diff --git a/python_payload/ui.py b/python_payload/ui.py index 36616f7895..541e688817 100644 --- a/python_payload/ui.py +++ b/python_payload/ui.py @@ -95,30 +95,48 @@ class Icon(UIElement): super().__init__() def _draw(self,pos): - #print("ui.Icon._draw()") - (x,y) = pos - self.ctx.text_align = self.ctx.CENTER self.ctx.text_baseline = self.ctx.MIDDLE - self.ctx.font_size = 30 + self.ctx.font_size=self.size/3 - if self.has_highlight: - hs = self.size+5; - self.ctx.move_to(x,y-hs/2).rgb(1,1,1).round_rectangle( - x-hs/2, - y-hs/2, - hs,hs,hs//2 - ).fill() + (x,y)=pos + hs = 5 + if self.has_highlight: + self.ctx.rgb(*GO_GREEN).arc(x,y, self.size/2+hs,-math.pi,math.pi,True).fill() self.ctx.move_to(x,y).rgb(*self.bg).arc(x,y,self.size/2,-math.pi,math.pi,True).fill() - #self.ctx.move_to(x,y).rgb(self.bg_r,self.bg_g,self.bg_b).circle(x,y,self.size/2).fill() - - self.ctx.rgb(1,1,1).move_to(x,y).text(self.label) + + y += self.size/3 + width = max(self.size-10, self.ctx.text_width(self.label))+10 + height = self.size/3+8 + if self.has_highlight: + self.ctx.rgb(*BLACK).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() + self.ctx.rgb(*GO_GREEN).move_to(x,y).text(self.label) + else: + self.ctx.rgb(*PUSH_RED).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() + self.ctx.rgb(*BLACK).move_to(x,y).text(self.label) + +class IconLabel(Icon): + def _draw(self,pos): + self.ctx.text_align = self.ctx.CENTER + self.ctx.text_baseline = self.ctx.MIDDLE + self.ctx.font_size=self.size/2 + + (x,y)=pos + hs = 5 + width = self.ctx.text_width(self.label)+10 + height = self.size/2 + if self.has_highlight: + self.ctx.rgb(*GO_GREEN).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() + self.ctx.rgb(*BLACK).move_to(x,y).text(self.label) + else: + self.ctx.rgb(*PUSH_RED).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() + self.ctx.rgb(*BLACK).move_to(x,y).text(self.label) class IconFlower(Icon): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.petal_count= 0 #random.randint(4,8) + 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,12 +145,14 @@ class IconFlower(Icon): def _draw(self,pos): self.ctx.text_align = self.ctx.CENTER self.ctx.text_baseline = self.ctx.MIDDLE + self.ctx.font_size=self.size/3 + (x,y)=pos petal_size=0 if self.petal_count: petal_size=2.3*self.size/self.petal_count+self.size_offset - self.ctx.font_size=self.size/3 - hs = 3 + + hs = 5 for i in range(self.petal_count): phi = math.pi*2 / self.petal_count * i + self.phi_offset @@ -140,14 +160,22 @@ class IconFlower(Icon): (x_,y_) = xy_from_polar(r, phi) size_rnd = random.randint(-3,3) if self.has_highlight: - self.ctx.move_to(x+x_,y+y_).rgb(1,1,1).arc(x+x_,y+y_, petal_size/2+hs+size_rnd,-math.pi,math.pi,True).fill() + self.ctx.move_to(x+x_,y+y_).rgb(*GO_GREEN).arc(x+x_,y+y_, petal_size/2+hs+size_rnd,-math.pi,math.pi,True).fill() self.ctx.move_to(x+x_,y+y_).rgb(*self.petal_color).arc(x+x_,y+y_, petal_size/2+size_rnd,-math.pi,math.pi,True).fill() - #if self.has_highlight: - # self.ctx.rgb(1,1,1).arc(x,y, self.size/2+hs,-math.pi,math.pi,True).fill() + if self.has_highlight: + self.ctx.rgb(*GO_GREEN).arc(x,y, self.size/2+hs,-math.pi,math.pi,True).fill() self.ctx.move_to(x,y).rgb(*self.bg).arc(x,y,self.size/2,-math.pi,math.pi,True).fill() - self.ctx.rgb(*WHITE).move_to(x,y).text(self.label) + y += self.size/3 + width = max(self.size, self.ctx.text_width(self.label)+10) + height = self.size/3+8 + if self.has_highlight: + self.ctx.rgb(*BLACK).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() + self.ctx.rgb(*GO_GREEN).move_to(x,y).text(self.label) + else: + self.ctx.rgb(*PUSH_RED).move_to(x,y-height/2).round_rectangle(x-width/2,y-height/2,width,height,width//2).fill() + self.ctx.rgb(*BLACK).move_to(x,y).text(self.label) @@ -155,15 +183,25 @@ class IconValue(Icon): def __init__(self, value=0, *args, **kwargs): super().__init__(*args, **kwargs) self.value = value + self.get_value = None def _draw(self,pos): (x,y) = pos + v = self.value + if self.get_value: + v = self.get_value() + self.value = v + + self.ctx.text_align = self.ctx.CENTER + self.ctx.text_baseline = self.ctx.MIDDLE + self.ctx.font_size=self.size/3 + 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(*WHITE).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.move_to(x,y).rgb(*GO_GREEN).arc(x,y,self.size/2-5,v*2*pi,0,1).fill() self.ctx.rgb(0,0,0).move_to(x,y).text(self.label) @@ -194,4 +232,5 @@ class GroupRing(UIElement): def _draw(self,pos): if self.element_center: + self.element_center.has_highlight = False self.element_center._draw(pos) -- GitLab