trezor-core/src/trezor/ui/button.py

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