class HoldToConfirmDialog(Widget): def __init__( self, content, hold="Hold to confirm", button_style=ui.BTN_CONFIRM, loader_style=ui.LDR_DEFAULT, ): self.content = content self.button = Button(ui.grid(4, n_x=1), hold, style=button_style) self.loader = Loader(style=loader_style) if content.__class__.__iter__ is not Widget.__iter__: raise TypeError( "HoldToConfirmDialog does not support widgets with custom event loop" ) def taint(self): super().taint() self.button.taint() self.content.taint() def render(self): self.button.render() if not self.loader.is_active(): self.content.render() def touch(self, event, pos): button = self.button was_active = button.state == BTN_ACTIVE button.touch(event, pos) is_active = button.state == BTN_ACTIVE if is_active and not was_active: ui.display.clear() self.loader.start() return _STARTED if was_active and not is_active: self.content.taint() if self.loader.stop(): return CONFIRMED else: return _STOPPED async def __iter__(self): result = None while result is None or result < 0: # _STARTED or _STOPPED if self.loader.is_active(): if __debug__: result = await loop.spawn(self.loader, super().__iter__(), confirm_signal) else: result = await loop.spawn(self.loader, super().__iter__()) else: if __debug__: result = await loop.spawn(super().__iter__(), confirm_signal) else: result = await super().__iter__() return result
class HoldToConfirmDialog(Widget): def __init__( self, content, hold="Hold to confirm", button_style=ui.BTN_CONFIRM, loader_style=ui.LDR_DEFAULT, ): self.content = content self.button = Button(ui.grid(4, n_x=1), hold, style=button_style) self.loader = Loader(style=loader_style) def taint(self): super().taint() self.button.taint() self.content.taint() def render(self): self.button.render() def touch(self, event, pos): button = self.button was_active = button.state == BTN_ACTIVE button.touch(event, pos) is_active = button.state == BTN_ACTIVE if is_active and not was_active: ui.display.clear() self.loader.start() return _STARTED if was_active and not is_active: self.content.taint() if self.loader.stop(): return CONFIRMED else: return _STOPPED async def __iter__(self): result = None while result is None or result < 0: # _STARTED or _STOPPED if self.loader.is_active(): content_loop = self.loader else: content_loop = self.content confirm_loop = super().__iter__() # default loop (render on touch) if __debug__: result = await loop.spawn(content_loop, confirm_loop, confirm_signal) else: result = await loop.spawn(content_loop, confirm_loop) return result
class EntrySelector(Widget): def __init__(self, content): self.content = content self.device = Button(ui.grid(8, n_y=4, n_x=4, cells_x=4), "Device") self.host = Button(ui.grid(12, n_y=4, n_x=4, cells_x=4), "Host") def taint(self): super().taint() self.device.taint() self.host.taint() def render(self): self.device.render() self.host.render() def touch(self, event, pos): if self.device.touch(event, pos) == BTN_CLICKED: return DEVICE if self.host.touch(event, pos) == BTN_CLICKED: return HOST async def __iter__(self): return await loop.spawn(super().__iter__(), self.content)
class WordSelector(Widget): def __init__(self, content): self.content = content self.w12 = Button(ui.grid(6, n_y=4, n_x=3, cells_y=2), str(_W12), style=ui.BTN_KEY) self.w18 = Button(ui.grid(7, n_y=4, n_x=3, cells_y=2), str(_W18), style=ui.BTN_KEY) self.w24 = Button(ui.grid(8, n_y=4, n_x=3, cells_y=2), str(_W24), style=ui.BTN_KEY) def taint(self): super().taint() self.w12.taint() self.w18.taint() self.w24.taint() def render(self): self.w12.render() self.w18.render() self.w24.render() def touch(self, event, pos): if self.w12.touch(event, pos) == BTN_CLICKED: return _W12 if self.w18.touch(event, pos) == BTN_CLICKED: return _W18 if self.w24.touch(event, pos) == BTN_CLICKED: return _W24 async def __iter__(self): if __debug__: result = await loop.spawn(super().__iter__(), self.content, input_signal) if isinstance(result, str): return int(result) else: return result else: return await loop.spawn(super().__iter__(), self.content)
class MnemonicKeyboard(ui.Widget): def __init__(self, prompt: str=''): self.prompt = prompt self.input = Input(ui.grid(1, n_x=4, n_y=4, cells_x=3), '', '') self.back = Button(ui.grid(0, n_x=4, n_y=4), res.load(ui.ICON_BACK), style=ui.BTN_CLEAR) self.keys = key_buttons(MNEMONIC_KEYS) self.pbutton = None # pending key button self.pindex = 0 # index of current pending char in pbutton def render(self): if self.input.content: # content button and backspace self.input.render() self.back.render() else: # prompt display.bar(0, 8, 240, 60, ui.BG) display.text(20, 40, self.prompt, ui.BOLD, ui.GREY, ui.BG) # key buttons for btn in self.keys: btn.render() def touch(self, event, pos): content = self.input.content word = self.input.word if self.back.touch(event, pos) == BTN_CLICKED: # backspace, delete the last character of input self.edit(content[:-1]) return if self.input.touch(event, pos) == BTN_CLICKED: # input press, either auto-complete or confirm if content == word: self.edit('') return content else: self.edit(word) return for btn in self.keys: if btn.touch(event, pos) == BTN_CLICKED: # key press, add new char to input or cycle the pending button if self.pbutton is btn: index = (self.pindex + 1) % len(btn.content) content = content[:-1] + btn.content[index] else: index = 0 content += btn.content[0] self.edit(content, btn, index) return def edit(self, content, button=None, index=0): word = bip39.find_word(content) or '' mask = bip39.complete_word(content) self.pbutton = button self.pindex = index self.input.edit(content, word, button is not None) # enable or disable key buttons for btn in self.keys: if btn is button or compute_mask(btn.content) & mask: btn.enable() else: btn.disable() async def __iter__(self): timeout = loop.sleep(1000 * 1000 * 1) touch = loop.select(io.TOUCH) wait_timeout = loop.wait(touch, timeout) wait_touch = loop.wait(touch) content = None self.back.taint() self.input.taint() while content is None: self.render() if self.pbutton is not None: wait = wait_timeout else: wait = wait_touch result = await wait if touch in wait.finished: event, *pos = result content = self.touch(event, pos) else: if self.input.word: # just reset the pending state self.edit(self.input.content) else: # invalid character, backspace it self.edit(self.input.content[:-1]) return content
class PassphraseKeyboard(ui.Widget): def __init__(self, prompt, page=1): self.prompt = Prompt(prompt) self.page = page self.input = Input(ui.grid(0, n_x=1, n_y=6), '') self.back = Button(ui.grid(12), res.load(ui.ICON_BACK), style=ui.BTN_CLEAR) self.done = Button(ui.grid(14), res.load(ui.ICON_CONFIRM), style=ui.BTN_CONFIRM) self.keys = key_buttons(KEYBOARD_KEYS[self.page]) self.pbutton = None # pending key button self.pindex = 0 # index of current pending char in pbutton def render(self): # passphrase or prompt if self.input.content: self.input.render() else: self.prompt.render() render_scrollbar(self.page) # buttons self.back.render() self.done.render() for btn in self.keys: btn.render() def touch(self, event, pos): content = self.input.content if self.back.touch(event, pos) == BTN_CLICKED: if content: # backspace, delete the last character of input self.edit(content[:-1]) return else: # cancel return CANCELLED if self.done.touch(event, pos) == BTN_CLICKED: # confirm button, return the content return content for btn in self.keys: if btn.touch(event, pos) == BTN_CLICKED: if isinstance(btn.content[0], str): # key press, add new char to input or cycle the pending button if self.pbutton is btn: index = (self.pindex + 1) % len(btn.content) content = content[:-1] + btn.content[index] else: index = 0 content += btn.content[0] else: index = 0 content += ' ' self.edit(content, btn, index) return def edit(self, content, button=None, index=0): if button and len(button.content) == 1: # one-letter buttons are never pending button = None index = 0 self.pbutton = button self.pindex = index self.input.edit(content, button is not None) if content: self.back.enable() else: self.back.disable() self.prompt.taint() async def __iter__(self): self.edit(self.input.content) # init button state while True: change = self.change_page() enter = self.enter_text() wait = loop.spawn(change, enter) result = await wait if enter in wait.finished: return result @ui.layout async def enter_text(self): timeout = loop.sleep(1000 * 1000 * 1) touch = loop.wait(io.TOUCH) wait_timeout = loop.spawn(touch, timeout) wait_touch = loop.spawn(touch) content = None while content is None: self.render() if self.pbutton is not None: wait = wait_timeout else: wait = wait_touch result = await wait if touch in wait.finished: event, *pos = result content = self.touch(event, pos) else: # disable the pending buttons self.edit(self.input.content) return content async def change_page(self): swipe = await Swipe(directions=SWIPE_HORIZONTAL) if swipe == SWIPE_LEFT: self.page = (self.page + 1) % len(KEYBOARD_KEYS) else: self.page = (self.page - 1) % len(KEYBOARD_KEYS) self.keys = key_buttons(KEYBOARD_KEYS[self.page]) self.back.taint() self.done.taint() self.input.taint() self.prompt.taint()
class KeyboardZooming(ui.Widget): def __init__(self, content='', uppercase=True): self.content = content self.uppercase = uppercase self.zoom_buttons = None self.key_buttons = key_buttons() self.bs_button = Button((240 - 35, 5, 30, 30), res.load('trezor/res/pin_close.toig'), normal_style=ui.BTN_CLEAR, active_style=ui.BTN_CLEAR_ACTIVE) def render(self): self.render_input() if self.zoom_buttons: for btn in self.zoom_buttons: btn.render() else: for btn in self.key_buttons: btn.render() def render_input(self): if self.content: display.bar(0, 0, 200, 40, ui.BG) else: display.bar(0, 0, 240, 40, ui.BG) display.text(20, 30, self.content, ui.BOLD, ui.GREY, ui.BG) if self.content: self.bs_button.render() def touch(self, event, pos): if self.bs_button.touch(event, pos) == BTN_CLICKED: self.content = self.content[:-1] self.bs_button.taint() return if self.zoom_buttons: return self.touch_zoom(event, pos) else: return self.touch_keyboard(event, pos) def touch_zoom(self, event, pos): for btn in self.zoom_buttons: if btn.touch(event, pos) == BTN_CLICKED: self.content += btn.content self.zoom_buttons = None for b in self.key_buttons: b.taint() self.bs_button.taint() break def touch_keyboard(self, event, pos): for btn in self.key_buttons: if btn.touch(event, pos) == BTN_CLICKED: self.zoom_buttons = zoom_buttons(btn.content, self.uppercase) for b in self.zoom_buttons: b.taint() self.bs_button.taint() break def __iter__(self): timeout = loop.sleep(1000 * 1000 * 1) touch = loop.select(io.TOUCH) wait = loop.wait(touch, timeout) while True: self.render() result = yield wait if touch in wait.finished: event, *pos = result self.touch(event, pos) elif self.zoom_buttons: self.zoom_buttons = None for btn in self.key_buttons: btn.taint()