From 6e13a1475b51bd1ff308fc60d95b13aa721c9637 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Thu, 28 Jun 2018 14:05:38 +0200 Subject: [PATCH] ui: introduce LazyWidget Used in Button and Text. --- src/trezor/ui/__init__.py | 18 ++++++++++ src/trezor/ui/button.py | 74 +++++++++++++++++++-------------------- src/trezor/ui/confirm.py | 12 ++++--- src/trezor/ui/text.py | 2 +- 4 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/trezor/ui/__init__.py b/src/trezor/ui/__init__.py index 236b19e0b..4465c92b7 100644 --- a/src/trezor/ui/__init__.py +++ b/src/trezor/ui/__init__.py @@ -175,3 +175,21 @@ class Widget: event, *pos = yield touch result = self.touch(event, pos) 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 diff --git a/src/trezor/ui/button.py b/src/trezor/ui/button.py index 8009b1719..f51ade51d 100644 --- a/src/trezor/ui/button.py +++ b/src/trezor/ui/button.py @@ -6,57 +6,53 @@ from trezor import ui from trezor.ui import contains from trezor.ui import display from trezor.ui import rotate -from trezor.ui import Widget +from trezor.ui import LazyWidget +# button events BTN_CLICKED = const(1) -BTN_STARTED = const(1) -BTN_ACTIVE = const(2) -BTN_DIRTY = const(4) -BTN_DISABLED = const(8) +# button states +BTN_INITIAL = const(0) +BTN_DISABLED = const(1) +BTN_FOCUSED = const(2) +BTN_ACTIVE = const(3) +# constants ICON = const(16) # icon 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.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 + self.state = BTN_INITIAL def enable(self): - if self.state & BTN_DISABLED: - self.state &= ~BTN_DISABLED - self.state |= BTN_DIRTY + if self.state == BTN_DISABLED: + self.state = BTN_INITIAL + self.render_next_frame = True def disable(self): - if not self.state & BTN_DISABLED: - self.state |= BTN_DISABLED | BTN_DIRTY - - def taint(self): - self.state |= BTN_DIRTY + if self.state != BTN_DISABLED: + self.state = BTN_DISABLED + self.render_next_frame = True def render(self): - if not self.state & BTN_DIRTY: - return - state = self.state & ~BTN_DIRTY - if state & BTN_DISABLED: + state = self.state + if state == BTN_DISABLED: s = self.disabled_style - elif state & BTN_ACTIVE: + 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'] @@ -94,25 +90,29 @@ class Button(Widget): tx - ICON // 2, ty - ICON, c, s['fg-color'], s['bg-color']) def touch(self, event, pos): + pos = rotate(pos) + state = self.state - if state & BTN_DISABLED: + 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 + 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 not state & BTN_ACTIVE: - self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE + if state == BTN_FOCUSED: + self.state = BTN_ACTIVE + self.render_next_frame = True 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): + if state == BTN_ACTIVE: + self.state = BTN_FOCUSED + self.render_next_frame = True + + elif event == io.TOUCH_END: + self.state = BTN_INITIAL + self.render_next_frame = True + if state == BTN_ACTIVE and contains(self.area, pos): return BTN_CLICKED diff --git a/src/trezor/ui/confirm.py b/src/trezor/ui/confirm.py index e98f23435..d27fd35ce 100644 --- a/src/trezor/ui/confirm.py +++ b/src/trezor/ui/confirm.py @@ -1,7 +1,7 @@ from micropython import const from trezor import loop, res, ui 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 if __debug__: @@ -70,14 +70,16 @@ class HoldToConfirmDialog(Widget): def touch(self, event, pos): button = self.button - was_started = button.state & BTN_STARTED and button.state & BTN_ACTIVE + was_active = button.state == BTN_ACTIVE button.touch(event, pos) - is_started = button.state & BTN_STARTED and button.state & BTN_ACTIVE - if is_started and not was_started: + is_active = button.state == BTN_ACTIVE + if is_active and not was_active: ui.display.clear() self.loader.start() 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(): return CONFIRMED else: diff --git a/src/trezor/ui/text.py b/src/trezor/ui/text.py index 3abb06b1b..27ae2280b 100644 --- a/src/trezor/ui/text.py +++ b/src/trezor/ui/text.py @@ -98,7 +98,7 @@ def render_words(words: list, new_lines: bool, max_lines: int) -> None: offset_x += SPACE -class Text(ui.Widget): +class Text(ui.LazyWidget): def __init__(self, header_text: str, header_icon: bytes,