ui: request_words, keyboard ui
BIN
assets/5390-200.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
assets/left.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/recovery-old.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
assets/send-old.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/send.png
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
30
src/apps/common/request_words.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from trezor import wire, ui, loop
|
||||||
|
from trezor.utils import unimport
|
||||||
|
|
||||||
|
# used to confirm/cancel the dialogs from outside of this module (i.e.
|
||||||
|
# through debug link)
|
||||||
|
if __debug__:
|
||||||
|
signal = loop.signal()
|
||||||
|
|
||||||
|
|
||||||
|
@ui.layout
|
||||||
|
@unimport
|
||||||
|
async def request_words(ctx, content, code=None, *args, **kwargs):
|
||||||
|
from trezor.ui.word_select import WordSelector
|
||||||
|
from trezor.messages.ButtonRequest import ButtonRequest
|
||||||
|
from trezor.messages.ButtonRequestType import Other
|
||||||
|
from trezor.messages.wire_types import ButtonAck
|
||||||
|
|
||||||
|
ui.display.clear()
|
||||||
|
dialog = WordSelector(content, *args, **kwargs)
|
||||||
|
dialog.render()
|
||||||
|
|
||||||
|
if code is None:
|
||||||
|
code = Other
|
||||||
|
await ctx.call(ButtonRequest(code=code), ButtonAck)
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
waiter = loop.wait(signal, dialog)
|
||||||
|
else:
|
||||||
|
waiter = dialog
|
||||||
|
return await waiter
|
@ -11,15 +11,20 @@ async def layout_recovery_device(ctx, msg):
|
|||||||
from trezor.ui.text import Text
|
from trezor.ui.text import Text
|
||||||
from apps.common import storage
|
from apps.common import storage
|
||||||
from apps.common.confirm import require_confirm
|
from apps.common.confirm import require_confirm
|
||||||
|
from apps.common.request_words import request_words
|
||||||
|
|
||||||
if storage.is_initialized():
|
if storage.is_initialized():
|
||||||
raise wire.FailureError(UnexpectedMessage, 'Already initialized')
|
raise wire.FailureError(UnexpectedMessage, 'Already initialized')
|
||||||
|
|
||||||
words = []
|
words = []
|
||||||
|
|
||||||
|
wc = await request_words(ctx, Text(
|
||||||
|
'Device recovery', ui.ICON_RECOVERY, 'Number of words?'))
|
||||||
|
msg.word_count = int(wc)
|
||||||
|
ui.display.clear()
|
||||||
kbd = KeyboardMultiTap()
|
kbd = KeyboardMultiTap()
|
||||||
for i in range(0, msg.word_count):
|
for i in range(0, msg.word_count):
|
||||||
kbd.prompt = '%s. ' % (i + 1)
|
kbd.prompt = 'Type %s. word' % (i + 1)
|
||||||
word = await kbd
|
word = await kbd
|
||||||
words.append(word)
|
words.append(word)
|
||||||
|
|
||||||
|
BIN
src/trezor/res/click.toig
Normal file
BIN
src/trezor/res/confirm2.toig
Normal file
BIN
src/trezor/res/cross2.toig
Normal file
BIN
src/trezor/res/left.toig
Normal file
BIN
src/trezor/res/recovery.toig
Normal file
BIN
src/trezor/res/send2.toig
Normal file
@ -106,11 +106,10 @@ def layout(f):
|
|||||||
return inner
|
return inner
|
||||||
|
|
||||||
|
|
||||||
def header(title: str, icon: bytes=ICON_RESET, fg: int=BG, bg: int=BG):
|
def header(title: str, icon: bytes=ICON_RESET, fg: int=BG, bg: int=BG, ifg: int=BG):
|
||||||
display.bar(0, 0, 240, 32, bg)
|
|
||||||
if icon is not None:
|
if icon is not None:
|
||||||
display.icon(8, 4, res.load(icon), fg, bg)
|
display.icon(14, 14, res.load(icon), ifg, bg)
|
||||||
display.text(8 + 24 + 2, 24, title, BOLD, fg, bg)
|
display.text(44, 35, title, BOLD, fg, bg)
|
||||||
|
|
||||||
|
|
||||||
class Widget:
|
class Widget:
|
||||||
|
@ -32,11 +32,13 @@ class Button(Widget):
|
|||||||
self.state = BTN_DIRTY
|
self.state = BTN_DIRTY
|
||||||
|
|
||||||
def enable(self):
|
def enable(self):
|
||||||
self.state &= ~BTN_DISABLED
|
if self.state & BTN_DISABLED:
|
||||||
self.state |= BTN_DIRTY
|
self.state &= ~BTN_DISABLED
|
||||||
|
self.state |= BTN_DIRTY
|
||||||
|
|
||||||
def disable(self):
|
def disable(self):
|
||||||
self.state |= BTN_DISABLED | BTN_DIRTY
|
if not self.state & BTN_DISABLED:
|
||||||
|
self.state |= BTN_DISABLED | BTN_DIRTY
|
||||||
|
|
||||||
def taint(self):
|
def taint(self):
|
||||||
self.state |= BTN_DIRTY
|
self.state |= BTN_DIRTY
|
||||||
@ -54,6 +56,7 @@ class Button(Widget):
|
|||||||
ax, ay, aw, ah = self.area
|
ax, ay, aw, ah = self.area
|
||||||
tx = ax + aw // 2
|
tx = ax + aw // 2
|
||||||
ty = ay + ah // 2 + 8
|
ty = ay + ah // 2 + 8
|
||||||
|
|
||||||
display.bar_radius(ax, ay, aw, ah,
|
display.bar_radius(ax, ay, aw, ah,
|
||||||
s['border-color'],
|
s['border-color'],
|
||||||
ui.BG,
|
ui.BG,
|
||||||
@ -70,7 +73,7 @@ class Button(Widget):
|
|||||||
s['bg-color'])
|
s['bg-color'])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
display.icon(tx - 15, ty - 20, self.content,
|
display.icon(tx - 8, ty - 16, self.content,
|
||||||
s['fg-color'],
|
s['fg-color'],
|
||||||
s['bg-color'])
|
s['bg-color'])
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ from trezor.ui import display
|
|||||||
from trezor.ui.button import Button, BTN_CLICKED
|
from trezor.ui.button import Button, BTN_CLICKED
|
||||||
|
|
||||||
|
|
||||||
def cell_area(i, n_x=3, n_y=3, start_x=0, start_y=40, end_x=240, end_y=240, spacing=0):
|
def cell_area(i, n_x=3, n_y=3, start_x=6, start_y=66, end_x=234, end_y=237, spacing=0):
|
||||||
w = (end_x - start_x) // n_x
|
w = (end_x - start_x) // n_x
|
||||||
h = (end_y - start_y) // n_y
|
h = (end_y - start_y) // n_y
|
||||||
x = (i % n_x) * w
|
x = (i % n_x) * w
|
||||||
@ -17,7 +17,8 @@ def key_buttons():
|
|||||||
# keys = [' ', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
|
# keys = [' ', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
|
||||||
return [Button(cell_area(i), k,
|
return [Button(cell_area(i), k,
|
||||||
normal_style=ui.BTN_KEY,
|
normal_style=ui.BTN_KEY,
|
||||||
active_style=ui.BTN_KEY_ACTIVE) for i, k in enumerate(keys)]
|
active_style=ui.BTN_KEY_ACTIVE,
|
||||||
|
disabled_style=ui.BTN_KEY_DISABLED) for i, k in enumerate(keys)]
|
||||||
|
|
||||||
|
|
||||||
def compute_mask(text):
|
def compute_mask(text):
|
||||||
@ -41,38 +42,52 @@ class KeyboardMultiTap(ui.Widget):
|
|||||||
self.pending_index = 0
|
self.pending_index = 0
|
||||||
|
|
||||||
self.key_buttons = key_buttons()
|
self.key_buttons = key_buttons()
|
||||||
self.sugg_button = Button((5, 5, 240 - 35, 30), '')
|
self.sugg_button = Button((63, 0, 240 - 65, 57), '')
|
||||||
self.bs_button = Button((240 - 35, 5, 30, 30),
|
self.bs_button = Button((6, 5, 57, 60),
|
||||||
res.load('trezor/res/pin_close.toig'),
|
res.load('trezor/res/left.toig'),
|
||||||
normal_style=ui.BTN_CLEAR,
|
normal_style=ui.BTN_CLEAR,
|
||||||
active_style=ui.BTN_CLEAR_ACTIVE)
|
active_style=ui.BTN_CLEAR_ACTIVE)
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
|
|
||||||
# clear canvas under input line
|
|
||||||
display.bar(0, 0, 205, 40, ui.BG)
|
|
||||||
|
|
||||||
# input line
|
|
||||||
content_width = display.text_width(self.prompt + self.content, ui.BOLD)
|
|
||||||
display.text(20, 30, self.prompt + self.content, ui.BOLD, ui.FG, ui.BG)
|
|
||||||
|
|
||||||
# pending marker
|
|
||||||
if self.pending_button is not None:
|
|
||||||
pending_width = display.text_width(self.content[-1:], ui.BOLD)
|
|
||||||
pending_x = 20 + content_width - pending_width
|
|
||||||
display.bar(pending_x, 33, pending_width + 2, 3, ui.FG)
|
|
||||||
|
|
||||||
# auto-suggest
|
|
||||||
if self.sugg_word is not None:
|
|
||||||
sugg_rest = self.sugg_word[len(self.content):]
|
|
||||||
sugg_x = 20 + content_width
|
|
||||||
display.text(sugg_x, 30, sugg_rest, ui.BOLD, ui.GREY, ui.BG)
|
|
||||||
|
|
||||||
# render backspace button
|
|
||||||
if self.content:
|
if self.content:
|
||||||
|
display.bar(62, 8, 168, 54, ui.BG)
|
||||||
|
content_width = display.text_width(self.content, ui.BOLD)
|
||||||
|
offset_x = 78
|
||||||
|
if self.content == self.sugg_word:
|
||||||
|
# confirm button + content
|
||||||
|
display.bar_radius(67, 8, 164, 54, ui.GREEN, ui.BG, ui.RADIUS)
|
||||||
|
type_icon = res.load(ui.ICON_CONFIRM2)
|
||||||
|
display.icon(228 - 30, 28, type_icon, ui.WHITE, ui.GREEN)
|
||||||
|
display.text(offset_x, 40, self.content, ui.BOLD, ui.WHITE, ui.GREEN)
|
||||||
|
|
||||||
|
elif self.sugg_word is not None:
|
||||||
|
# auto-suggest button + content + suggestion
|
||||||
|
display.bar_radius(67, 8, 164, 54, ui.BLACKISH, ui.BG, ui.RADIUS)
|
||||||
|
display.text(offset_x, 40, self.content, ui.BOLD, ui.FG, ui.BLACKISH)
|
||||||
|
sugg_text = self.sugg_word[len(self.content):]
|
||||||
|
sugg_x = offset_x + content_width
|
||||||
|
type_icon = res.load(ui.ICON_CLICK)
|
||||||
|
display.icon(228 - 30, 24, type_icon, ui.GREY, ui.BLACKISH)
|
||||||
|
display.text(sugg_x, 40, sugg_text, ui.BOLD, ui.GREY, ui.BLACKISH)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# content
|
||||||
|
display.bar(63, 8, 168, 54, ui.BG)
|
||||||
|
display.text(offset_x, 40, self.content, ui.BOLD, ui.FG, ui.BG)
|
||||||
|
|
||||||
|
# backspace button
|
||||||
self.bs_button.render()
|
self.bs_button.render()
|
||||||
|
|
||||||
|
# pending marker
|
||||||
|
if self.pending_button is not None:
|
||||||
|
pending_width = display.text_width(self.content[-1:], ui.BOLD)
|
||||||
|
pending_x = offset_x + content_width - pending_width
|
||||||
|
display.bar(pending_x, 42, pending_width + 2, 3, ui.FG)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
display.bar(240 - 48, 0, 48, 42, ui.BG)
|
# prompt
|
||||||
|
display.bar(0, 8, 240, 60, ui.BG)
|
||||||
|
display.text(20, 40, self.prompt, ui.BOLD, ui.GREY, ui.BG)
|
||||||
|
|
||||||
# key buttons
|
# key buttons
|
||||||
for btn in self.key_buttons:
|
for btn in self.key_buttons:
|
||||||
@ -87,10 +102,12 @@ class KeyboardMultiTap(ui.Widget):
|
|||||||
self._update_buttons()
|
self._update_buttons()
|
||||||
return
|
return
|
||||||
if self.sugg_button.touch(event, pos) == BTN_CLICKED:
|
if self.sugg_button.touch(event, pos) == BTN_CLICKED:
|
||||||
if self.content == bip39.find_word(self.content):
|
if not self.content or self.sugg_word is None:
|
||||||
|
return None
|
||||||
|
if self.content == self.sugg_word:
|
||||||
result = self.content
|
result = self.content
|
||||||
self.content = ''
|
self.content = ''
|
||||||
elif self.sugg_word is not None:
|
else:
|
||||||
result = None
|
result = None
|
||||||
self.content = self.sugg_word
|
self.content = self.sugg_word
|
||||||
self.pending_button = None
|
self.pending_button = None
|
||||||
@ -128,19 +145,22 @@ class KeyboardMultiTap(ui.Widget):
|
|||||||
else:
|
else:
|
||||||
btn.disable()
|
btn.disable()
|
||||||
|
|
||||||
def __iter__(self):
|
async def __iter__(self):
|
||||||
timeout = loop.sleep(1000 * 1000 * 1)
|
timeout = loop.sleep(1000 * 1000 * 1)
|
||||||
touch = loop.select(io.TOUCH)
|
touch = loop.select(io.TOUCH)
|
||||||
wait_timeout = loop.wait(touch, timeout)
|
wait_timeout = loop.wait(touch, timeout)
|
||||||
wait_touch = loop.wait(touch)
|
wait_touch = loop.wait(touch)
|
||||||
content = None
|
content = None
|
||||||
|
|
||||||
|
self.bs_button.taint()
|
||||||
|
|
||||||
while content is None:
|
while content is None:
|
||||||
self.render()
|
self.render()
|
||||||
if self.pending_button is not None:
|
if self.pending_button is not None:
|
||||||
wait = wait_timeout
|
wait = wait_timeout
|
||||||
else:
|
else:
|
||||||
wait = wait_touch
|
wait = wait_touch
|
||||||
result = yield wait
|
result = await wait
|
||||||
if touch in wait.finished:
|
if touch in wait.finished:
|
||||||
event, *pos = result
|
event, *pos = result
|
||||||
content = self.touch(event, pos)
|
content = self.touch(event, pos)
|
||||||
@ -154,90 +174,90 @@ class KeyboardMultiTap(ui.Widget):
|
|||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def zoom_buttons(keys, upper=False):
|
# def zoom_buttons(keys, upper=False):
|
||||||
n_x = len(keys)
|
# n_x = len(keys)
|
||||||
if upper:
|
# if upper:
|
||||||
keys = keys + keys.upper()
|
# keys = keys + keys.upper()
|
||||||
n_y = 2
|
# n_y = 2
|
||||||
else:
|
# else:
|
||||||
n_y = 1
|
# n_y = 1
|
||||||
return [Button(cell_area(i, n_x, n_y), key) for i, key in enumerate(keys)]
|
# return [Button(cell_area(i, n_x, n_y), key) for i, key in enumerate(keys)]
|
||||||
|
|
||||||
|
|
||||||
class KeyboardZooming(ui.Widget):
|
# class KeyboardZooming(ui.Widget):
|
||||||
|
|
||||||
def __init__(self, content='', uppercase=True):
|
# def __init__(self, content='', uppercase=True):
|
||||||
self.content = content
|
# self.content = content
|
||||||
self.uppercase = uppercase
|
# self.uppercase = uppercase
|
||||||
|
|
||||||
self.zoom_buttons = None
|
# self.zoom_buttons = None
|
||||||
self.key_buttons = key_buttons()
|
# self.key_buttons = key_buttons()
|
||||||
self.bs_button = Button((240 - 35, 5, 30, 30),
|
# self.bs_button = Button((240 - 35, 5, 30, 30),
|
||||||
res.load('trezor/res/pin_close.toig'),
|
# res.load('trezor/res/pin_close.toig'),
|
||||||
normal_style=ui.BTN_CLEAR,
|
# normal_style=ui.BTN_CLEAR,
|
||||||
active_style=ui.BTN_CLEAR_ACTIVE)
|
# active_style=ui.BTN_CLEAR_ACTIVE)
|
||||||
|
|
||||||
def render(self):
|
# def render(self):
|
||||||
self.render_input()
|
# self.render_input()
|
||||||
if self.zoom_buttons:
|
# if self.zoom_buttons:
|
||||||
for btn in self.zoom_buttons:
|
# for btn in self.zoom_buttons:
|
||||||
btn.render()
|
# btn.render()
|
||||||
else:
|
# else:
|
||||||
for btn in self.key_buttons:
|
# for btn in self.key_buttons:
|
||||||
btn.render()
|
# btn.render()
|
||||||
|
|
||||||
def render_input(self):
|
# def render_input(self):
|
||||||
if self.content:
|
# if self.content:
|
||||||
display.bar(0, 0, 200, 40, ui.BG)
|
# display.bar(0, 0, 200, 40, ui.BG)
|
||||||
else:
|
# else:
|
||||||
display.bar(0, 0, 240, 40, ui.BG)
|
# display.bar(0, 0, 240, 40, ui.BG)
|
||||||
display.text(20, 30, self.content, ui.BOLD, ui.GREY, ui.BG)
|
# display.text(20, 30, self.content, ui.BOLD, ui.GREY, ui.BG)
|
||||||
if self.content:
|
# if self.content:
|
||||||
self.bs_button.render()
|
# self.bs_button.render()
|
||||||
|
|
||||||
def touch(self, event, pos):
|
# def touch(self, event, pos):
|
||||||
if self.bs_button.touch(event, pos) == BTN_CLICKED:
|
# if self.bs_button.touch(event, pos) == BTN_CLICKED:
|
||||||
self.content = self.content[:-1]
|
# self.content = self.content[:-1]
|
||||||
self.bs_button.taint()
|
# self.bs_button.taint()
|
||||||
return
|
# return
|
||||||
if self.zoom_buttons:
|
# if self.zoom_buttons:
|
||||||
return self.touch_zoom(event, pos)
|
# return self.touch_zoom(event, pos)
|
||||||
else:
|
# else:
|
||||||
return self.touch_keyboard(event, pos)
|
# return self.touch_keyboard(event, pos)
|
||||||
|
|
||||||
def touch_zoom(self, event, pos):
|
# def touch_zoom(self, event, pos):
|
||||||
for btn in self.zoom_buttons:
|
# for btn in self.zoom_buttons:
|
||||||
if btn.touch(event, pos) == BTN_CLICKED:
|
# if btn.touch(event, pos) == BTN_CLICKED:
|
||||||
self.content += btn.content
|
# self.content += btn.content
|
||||||
self.zoom_buttons = None
|
# self.zoom_buttons = None
|
||||||
for b in self.key_buttons:
|
# for b in self.key_buttons:
|
||||||
b.taint()
|
# b.taint()
|
||||||
self.bs_button.taint()
|
# self.bs_button.taint()
|
||||||
break
|
# break
|
||||||
|
|
||||||
def touch_keyboard(self, event, pos):
|
# def touch_keyboard(self, event, pos):
|
||||||
for btn in self.key_buttons:
|
# for btn in self.key_buttons:
|
||||||
if btn.touch(event, pos) == BTN_CLICKED:
|
# if btn.touch(event, pos) == BTN_CLICKED:
|
||||||
self.zoom_buttons = zoom_buttons(btn.content, self.uppercase)
|
# self.zoom_buttons = zoom_buttons(btn.content, self.uppercase)
|
||||||
for b in self.zoom_buttons:
|
# for b in self.zoom_buttons:
|
||||||
b.taint()
|
# b.taint()
|
||||||
self.bs_button.taint()
|
# self.bs_button.taint()
|
||||||
break
|
# break
|
||||||
|
|
||||||
def __iter__(self):
|
# def __iter__(self):
|
||||||
timeout = loop.sleep(1000 * 1000 * 1)
|
# timeout = loop.sleep(1000 * 1000 * 1)
|
||||||
touch = loop.select(io.TOUCH)
|
# touch = loop.select(io.TOUCH)
|
||||||
wait = loop.wait(touch, timeout)
|
# wait = loop.wait(touch, timeout)
|
||||||
while True:
|
# while True:
|
||||||
self.render()
|
# self.render()
|
||||||
result = yield wait
|
# result = yield wait
|
||||||
if touch in wait.finished:
|
# if touch in wait.finished:
|
||||||
event, *pos = result
|
# event, *pos = result
|
||||||
self.touch(event, pos)
|
# self.touch(event, pos)
|
||||||
elif self.zoom_buttons:
|
# elif self.zoom_buttons:
|
||||||
self.zoom_buttons = None
|
# self.zoom_buttons = None
|
||||||
for btn in self.key_buttons:
|
# for btn in self.key_buttons:
|
||||||
btn.taint()
|
# btn.taint()
|
||||||
|
|
||||||
|
|
||||||
Keyboard = KeyboardMultiTap
|
Keyboard = KeyboardMultiTap
|
||||||
|
@ -38,7 +38,10 @@ DARK_GREY = rgb(0x3E, 0x3E, 0x3E)
|
|||||||
BLUE_GRAY = rgb(0x60, 0x7D, 0x8B)
|
BLUE_GRAY = rgb(0x60, 0x7D, 0x8B)
|
||||||
BLACK = rgb(0x00, 0x00, 0x00)
|
BLACK = rgb(0x00, 0x00, 0x00)
|
||||||
WHITE = rgb(0xFA, 0xFA, 0xFA)
|
WHITE = rgb(0xFA, 0xFA, 0xFA)
|
||||||
BLACKISH = rgb(0x20, 0x20, 0x20)
|
BLACKISH = rgb(0x30, 0x30, 0x30)
|
||||||
|
|
||||||
|
TITLE_GREY = rgb(0x9B, 0x9B, 0x9B)
|
||||||
|
ORANGE_ICON = rgb(0xF5, 0xA6, 0x23)
|
||||||
|
|
||||||
# common color styles
|
# common color styles
|
||||||
BG = BLACK
|
BG = BLACK
|
||||||
@ -47,11 +50,13 @@ FG = WHITE
|
|||||||
# icons
|
# icons
|
||||||
ICON_RESET = 'trezor/res/header_icons/reset.toig'
|
ICON_RESET = 'trezor/res/header_icons/reset.toig'
|
||||||
ICON_WIPE = 'trezor/res/header_icons/wipe.toig'
|
ICON_WIPE = 'trezor/res/header_icons/wipe.toig'
|
||||||
ICON_RECOVERY = 'trezor/res/header_icons/recovery.toig'
|
ICON_RECOVERY = 'trezor/res/header_icons/reset.toig'
|
||||||
ICON_CLEAR = 'trezor/res/clear.toig'
|
ICON_CLEAR = 'trezor/res/clear.toig'
|
||||||
ICON_CONFIRM = 'trezor/res/confirm.toig'
|
ICON_CONFIRM = 'trezor/res/confirm.toig'
|
||||||
|
ICON_CONFIRM2 = 'trezor/res/confirm2.toig'
|
||||||
ICON_LOCK = 'trezor/res/lock.toig'
|
ICON_LOCK = 'trezor/res/lock.toig'
|
||||||
ICON_SEND = 'trezor/res/send.toig'
|
ICON_SEND = 'trezor/res/send.toig'
|
||||||
|
ICON_CLICK = 'trezor/res/click.toig'
|
||||||
|
|
||||||
# buttons
|
# buttons
|
||||||
BTN_DEFAULT = {
|
BTN_DEFAULT = {
|
||||||
@ -104,7 +109,7 @@ BTN_CONFIRM_ACTIVE = {
|
|||||||
'radius': RADIUS,
|
'radius': RADIUS,
|
||||||
}
|
}
|
||||||
BTN_CLEAR = {
|
BTN_CLEAR = {
|
||||||
'bg-color': BG,
|
'bg-color': ORANGE,
|
||||||
'fg-color': FG,
|
'fg-color': FG,
|
||||||
'text-style': NORMAL,
|
'text-style': NORMAL,
|
||||||
'border-color': BG,
|
'border-color': BG,
|
||||||
@ -131,6 +136,13 @@ BTN_KEY_ACTIVE = {
|
|||||||
'border-color': FG,
|
'border-color': FG,
|
||||||
'radius': RADIUS,
|
'radius': RADIUS,
|
||||||
}
|
}
|
||||||
|
BTN_KEY_DISABLED = {
|
||||||
|
'bg-color': BG,
|
||||||
|
'fg-color': GREY,
|
||||||
|
'text-style': MONO,
|
||||||
|
'border-color': BG,
|
||||||
|
'radius': RADIUS,
|
||||||
|
}
|
||||||
|
|
||||||
# loader
|
# loader
|
||||||
LDR_DEFAULT = {
|
LDR_DEFAULT = {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from micropython import const
|
from micropython import const
|
||||||
from trezor import ui
|
from trezor import ui
|
||||||
|
|
||||||
TEXT_HEADER_HEIGHT = const(32)
|
TEXT_HEADER_HEIGHT = const(51)
|
||||||
TEXT_LINE_HEIGHT = const(23)
|
TEXT_LINE_HEIGHT = const(23)
|
||||||
TEXT_MARGIN_LEFT = const(10)
|
TEXT_MARGIN_LEFT = const(14)
|
||||||
|
|
||||||
|
|
||||||
class Text(ui.Widget):
|
class Text(ui.Widget):
|
||||||
@ -19,7 +19,7 @@ class Text(ui.Widget):
|
|||||||
style = ui.NORMAL
|
style = ui.NORMAL
|
||||||
fg = ui.FG
|
fg = ui.FG
|
||||||
bg = ui.BG
|
bg = ui.BG
|
||||||
ui.header(self.header_text, self.header_icon, ui.GREEN, ui.BG)
|
ui.header(self.header_text, self.header_icon, ui.TITLE_GREY, ui.BG, ui.ORANGE_ICON)
|
||||||
|
|
||||||
for item in self.content:
|
for item in self.content:
|
||||||
if isinstance(item, str):
|
if isinstance(item, str):
|
||||||
|
53
src/trezor/ui/word_select.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
from micropython import const
|
||||||
|
from trezor import loop
|
||||||
|
from trezor import ui, res
|
||||||
|
from trezor.ui import Widget
|
||||||
|
from trezor.ui.button import Button, BTN_CLICKED, BTN_STARTED, BTN_ACTIVE
|
||||||
|
|
||||||
|
W12 = '12'
|
||||||
|
W15 = '15'
|
||||||
|
W18 = '18'
|
||||||
|
W24 = '24'
|
||||||
|
|
||||||
|
class WordSelector(Widget):
|
||||||
|
|
||||||
|
def __init__(self, content):
|
||||||
|
self.content = content
|
||||||
|
self.w12 = Button((6, 135, 114, 51), W12,
|
||||||
|
normal_style=ui.BTN_KEY,
|
||||||
|
active_style=ui.BTN_KEY_ACTIVE)
|
||||||
|
self.w15 = Button((120, 135, 114, 51), W15,
|
||||||
|
normal_style=ui.BTN_KEY,
|
||||||
|
active_style=ui.BTN_KEY_ACTIVE)
|
||||||
|
self.w18 = Button((6, 186, 114, 51), W18,
|
||||||
|
normal_style=ui.BTN_KEY,
|
||||||
|
active_style=ui.BTN_KEY_ACTIVE)
|
||||||
|
self.w24 = Button((120, 186, 114, 51), W24,
|
||||||
|
normal_style=ui.BTN_KEY,
|
||||||
|
active_style=ui.BTN_KEY_ACTIVE)
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
self.w12.render()
|
||||||
|
self.w15.render()
|
||||||
|
self.w18.render()
|
||||||
|
self.w24.render()
|
||||||
|
|
||||||
|
def touch(self, event, pos):
|
||||||
|
if self.w12.touch(event, pos) == BTN_CLICKED:
|
||||||
|
return W12
|
||||||
|
if self.w15.touch(event, pos) == BTN_CLICKED:
|
||||||
|
return W15
|
||||||
|
if self.w18.touch(event, pos) == BTN_CLICKED:
|
||||||
|
return W18
|
||||||
|
if self.w24.touch(event, pos) == BTN_CLICKED:
|
||||||
|
return W24
|
||||||
|
|
||||||
|
async def __iter__(self):
|
||||||
|
return await loop.wait(super().__iter__(), self.content)
|
||||||
|
|
||||||
|
|
||||||
|
_STARTED = const(-1)
|
||||||
|
_STOPPED = const(-2)
|
||||||
|
|
||||||
|
|
||||||
|
|