WIP: more UI experiments, now with 100% more OOP

pull/25/head
Jan Pochyla 8 years ago committed by Pavol Rusnak
parent 4fec964a90
commit 15a03ce994
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D

@ -3,56 +3,12 @@ from trezor import ui
from trezor.utils import unimport_func
def multiplex_touch_events(gens):
while True:
event = yield loop.Wait([
loop.TOUCH_START,
loop.TOUCH_MOVE,
loop.TOUCH_END,
])
for gen in gens:
gen.send(event)
def in_area(pos, area):
x, y = pos
ax, ay, aw, ah = area
return ax <= x <= ax + aw and ay <= y <= ay + ah
def click_in(area, click=None, enter=None, leave=None):
while True:
e, pos = yield
if e is not loop.TOUCH_START or not in_area(pos, area):
continue
inside = True
if enter:
enter()
while True:
e, pos = yield
if e is loop.TOUCH_MOVE:
if in_area(pos, area):
if not inside:
if enter:
enter()
inside = True
else:
if inside:
if leave:
leave()
inside = False
elif e is loop.TOUCH_END:
if in_area(pos, area):
if click:
click()
else:
return
else:
break
default_button = {
'bg-color': ui.WHITE,
'fg-color': ui.BLACK,
@ -85,90 +41,102 @@ confirm_button_active = {
}
def render_button(area, text, style):
ax, ay, aw, ah = area
tx = ax + aw // 2
ty = ay + ah - 5
ui.display.bar(ax, ay, aw, ah, style['bg-color'])
ui.display.text_center(tx, ty, text,
style['text-style'],
style['fg-color'],
style['bg-color'])
def button_widget(area, text,
click=None,
style=default_button,
active_style=default_button_active):
def enter():
render_button(area, text, active_style)
def leave():
render_button(area, text, style)
def _click():
leave()
click()
render_button(area, text, style)
return click_in(area, _click, enter, leave)
def pin_widget():
pin = ''
BTN_CLICKED = const(1)
BTN_STARTED = const(1)
BTN_ACTIVE = const(2)
BTN_DIRTY = const(4)
class Button():
def __init__(self, area, text,
style=default_button,
active_style=default_button_active):
self.area = area
self.text = text
self.style = style
self.active_style = active_style
self.state = BTN_DIRTY
def render(self):
if not self.state & BTN_DIRTY:
return
state = self.state & ~BTN_DIRTY
style = self.active_style if state & BTN_ACTIVE else self.style
ax, ay, aw, ah = self.area
tx = ax + aw // 2
ty = ay + ah - 5
ui.display.bar(ax, ay, aw, ah, style['bg-color'])
ui.display.text_center(tx, ty, self.text,
style['text-style'],
style['fg-color'],
style['bg-color'])
self.state = state
def progress(self, event, pos):
if event is loop.TOUCH_START:
if in_area(pos, self.area):
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
elif event is loop.TOUCH_MOVE and self.state & BTN_STARTED:
if in_area(pos, self.area):
if not self.state & BTN_ACTIVE:
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
else:
if self.state & BTN_ACTIVE:
self.state = BTN_STARTED | BTN_DIRTY
elif event is loop.TOUCH_END and self.state & BTN_STARTED:
self.state = BTN_DIRTY
if in_area(pos, self.area):
return BTN_CLICKED
def digit_area(d):
width = const(80)
height = const(60)
margin = const(5)
def digit_area(d):
x = ((d - 1) % 3) * width
y = ((d - 1) // 3) * height
return (
x + margin,
y + margin,
width - margin,
height - margin
)
def append_digit(d):
pin += str(d)
print('PIN so far: ', pin)
def digit_widget(digit):
nonlocal pin
area = digit_area(digit)
button = button_widget(
area,
str(digit),
lambda: append_digit(digit))
return button
digits = (1, 2, 3, 4, 5, 6, 7, 8, 9)
buttons = [digit_widget(d) for d in digits]
def cancel():
raise StopIteration(None)
def confirm():
raise StopIteration(pin)
cancel_widget = button_widget((0, 240 - 60, 120, 60), 'Cancel',
click=cancel,
style=cancel_button,
active_style=cancel_button_active)
confirm_widget = button_widget((120, 240 - 60, 120, 60), 'Confirm',
click=confirm,
style=confirm_button,
active_style=confirm_button_active)
buttons.append(cancel_widget)
buttons.append(confirm_widget)
for but in buttons:
next(but)
return buttons
margin = const(1)
x = ((d - 1) % 3) * width
y = ((d - 1) // 3) * height
return (
x + margin,
y + margin,
width - margin,
height - margin)
PIN_CONFIRMED = const(1)
PIN_CANCELLED = const(2)
class PinDialog():
def __init__(self):
self.confirm_button = Button(
(0, 240-60, 120, 60), 'Confirm',
style=confirm_button,
active_style=confirm_button_active)
self.cancel_button = Button(
(120, 240-60, 120, 60), 'Cancel',
style=cancel_button,
active_style=cancel_button_active)
self.pin_buttons = [
Button(digit_area(d), str(d)) for d in range(1, 10)]
self.pin = ''
def render(self):
for b in self.pin_buttons:
b.render()
self.confirm_button.render()
self.cancel_button.render()
def progress(self, event, pos):
for b in self.pin_buttons:
if b.progress(event, pos) is BTN_CLICKED:
self.pin += b.text
if self.confirm_button.progress(event, pos) is BTN_CLICKED:
return PIN_CONFIRMED
if self.cancel_button.progress(event, pos) is BTN_CLICKED:
return PIN_CANCELLED
def layout_tap_to_confirm(address, amount, currency):
@ -193,17 +161,25 @@ def layout_tap_to_confirm(address, amount, currency):
# animation = ui.animate_pulse(func, ui.BLACK, ui.GREY, speed=200000)
# button = button_widget((20, 20, 210, 60), 'HELLO WORLD!')
# next(button)
pin = PinDialog()
pin = pin_widget()
result = yield loop.Wait((
# animation,
multiplex_touch_events(pin),
))
while True:
pin.render()
print(result)
# TODO: if we simply wait for any of scalar events, we can use
# something much more lightweight than loop.Wait
event, pos = yield loop.Wait([
loop.TOUCH_START,
loop.TOUCH_MOVE,
loop.TOUCH_END,
])
result = pin.progress(event, pos)
if result is PIN_CONFIRMED:
print('PIN confirmed:', pin.pin)
return
elif result is PIN_CANCELLED:
print('PIN CANCELLED, go home')
return
@unimport_func

Loading…
Cancel
Save