2017-06-07 10:06:26 -07:00
|
|
|
from micropython import const
|
|
|
|
|
2017-01-02 06:45:56 -08:00
|
|
|
import sys
|
2016-05-17 09:55:11 -07:00
|
|
|
import math
|
|
|
|
import utime
|
|
|
|
|
2017-06-14 09:47:38 -07:00
|
|
|
from trezorui import Display
|
2017-09-16 06:00:31 -07:00
|
|
|
|
|
|
|
from trezor import io
|
|
|
|
from trezor import loop
|
|
|
|
from trezor import res
|
2018-02-19 07:50:58 -08:00
|
|
|
from trezor import workflow
|
2016-05-17 09:55:11 -07:00
|
|
|
|
2016-05-17 09:37:26 -07:00
|
|
|
display = Display()
|
2016-05-17 09:55:11 -07:00
|
|
|
|
2017-09-25 08:23:24 -07:00
|
|
|
# for desktop platforms, we need to refresh the display after each frame
|
2017-09-16 06:00:31 -07:00
|
|
|
if sys.platform != 'trezor':
|
2017-01-02 06:45:56 -08:00
|
|
|
loop.after_step_hook = display.refresh
|
|
|
|
|
2017-12-16 05:50:28 -08:00
|
|
|
# import constants from modtrezorui
|
|
|
|
|
|
|
|
SIZE = Display.FONT_SIZE
|
2017-09-25 08:23:24 -07:00
|
|
|
NORMAL = Display.FONT_NORMAL
|
|
|
|
BOLD = Display.FONT_BOLD
|
|
|
|
MONO = Display.FONT_MONO
|
2018-02-22 07:44:46 -08:00
|
|
|
WIDTH = Display.WIDTH
|
|
|
|
HEIGHT = Display.HEIGHT
|
2016-05-17 09:55:11 -07:00
|
|
|
|
2017-01-02 06:45:56 -08:00
|
|
|
|
2017-09-25 08:23:24 -07:00
|
|
|
def lerpi(a: int, b: int, t: float) -> int:
|
|
|
|
return int(a + t * (b - a))
|
2016-05-17 09:55:11 -07:00
|
|
|
|
2017-03-20 13:40:53 -07:00
|
|
|
|
2017-09-25 08:23:24 -07:00
|
|
|
def rgb(r: int, g: int, b: int) -> int:
|
|
|
|
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)
|
|
|
|
|
|
|
|
|
|
|
|
def blend(ca: int, cb: int, t: float) -> int:
|
|
|
|
return rgb(
|
|
|
|
lerpi((ca >> 8) & 0xF8, (cb >> 8) & 0xF8, t),
|
|
|
|
lerpi((ca >> 3) & 0xFC, (cb >> 3) & 0xFC, t),
|
|
|
|
lerpi((ca << 3) & 0xF8, (cb << 3) & 0xF8, t))
|
2016-10-08 02:47:28 -07:00
|
|
|
|
2017-03-30 08:35:15 -07:00
|
|
|
|
2017-09-25 08:23:24 -07:00
|
|
|
from trezor.ui.style import *
|
2016-05-17 09:55:11 -07:00
|
|
|
|
2017-01-02 06:45:56 -08:00
|
|
|
|
2017-09-25 08:23:24 -07:00
|
|
|
def contains(area: tuple, pos: tuple) -> bool:
|
2016-05-17 09:55:11 -07:00
|
|
|
x, y = pos
|
|
|
|
ax, ay, aw, ah = area
|
|
|
|
return ax <= x <= ax + aw and ay <= y <= ay + ah
|
|
|
|
|
|
|
|
|
2017-09-25 08:23:24 -07:00
|
|
|
def rotate(pos: tuple) -> tuple:
|
|
|
|
r = display.orientation()
|
|
|
|
if r == 0:
|
|
|
|
return pos
|
|
|
|
x, y = pos
|
|
|
|
if r == 90:
|
|
|
|
return (y, 240 - x)
|
|
|
|
if r == 180:
|
|
|
|
return (240 - x, 240 - y)
|
|
|
|
if r == 270:
|
|
|
|
return (240 - y, x)
|
2016-05-17 09:55:11 -07:00
|
|
|
|
|
|
|
|
2017-09-26 02:54:37 -07:00
|
|
|
def pulse(delay: int):
|
2017-09-16 06:00:31 -07:00
|
|
|
while True:
|
|
|
|
# normalize sin from interval -1:1 to 0:1
|
|
|
|
yield 0.5 + 0.5 * math.sin(utime.ticks_us() / delay)
|
|
|
|
|
|
|
|
|
2017-09-26 02:54:37 -07:00
|
|
|
async def alert(count: int=3):
|
2017-09-16 06:00:31 -07:00
|
|
|
short_sleep = loop.sleep(20000)
|
|
|
|
long_sleep = loop.sleep(80000)
|
2016-10-08 02:47:28 -07:00
|
|
|
current = display.backlight()
|
2016-10-20 06:11:33 -07:00
|
|
|
for i in range(count * 2):
|
2016-10-08 02:47:28 -07:00
|
|
|
if i % 2 == 0:
|
|
|
|
display.backlight(BACKLIGHT_MAX)
|
2017-09-16 06:00:31 -07:00
|
|
|
yield short_sleep
|
2016-10-08 02:47:28 -07:00
|
|
|
else:
|
|
|
|
display.backlight(BACKLIGHT_NORMAL)
|
2017-09-16 06:00:31 -07:00
|
|
|
yield long_sleep
|
2016-10-08 02:47:28 -07:00
|
|
|
display.backlight(current)
|
|
|
|
|
2016-10-20 06:11:33 -07:00
|
|
|
|
2018-02-05 02:49:04 -08:00
|
|
|
async def click() -> tuple:
|
|
|
|
touch = loop.select(io.TOUCH)
|
|
|
|
while True:
|
|
|
|
ev, *pos = yield touch
|
|
|
|
if ev == io.TOUCH_START:
|
|
|
|
break
|
|
|
|
while True:
|
|
|
|
ev, *pos = yield touch
|
|
|
|
if ev == io.TOUCH_END:
|
|
|
|
break
|
|
|
|
return pos
|
|
|
|
|
|
|
|
|
2018-02-19 07:50:58 -08:00
|
|
|
async def backlight_slide(val: int, delay: int=35000, step: int=20):
|
2017-09-16 06:00:31 -07:00
|
|
|
sleep = loop.sleep(delay)
|
2016-10-08 02:47:28 -07:00
|
|
|
current = display.backlight()
|
2017-10-10 06:33:54 -07:00
|
|
|
for i in range(current, val, -step if current > val else step):
|
2016-10-08 02:47:28 -07:00
|
|
|
display.backlight(i)
|
2018-01-30 08:56:30 -08:00
|
|
|
yield sleep
|
2016-05-25 05:27:22 -07:00
|
|
|
|
2016-10-20 06:11:33 -07:00
|
|
|
|
2017-09-26 02:54:37 -07:00
|
|
|
def layout(f):
|
|
|
|
async def inner(*args, **kwargs):
|
2018-02-19 07:50:58 -08:00
|
|
|
await backlight_slide(BACKLIGHT_DIM)
|
|
|
|
slide = backlight_slide(BACKLIGHT_NORMAL)
|
2017-10-10 06:33:54 -07:00
|
|
|
try:
|
2018-02-19 07:50:58 -08:00
|
|
|
layout = f(*args, **kwargs)
|
|
|
|
workflow.onlayoutstart(layout)
|
2017-10-10 06:33:54 -07:00
|
|
|
loop.schedule(slide)
|
2018-02-26 09:40:44 -08:00
|
|
|
display.clear()
|
2018-02-19 07:50:58 -08:00
|
|
|
return await layout
|
2017-10-10 06:33:54 -07:00
|
|
|
finally:
|
|
|
|
loop.close(slide)
|
2018-02-19 07:50:58 -08:00
|
|
|
workflow.onlayoutclose(layout)
|
2017-09-26 02:54:37 -07:00
|
|
|
|
|
|
|
return inner
|
|
|
|
|
|
|
|
|
2018-01-11 10:44:56 -08:00
|
|
|
def header(title: str,
|
|
|
|
icon: bytes=ICON_RESET,
|
|
|
|
fg: int=BG,
|
|
|
|
bg: int=BG,
|
|
|
|
ifg: int=BG):
|
2017-09-16 06:00:31 -07:00
|
|
|
if icon is not None:
|
2018-01-23 06:06:10 -08:00
|
|
|
display.icon(14, 17, res.load(icon), ifg, bg)
|
2017-11-03 09:14:01 -07:00
|
|
|
display.text(44, 35, title, BOLD, fg, bg)
|
2017-09-16 06:00:31 -07:00
|
|
|
|
|
|
|
|
2018-01-11 10:44:56 -08:00
|
|
|
VIEWX = const(6)
|
|
|
|
VIEWY = const(9)
|
|
|
|
|
|
|
|
|
|
|
|
def grid(i: int,
|
|
|
|
n_x: int=3,
|
|
|
|
n_y: int=5,
|
|
|
|
start_x: int=VIEWX,
|
|
|
|
start_y: int=VIEWY,
|
2018-02-22 07:44:46 -08:00
|
|
|
end_x: int=(WIDTH - VIEWX),
|
|
|
|
end_y: int=(HEIGHT - VIEWY),
|
2018-01-11 10:44:56 -08:00
|
|
|
cells_x: int=1,
|
|
|
|
cells_y: int=1,
|
|
|
|
spacing: int=0):
|
|
|
|
w = (end_x - start_x) // n_x
|
|
|
|
h = (end_y - start_y) // n_y
|
|
|
|
x = (i % n_x) * w
|
|
|
|
y = (i // n_x) * h
|
|
|
|
return (x + start_x, y + start_y, (w - spacing) * cells_x, (h - spacing) * cells_y)
|
|
|
|
|
|
|
|
|
2017-02-08 07:19:33 -08:00
|
|
|
class Widget:
|
|
|
|
def render(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def touch(self, event, pos):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def __iter__(self):
|
2017-09-16 06:00:31 -07:00
|
|
|
touch = loop.select(io.TOUCH)
|
2017-09-26 02:54:37 -07:00
|
|
|
result = None
|
|
|
|
while result is None:
|
2017-02-08 07:19:33 -08:00
|
|
|
self.render()
|
2017-09-16 06:00:31 -07:00
|
|
|
event, *pos = yield touch
|
2017-02-08 07:19:33 -08:00
|
|
|
result = self.touch(event, pos)
|
2017-09-26 02:54:37 -07:00
|
|
|
return result
|