mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-06-07 16:49:04 +00:00
ui: introduce LazyWidget
Used in Button and Text.
This commit is contained in:
parent
f9d77479d4
commit
6e13a1475b
@ -175,3 +175,21 @@ class Widget:
|
|||||||
event, *pos = yield touch
|
event, *pos = yield touch
|
||||||
result = self.touch(event, pos)
|
result = self.touch(event, pos)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class LazyWidget(Widget):
|
||||||
|
render_next_frame = True
|
||||||
|
|
||||||
|
def taint(self):
|
||||||
|
self.render_next_frame = True
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
touch = loop.wait(io.TOUCH)
|
||||||
|
result = None
|
||||||
|
while result is None:
|
||||||
|
if self.render_next_frame:
|
||||||
|
self.render()
|
||||||
|
self.render_next_frame = False
|
||||||
|
event, *pos = yield touch
|
||||||
|
result = self.touch(event, pos)
|
||||||
|
return result
|
||||||
|
@ -6,57 +6,53 @@ from trezor import ui
|
|||||||
from trezor.ui import contains
|
from trezor.ui import contains
|
||||||
from trezor.ui import display
|
from trezor.ui import display
|
||||||
from trezor.ui import rotate
|
from trezor.ui import rotate
|
||||||
from trezor.ui import Widget
|
from trezor.ui import LazyWidget
|
||||||
|
|
||||||
|
# button events
|
||||||
BTN_CLICKED = const(1)
|
BTN_CLICKED = const(1)
|
||||||
|
|
||||||
BTN_STARTED = const(1)
|
# button states
|
||||||
BTN_ACTIVE = const(2)
|
BTN_INITIAL = const(0)
|
||||||
BTN_DIRTY = const(4)
|
BTN_DISABLED = const(1)
|
||||||
BTN_DISABLED = const(8)
|
BTN_FOCUSED = const(2)
|
||||||
|
BTN_ACTIVE = const(3)
|
||||||
|
|
||||||
|
# constants
|
||||||
ICON = const(16) # icon size in pixels
|
ICON = const(16) # icon size in pixels
|
||||||
BORDER = const(4) # border size in pixels
|
BORDER = const(4) # border size in pixels
|
||||||
|
|
||||||
|
|
||||||
class Button(Widget):
|
class Button(LazyWidget):
|
||||||
|
|
||||||
def __init__(self, area, content, style=ui.BTN_KEY, absolute=False):
|
def __init__(self, area: tuple, content: str, style: dict = ui.BTN_KEY):
|
||||||
self.area = area
|
self.area = area
|
||||||
self.content = content
|
self.content = content
|
||||||
self.normal_style = style['normal'] or ui.BTN_KEY['normal']
|
self.normal_style = style['normal'] or ui.BTN_KEY['normal']
|
||||||
self.active_style = style['active'] or ui.BTN_KEY['active']
|
self.active_style = style['active'] or ui.BTN_KEY['active']
|
||||||
self.disabled_style = style['disabled'] or ui.BTN_KEY['disabled']
|
self.disabled_style = style['disabled'] or ui.BTN_KEY['disabled']
|
||||||
self.absolute = absolute
|
self.state = BTN_INITIAL
|
||||||
self.state = BTN_DIRTY
|
|
||||||
|
|
||||||
def enable(self):
|
def enable(self):
|
||||||
if self.state & BTN_DISABLED:
|
if self.state == BTN_DISABLED:
|
||||||
self.state &= ~BTN_DISABLED
|
self.state = BTN_INITIAL
|
||||||
self.state |= BTN_DIRTY
|
self.render_next_frame = True
|
||||||
|
|
||||||
def disable(self):
|
def disable(self):
|
||||||
if not self.state & BTN_DISABLED:
|
if self.state != BTN_DISABLED:
|
||||||
self.state |= BTN_DISABLED | BTN_DIRTY
|
self.state = BTN_DISABLED
|
||||||
|
self.render_next_frame = True
|
||||||
def taint(self):
|
|
||||||
self.state |= BTN_DIRTY
|
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
if not self.state & BTN_DIRTY:
|
state = self.state
|
||||||
return
|
if state == BTN_DISABLED:
|
||||||
state = self.state & ~BTN_DIRTY
|
|
||||||
if state & BTN_DISABLED:
|
|
||||||
s = self.disabled_style
|
s = self.disabled_style
|
||||||
elif state & BTN_ACTIVE:
|
elif state == BTN_ACTIVE:
|
||||||
s = self.active_style
|
s = self.active_style
|
||||||
else:
|
else:
|
||||||
s = self.normal_style
|
s = self.normal_style
|
||||||
ax, ay, aw, ah = self.area
|
ax, ay, aw, ah = self.area
|
||||||
|
|
||||||
self.render_background(s, ax, ay, aw, ah)
|
self.render_background(s, ax, ay, aw, ah)
|
||||||
self.render_content(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):
|
def render_background(self, s, ax, ay, aw, ah):
|
||||||
radius = s['radius']
|
radius = s['radius']
|
||||||
@ -94,25 +90,29 @@ class Button(Widget):
|
|||||||
tx - ICON // 2, ty - ICON, c, s['fg-color'], s['bg-color'])
|
tx - ICON // 2, ty - ICON, c, s['fg-color'], s['bg-color'])
|
||||||
|
|
||||||
def touch(self, event, pos):
|
def touch(self, event, pos):
|
||||||
|
pos = rotate(pos)
|
||||||
|
|
||||||
state = self.state
|
state = self.state
|
||||||
if state & BTN_DISABLED:
|
if state == BTN_DISABLED:
|
||||||
return
|
return
|
||||||
if not self.absolute:
|
|
||||||
pos = rotate(pos)
|
|
||||||
|
|
||||||
if event == io.TOUCH_START:
|
if event == io.TOUCH_START:
|
||||||
if contains(self.area, pos):
|
if contains(self.area, pos):
|
||||||
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
|
self.state = BTN_ACTIVE
|
||||||
|
self.render_next_frame = True
|
||||||
|
|
||||||
elif event == io.TOUCH_MOVE and state & BTN_STARTED:
|
elif event == io.TOUCH_MOVE:
|
||||||
if contains(self.area, pos):
|
if contains(self.area, pos):
|
||||||
if not state & BTN_ACTIVE:
|
if state == BTN_FOCUSED:
|
||||||
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
|
self.state = BTN_ACTIVE
|
||||||
|
self.render_next_frame = True
|
||||||
else:
|
else:
|
||||||
if state & BTN_ACTIVE:
|
if state == BTN_ACTIVE:
|
||||||
self.state = BTN_STARTED | BTN_DIRTY
|
self.state = BTN_FOCUSED
|
||||||
|
self.render_next_frame = True
|
||||||
|
|
||||||
elif event == io.TOUCH_END and state & BTN_STARTED:
|
elif event == io.TOUCH_END:
|
||||||
self.state = BTN_DIRTY
|
self.state = BTN_INITIAL
|
||||||
if contains(self.area, pos):
|
self.render_next_frame = True
|
||||||
|
if state == BTN_ACTIVE and contains(self.area, pos):
|
||||||
return BTN_CLICKED
|
return BTN_CLICKED
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from micropython import const
|
from micropython import const
|
||||||
from trezor import loop, res, ui
|
from trezor import loop, res, ui
|
||||||
from trezor.ui import Widget
|
from trezor.ui import Widget
|
||||||
from trezor.ui.button import BTN_ACTIVE, BTN_CLICKED, BTN_STARTED, Button
|
from trezor.ui.button import BTN_ACTIVE, BTN_CLICKED, Button
|
||||||
from trezor.ui.loader import Loader
|
from trezor.ui.loader import Loader
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
@ -70,14 +70,16 @@ class HoldToConfirmDialog(Widget):
|
|||||||
|
|
||||||
def touch(self, event, pos):
|
def touch(self, event, pos):
|
||||||
button = self.button
|
button = self.button
|
||||||
was_started = button.state & BTN_STARTED and button.state & BTN_ACTIVE
|
was_active = button.state == BTN_ACTIVE
|
||||||
button.touch(event, pos)
|
button.touch(event, pos)
|
||||||
is_started = button.state & BTN_STARTED and button.state & BTN_ACTIVE
|
is_active = button.state == BTN_ACTIVE
|
||||||
if is_started and not was_started:
|
if is_active and not was_active:
|
||||||
ui.display.clear()
|
ui.display.clear()
|
||||||
self.loader.start()
|
self.loader.start()
|
||||||
return _STARTED
|
return _STARTED
|
||||||
if was_started and not is_started:
|
if was_active and not is_active:
|
||||||
|
if isinstance(self.content, ui.LazyWidget):
|
||||||
|
self.content.taint()
|
||||||
if self.loader.stop():
|
if self.loader.stop():
|
||||||
return CONFIRMED
|
return CONFIRMED
|
||||||
else:
|
else:
|
||||||
|
@ -98,7 +98,7 @@ def render_words(words: list, new_lines: bool, max_lines: int) -> None:
|
|||||||
offset_x += SPACE
|
offset_x += SPACE
|
||||||
|
|
||||||
|
|
||||||
class Text(ui.Widget):
|
class Text(ui.LazyWidget):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
header_text: str,
|
header_text: str,
|
||||||
header_icon: bytes,
|
header_icon: bytes,
|
||||||
|
Loading…
Reference in New Issue
Block a user