119 lines
3.7 KiB
Python
119 lines
3.7 KiB
Python
from micropython import const
|
|
|
|
from trezor import io
|
|
from trezor import ui
|
|
|
|
from trezor.ui import contains
|
|
from trezor.ui import display
|
|
from trezor.ui import rotate
|
|
from trezor.ui import Widget
|
|
|
|
BTN_CLICKED = const(1)
|
|
|
|
BTN_STARTED = const(1)
|
|
BTN_ACTIVE = const(2)
|
|
BTN_DIRTY = const(4)
|
|
BTN_DISABLED = const(8)
|
|
|
|
ICON = const(16) # icon size in pixels
|
|
BORDER = const(4) # border size in pixels
|
|
|
|
|
|
class Button(Widget):
|
|
|
|
def __init__(self, area, content, style=ui.BTN_KEY, absolute=False):
|
|
self.area = area
|
|
self.content = content
|
|
self.normal_style = style['normal'] or ui.BTN_KEY['normal']
|
|
self.active_style = style['active'] or ui.BTN_KEY['active']
|
|
self.disabled_style = style['disabled'] or ui.BTN_KEY['disabled']
|
|
self.absolute = absolute
|
|
self.state = BTN_DIRTY
|
|
|
|
def enable(self):
|
|
if self.state & BTN_DISABLED:
|
|
self.state &= ~BTN_DISABLED
|
|
self.state |= BTN_DIRTY
|
|
|
|
def disable(self):
|
|
if not self.state & BTN_DISABLED:
|
|
self.state |= BTN_DISABLED | BTN_DIRTY
|
|
|
|
def taint(self):
|
|
self.state |= BTN_DIRTY
|
|
|
|
def render(self):
|
|
if not self.state & BTN_DIRTY:
|
|
return
|
|
state = self.state & ~BTN_DIRTY
|
|
if state & BTN_DISABLED:
|
|
s = self.disabled_style
|
|
elif state & BTN_ACTIVE:
|
|
s = self.active_style
|
|
else:
|
|
s = self.normal_style
|
|
ax, ay, aw, ah = self.area
|
|
|
|
self.render_background(s, ax, ay, aw, ah)
|
|
self.render_content(s, ax, ay, aw, ah)
|
|
self.state = state
|
|
|
|
def render_background(self, s, ax, ay, aw, ah):
|
|
radius = s['radius']
|
|
bg_color = s['bg-color']
|
|
border_color = s['border-color']
|
|
if border_color != bg_color:
|
|
# render border and background on top of it
|
|
display.bar_radius(ax, ay,
|
|
aw, ah,
|
|
border_color,
|
|
ui.BG,
|
|
radius)
|
|
display.bar_radius(ax + BORDER, ay + BORDER,
|
|
aw - BORDER * 2, ah - BORDER * 2,
|
|
bg_color,
|
|
border_color,
|
|
radius)
|
|
else:
|
|
# render only the background
|
|
display.bar_radius(ax, ay,
|
|
aw, ah,
|
|
bg_color,
|
|
ui.BG,
|
|
radius)
|
|
|
|
def render_content(self, s, ax, ay, aw, ah):
|
|
c = self.content
|
|
tx = ax + aw // 2
|
|
ty = ay + ah // 2 + 8
|
|
if isinstance(c, str):
|
|
display.text_center(
|
|
tx, ty, c, s['text-style'], s['fg-color'], s['bg-color'])
|
|
else:
|
|
display.icon(
|
|
tx - ICON // 2, ty - ICON, c, s['fg-color'], s['bg-color'])
|
|
|
|
def touch(self, event, pos):
|
|
state = self.state
|
|
if state & BTN_DISABLED:
|
|
return
|
|
if not self.absolute:
|
|
pos = rotate(pos)
|
|
|
|
if event == io.TOUCH_START:
|
|
if contains(self.area, pos):
|
|
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
|
|
|
|
elif event == io.TOUCH_MOVE and state & BTN_STARTED:
|
|
if contains(self.area, pos):
|
|
if not state & BTN_ACTIVE:
|
|
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
|
|
else:
|
|
if state & BTN_ACTIVE:
|
|
self.state = BTN_STARTED | BTN_DIRTY
|
|
|
|
elif event == io.TOUCH_END and state & BTN_STARTED:
|
|
self.state = BTN_DIRTY
|
|
if contains(self.area, pos):
|
|
return BTN_CLICKED
|