Skip to content
Snippets Groups Projects
Forked from flow3r / flow3r firmware
1419 commits behind the upstream repository.
ui.py 7.80 KiB
import hardware
import random
import math
import time
from math import sin,cos,pi

import gc

WIDTH = 240
HEIGHT = 240

#Define a few RGB (0.0 to 1.0) colors
BLACK = (0,0,0)
RED = (1,0,0)
GREEN = (0,1,0)
BLUE = (0,0,1)
WHITE = (1,1,1)
GREY = (0.5,0.5,0.5)
GO_GREEN = (63/255,255/255,33/53)
PUSH_RED = (251/255,72/255,196/255)

the_ctx = hardware.get_ctx()

# Utility functions
def xy_from_polar(r,phi):
    return (
        r * math.sin(phi), #x
        r * math.cos(phi)  #y
    )

#def ctx_circle(self, x,y, radius, arc_from = -math.pi, arc_to = math.pi):
#    return self.arc(x,y,radius,arc_from,arc_to,True)

#the_ctx.circle = ctx_circle

def randrgb():
    return ((random.random(),random.random(),random.random()))

class UIElement():
    def __init__(self,origin=(0,0)):
        self.children = []
        self.origin = origin
        self.ctx = the_ctx
    
    def draw(self, offset=(0,0)):
        pos = (self.origin[0]+offset[0],self.origin[1]+offset[1])

        self._draw(pos)
        for child in self.children:
            child.draw(pos)

        

    def _draw(self,pos):
        pass

    def add(self, child):
        self.children.append(child)

class Viewport(UIElement):
    def _draw(self,pos):
        self.ctx.rgb(0.3,0.3,0.3).rectangle(-WIDTH/2,-HEIGHT/2,WIDTH,HEIGHT).fill()

class Circle(UIElement):
    def __init__(self,radius,color=PUSH_RED,arc_from=-math.pi, arc_to=math.pi, *args, **kwargs):
        self.radius = radius
        self.color = color
        self.arc_from = arc_from
        self.arc_to = arc_to
        super().__init__()
    
    def _draw(self,pos):
        (x,y)=pos
        self.ctx.move_to(x,y).rgb(*self.color).arc(x,y,self.radius,self.arc_from,self.arc_to,True).fill()


class Text(UIElement):
    def __init__(self,s="foo"):
        self.s = s
        super().__init__()

    def _draw(self, pos):
        self.ctx.text_align = self.ctx.CENTER
        self.ctx.text_baseline = self.ctx.MIDDLE
        self.ctx.font_size = 30
        self.ctx.rgb(1,1,1).move_to(pos[0],pos[1]).text(self.s)

class Icon(UIElement):
    def __init__(self,label="?", size=60):
        self.bg = (random.random(),random.random(),random.random())
        self.fg = 0
        self.label=label
        self.size=size
        self.has_highlight = False
        super().__init__()

    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
        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()

        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= random.randint(3,5)
        self.petal_count = 0
        self.petal_color = (random.random(),random.random(),random.random())
        self.phi_offset = random.random()
        self.size_offset = random.randint(0,20)
        #self.bg=PUSH_RED
    
    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

        hs = 5
            
        for i in range(self.petal_count):
            phi = math.pi*2 / self.petal_count * i + self.phi_offset
            r = self.size/2
            (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(*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(*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()

        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)



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(*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,v*2*pi,0,1).fill()
        self.ctx.rgb(0,0,0).move_to(x,y).text(self.label)




class GroupStackedVertical(UIElement):
    pass

        
class GroupRing(UIElement):
    def __init__(self,r=100,origin=(0,0),element_center=None):
        self.r = r
        self.angle_offset = 0
        self.element_center=element_center
        super().__init__(origin)

    def draw(self, offset=(0,0)):
        pos = (self.origin[0]+offset[0],self.origin[1]+offset[1])
        self._draw(pos)
        for index in range(len(self.children)):
            #print("child",index)
            child = self.children[index]
            if not child:
                continue
            angle = 2*math.pi/len(self.children)*index+self.angle_offset
            #print(angle,self.r,pos[0])
            x = -math.sin(angle)*self.r+pos[0]
            y = -math.cos(angle)*self.r+pos[1]
            #print("pos",(x,y))
            child.draw(offset=(x,y))

    def _draw(self,pos):
        if self.element_center:
            self.element_center.has_highlight = False
            self.element_center._draw(pos)

class GroupPetals(GroupRing):
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.children = [None for i in range(10)]