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), normal_style=ui.BTN_CLEAR, active_style=ui.BTN_CLEAR_ACTIVE) self.keys = key_buttons() self.pbutton = None # pending key button self.pindex = 0 # index of current pending char in pbutton
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=CLEAR_BUTTON, active_style=CLEAR_BUTTON_ACTIVE)
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 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): return await loop.wait(super().__iter__(), self.content)
class Confirm(ui.Layout): DEFAULT_CONFIRM = res.load(ui.ICON_CONFIRM) DEFAULT_CONFIRM_STYLE = ButtonConfirm DEFAULT_CANCEL = res.load(ui.ICON_CANCEL) DEFAULT_CANCEL_STYLE = ButtonCancel def __init__( self, content: ui.Component, confirm: Optional[ButtonContent] = DEFAULT_CONFIRM, confirm_style: ButtonStyleType = DEFAULT_CONFIRM_STYLE, cancel: Optional[ButtonContent] = DEFAULT_CANCEL, cancel_style: ButtonStyleType = DEFAULT_CANCEL_STYLE, major_confirm: bool = False, ) -> None: self.content = content if confirm is not None: if cancel is None: area = ui.grid(4, n_x=1) elif major_confirm: area = ui.grid(13, cells_x=2) else: area = ui.grid(9, n_x=2) self.confirm = Button(area, confirm, confirm_style) # type: Optional[Button] self.confirm.on_click = self.on_confirm # type: ignore else: self.confirm = None if cancel is not None: if confirm is None: area = ui.grid(4, n_x=1) elif major_confirm: area = ui.grid(12, cells_x=1) else: area = ui.grid(8, n_x=2) self.cancel = Button(area, cancel, cancel_style) # type: Optional[Button] self.cancel.on_click = self.on_cancel # type: ignore else: self.cancel = None def dispatch(self, event: int, x: int, y: int) -> None: self.content.dispatch(event, x, y) if self.confirm is not None: self.confirm.dispatch(event, x, y) if self.cancel is not None: self.cancel.dispatch(event, x, y) def on_confirm(self) -> None: raise ui.Result(CONFIRMED) def on_cancel(self) -> None: raise ui.Result(CANCELLED)
class PageWithButtons(ui.Component): def __init__( self, content: ui.Component, paginated: "PaginatedWithButtons", index: int, count: int, ) -> None: self.content = content self.paginated = paginated self.index = index self.count = count # somewhere in the middle, we can go up or down left = res.load(ui.ICON_BACK) left_style = ButtonDefault right = res.load(ui.ICON_CLICK) right_style = ButtonDefault if self.index == 0: # first page, we can cancel or go down left = res.load(ui.ICON_CANCEL) left_style = ButtonCancel right = res.load(ui.ICON_CLICK) right_style = ButtonDefault elif self.index == count - 1: # last page, we can go up or confirm left = res.load(ui.ICON_BACK) left_style = ButtonDefault right = res.load(ui.ICON_CONFIRM) right_style = ButtonConfirm self.left = Button(ui.grid(8, n_x=2), left, left_style) self.left.on_click = self.on_left # type: ignore self.right = Button(ui.grid(9, n_x=2), right, right_style) self.right.on_click = self.on_right # type: ignore def dispatch(self, event: int, x: int, y: int) -> None: self.content.dispatch(event, x, y) self.left.dispatch(event, x, y) self.right.dispatch(event, x, y) def on_left(self) -> None: if self.index == 0: self.paginated.on_cancel() else: self.paginated.on_up() def on_right(self) -> None: if self.index == self.count - 1: self.paginated.on_confirm() else: self.paginated.on_down()
class PinMatrix(ui.Widget): def __init__(self, label, pin=''): self.label = label self.pin = pin self.digits = generate_digits() # we lay out the buttons top-left to bottom-right, but the order of the # digits is defined as bottom-left to top-right (on numpad) reordered_digits = self.digits[6:] + self.digits[3:6] + self.digits[:3] self.pin_buttons = [ Button(digit_area(i), str(d)) for i, d in enumerate(reordered_digits) ] self.clear_button = Button((240 - 35, 5, 30, 30), res.load('trezor/res/pin_close.toig'), normal_style=CLEAR_BUTTON, active_style=CLEAR_BUTTON_ACTIVE) def render(self): header = '*' * len(self.pin) if self.pin else self.label # clear canvas under input line display.bar(0, 0, 205, 48, ui.BLACK) # input line with a header display.text_center(120, 30, header, ui.BOLD, ui.GREY, ui.BLACK) # render clear button if self.pin: self.clear_button.render() else: display.bar(240 - 48, 0, 48, 42, ui.BLACK) # pin matrix buttons for btn in self.pin_buttons: btn.render() # vertical border bars # display.bar(79, 48, 2, 143, ui.blend(ui.BLACK, ui.WHITE, 0.25)) # display.bar(158, 48, 2, 143, ui.blend(ui.BLACK, ui.WHITE, 0.25)) # horizontal border bars # display.bar(0, 95, 240, 2, ui.blend(ui.BLACK, ui.WHITE, 0.25)) # display.bar(0, 142, 240, 2, ui.blend(ui.BLACK, ui.WHITE, 0.25)) def touch(self, event, pos): if self.clear_button.touch(event, pos) == BTN_CLICKED: self.pin = '' for btn in self.pin_buttons: if btn.touch(event, pos) == BTN_CLICKED: if len(self.pin) < 9: self.pin += btn.content
def __init__(self, content): self.content = content self.w12 = Button(ui.grid(6, n_y=4), "12") self.w12.on_click = self.on_w12 self.w18 = Button(ui.grid(7, n_y=4), "18") self.w18.on_click = self.on_w18 self.w20 = Button(ui.grid(8, n_y=4), "20") self.w20.on_click = self.on_w20 self.w24 = Button(ui.grid(9, n_y=4), "24") self.w24.on_click = self.on_w24 self.w33 = Button(ui.grid(10, n_y=4), "33") self.w33.on_click = self.on_w33
class Confirm(ui.Layout): DEFAULT_CONFIRM = res.load(ui.ICON_CONFIRM) DEFAULT_CONFIRM_STYLE = ButtonConfirm DEFAULT_CANCEL = res.load(ui.ICON_CANCEL) DEFAULT_CANCEL_STYLE = ButtonCancel def __init__( self, content, confirm=DEFAULT_CONFIRM, confirm_style=DEFAULT_CONFIRM_STYLE, cancel=DEFAULT_CANCEL, cancel_style=DEFAULT_CANCEL_STYLE, major_confirm=False, ): self.content = content if confirm is not None: if cancel is None: area = ui.grid(4, n_x=1) elif major_confirm: area = ui.grid(13, cells_x=2) else: area = ui.grid(9, n_x=2) self.confirm = Button(area, confirm, confirm_style) self.confirm.on_click = self.on_confirm else: self.confirm = None if cancel is not None: if confirm is None: area = ui.grid(4, n_x=1) elif major_confirm: area = ui.grid(12, cells_x=1) else: area = ui.grid(8, n_x=2) self.cancel = Button(area, cancel, cancel_style) self.cancel.on_click = self.on_cancel else: self.cancel = None def dispatch(self, event, x, y): self.content.dispatch(event, x, y) if self.confirm is not None: self.confirm.dispatch(event, x, y) if self.cancel is not None: self.cancel.dispatch(event, x, y) def on_confirm(self): raise ui.Result(CONFIRMED) def on_cancel(self): raise ui.Result(CANCELLED)
def __init__(self, content: ui.Component) -> None: self.content = content self.w12 = Button(ui.grid(6, n_y=4), "12") self.w12.on_click = self.on_w12 # type: ignore self.w18 = Button(ui.grid(7, n_y=4), "18") self.w18.on_click = self.on_w18 # type: ignore self.w20 = Button(ui.grid(8, n_y=4), "20") self.w20.on_click = self.on_w20 # type: ignore self.w24 = Button(ui.grid(9, n_y=4), "24") self.w24.on_click = self.on_w24 # type: ignore self.w33 = Button(ui.grid(10, n_y=4), "33") self.w33.on_click = self.on_w33 # type: ignore
def __init__(self, count=5, max_count=16, min_count=1): self.count = count self.max_count = max_count self.min_count = min_count self.minus = Button(ui.grid(3), "-") self.minus.on_click = self.on_minus self.plus = Button(ui.grid(5), "+") self.plus.on_click = self.on_plus self.text = Label(ui.grid(4), "", LABEL_CENTER, ui.BOLD) self.edit(count)
class HoldToConfirm(ui.Layout): DEFAULT_CONFIRM = "Hold To Confirm" DEFAULT_CONFIRM_STYLE = ButtonConfirm DEFAULT_LOADER_STYLE = LoaderDefault def __init__( self, content: ui.Component, confirm: str = DEFAULT_CONFIRM, confirm_style: ButtonStyleType = DEFAULT_CONFIRM_STYLE, loader_style: LoaderStyleType = DEFAULT_LOADER_STYLE, ): self.content = content self.loader = Loader(loader_style) self.loader.on_start = self._on_loader_start # type: ignore self.button = Button(ui.grid(4, n_x=1), confirm, confirm_style) self.button.on_press_start = self._on_press_start # type: ignore self.button.on_press_end = self._on_press_end # type: ignore self.button.on_click = self._on_click # type: ignore def _on_press_start(self) -> None: self.loader.start() def _on_press_end(self) -> None: self.loader.stop() def _on_loader_start(self) -> None: # Loader has either started growing, or returned to the 0-position. # In the first case we need to clear the content leftovers, in the latter # we need to render the content again. ui.display.bar(0, 0, ui.WIDTH, ui.HEIGHT - 60, ui.BG) self.content.dispatch(ui.REPAINT, 0, 0) def _on_click(self) -> None: if self.loader.elapsed_ms() >= self.loader.target_ms: self.on_confirm() def dispatch(self, event: int, x: int, y: int) -> None: if self.loader.start_ms is not None: self.loader.dispatch(event, x, y) else: self.content.dispatch(event, x, y) self.button.dispatch(event, x, y) def on_confirm(self) -> None: raise ui.Result(CONFIRMED) if __debug__: def read_content(self) -> List[str]: return self.content.read_content()
def __init__(self, content=''): self.content = content self.sugg_mask = 0xffffffff self.sugg_word = None self.pending_button = None self.pending_index = 0 self.key_buttons = key_buttons() self.bs_button = Button((240 - 35, 5, 30, 30), res.load('trezor/res/pin_close.toig'), normal_style=CLEAR_BUTTON, active_style=CLEAR_BUTTON_ACTIVE)
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
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
def __init__(self, prompt: str, subprompt: str, allow_cancel: bool = True, maxlength: int = 9) -> None: self.maxlength = maxlength self.input = PinInput(prompt, subprompt, "") icon_confirm = res.load(ui.ICON_CONFIRM) self.confirm_button = Button(ui.grid(14), icon_confirm, ButtonConfirm) self.confirm_button.on_click = self.on_confirm # type: ignore self.confirm_button.disable() icon_back = res.load(ui.ICON_BACK) self.reset_button = Button(ui.grid(12), icon_back, ButtonClear) self.reset_button.on_click = self.on_reset # type: ignore if allow_cancel: icon_lock = res.load(ui.ICON_LOCK) self.cancel_button = Button(ui.grid(12), icon_lock, ButtonCancel) self.cancel_button.on_click = self.on_cancel # type: ignore else: self.cancel_button = Button(ui.grid(12), "") self.cancel_button.disable() self.pin_buttons = [ PinButton(i, d, self) for i, d in enumerate(generate_digits()) ]
def __init__( self, text: str, confirm: ButtonContent = DEFAULT_CONFIRM, style: InfoConfirmStyleType = DEFAULT_STYLE, ) -> None: super().__init__() self.text = text.split() self.style = style panel_area = ui.grid(0, n_x=1, n_y=1) self.panel_area = panel_area confirm_area = ui.grid(4, n_x=1) self.confirm = Button(confirm_area, confirm, style.button) self.confirm.on_click = self.on_confirm # type: ignore
def generate_buttons(start, end, page, pad): start = start + (_ITEMS_PER_PAGE + 1) * page - page end = min(end, (_ITEMS_PER_PAGE + 1) * (page + 1) - page) digits = list(range(start, end)) buttons = [NumButton(i, d, pad) for i, d in enumerate(digits)] area = ui.grid(_PLUS_BUTTON_POSITION + 3) plus = Button(area, str(end) + "+", ButtonMonoDark) plus.on_click = pad.on_plus area = ui.grid(_BACK_BUTTON_POSITION + 3) back = Button(area, res.load(ui.ICON_BACK), ButtonMonoDark) back.on_click = pad.on_back if len(digits) == _ITEMS_PER_PAGE: # move the tenth button to its proper place and make place for the back button buttons[-1].area = ui.grid(_PLUS_BUTTON_POSITION - 1 + 3) buttons.append(plus) if page == 0: back.disable() buttons.append(back) return buttons
class InfoConfirm(ui.Layout): DEFAULT_CONFIRM = res.load(ui.ICON_CONFIRM) DEFAULT_STYLE = DefaultInfoConfirm def __init__( self, text: str, confirm: ButtonContent = DEFAULT_CONFIRM, style: InfoConfirmStyleType = DEFAULT_STYLE, ) -> None: super().__init__() self.text = text.split() self.style = style panel_area = ui.grid(0, n_x=1, n_y=1) self.panel_area = panel_area confirm_area = ui.grid(4, n_x=1) self.confirm = Button(confirm_area, confirm, style.button) self.confirm.on_click = self.on_confirm # type: ignore def dispatch(self, event: int, x: int, y: int) -> None: if event == ui.RENDER: self.on_render() self.confirm.dispatch(event, x, y) def on_render(self) -> None: if self.repaint: x, y, w, h = self.panel_area fg_color = self.style.fg_color bg_color = self.style.bg_color # render the background panel ui.display.bar_radius(x, y, w, h, bg_color, ui.BG, ui.RADIUS) # render the info text render_text( # type: ignore self.text, new_lines=False, max_lines=6, offset_y=y + TEXT_LINE_HEIGHT, offset_x=x + TEXT_MARGIN_LEFT - ui.VIEWX, offset_x_max=x + w - ui.VIEWX, fg=fg_color, bg=bg_color, ) self.repaint = False def on_confirm(self) -> None: raise ui.Result(CONFIRMED)
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 __init__(self, words, share_index, word_index): self.words = words self.share_index = share_index self.word_index = word_index self.buttons = [] for i, word in enumerate(words): area = ui.grid(i + 2, n_x=1) btn = Button(area, word) btn.on_click = self.select(word) self.buttons.append(btn) if share_index is None: self.text = Text("Check seed") else: self.text = Text("Check share #%s" % (share_index + 1)) self.text.normal("Select the %s word:" % utils.format_ordinal(word_index + 1))
def __init__( self, content: ui.Component, confirm: str = DEFAULT_CONFIRM, confirm_style: ButtonStyleType = DEFAULT_CONFIRM_STYLE, loader_style: LoaderStyleType = DEFAULT_LOADER_STYLE, ): self.content = content self.loader = Loader(loader_style) self.loader.on_start = self._on_loader_start # type: ignore self.button = Button(ui.grid(4, n_x=1), confirm, confirm_style) self.button.on_press_start = self._on_press_start # type: ignore self.button.on_press_end = self._on_press_end # type: ignore self.button.on_click = self._on_click # type: ignore
def __init__(self, count: int = 5, max_count: int = 16, min_count: int = 1) -> None: super().__init__() self.count = count self.max_count = max_count self.min_count = min_count self.minus = Button(ui.grid(3), "-") self.minus.on_click = self.on_minus # type: ignore self.plus = Button(ui.grid(5), "+") self.plus.on_click = self.on_plus # type: ignore self.text = Label(ui.grid(4), "", LABEL_CENTER, ui.BOLD) self.edit(count)
def __init__( self, content, confirm=DEFAULT_CONFIRM, confirm_style=DEFAULT_CONFIRM_STYLE, loader_style=DEFAULT_LOADER_STYLE, ): self.content = content self.loader = Loader(loader_style) self.loader.on_start = self._on_loader_start self.button = Button(ui.grid(4, n_x=1), confirm, confirm_style) self.button.on_press_start = self._on_press_start self.button.on_press_end = self._on_press_end self.button.on_click = self._on_click
def __init__(self, label, pin=''): self.label = label self.pin = pin self.digits = generate_digits() # we lay out the buttons top-left to bottom-right, but the order of the # digits is defined as bottom-left to top-right (on numpad) reordered_digits = self.digits[6:] + self.digits[3:6] + self.digits[:3] self.pin_buttons = [ Button(digit_area(i), str(d)) for i, d in enumerate(reordered_digits) ] self.clear_button = Button((240 - 35, 5, 30, 30), res.load('trezor/res/pin_close.toig'), normal_style=CLEAR_BUTTON, active_style=CLEAR_BUTTON_ACTIVE)
def _generate_buttons(self): display.clear() # we need to clear old buttons start = self.start + (ITEMS_PER_PAGE + 1) * self.page - self.page end = min(self.end, (ITEMS_PER_PAGE + 1) * (self.page + 1) - self.page) digits = list(range(start, end)) if len(digits) == ITEMS_PER_PAGE: digits.append(str(end) + "+") self.buttons = [Button(digit_area(i), str(d)) for i, d in enumerate(digits)]
def __init__(self, prompt): self.prompt = Prompt(prompt) icon_back = res.load(ui.ICON_BACK) self.back = Button(ui.grid(0, n_x=4, n_y=4), icon_back, ButtonClear) self.back.on_click = self.on_back_click self.input = InputButton(ui.grid(1, n_x=4, n_y=4, cells_x=3), "", "") self.input.on_click = self.on_input_click self.keys = [ KeyButton(ui.grid(i + 3, n_y=4), k, self) for i, k in enumerate(("abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz")) ] self.pending_button = None self.pending_index = 0
def zoom_buttons(keys, upper=False): n_x = len(keys) if upper: keys = keys + keys.upper() n_y = 2 else: n_y = 1 return [Button(cell_area(i, n_x, n_y), key) for i, key in enumerate(keys)]
def __init__(self, prompt: str, max_length: int, page: int = 1) -> None: self.prompt = Prompt(prompt) self.max_length = max_length 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), ButtonClear) self.back.on_click = self.on_back_click # type: ignore self.back.disable() self.done = Button(ui.grid(14), res.load(ui.ICON_CONFIRM), ButtonConfirm) self.done.on_click = self.on_confirm # type: ignore self.keys = key_buttons(KEYBOARD_KEYS[self.page], self) self.pending_button = None # type: Optional[KeyButton] self.pending_index = 0
def __init__(self, prompt): self.prompt = Prompt(prompt) icon_back = res.load(ui.ICON_BACK) self.back = Button(ui.grid(0, n_x=4, n_y=4), icon_back, ButtonClear) self.back.on_click = self.on_back_click self.input = InputButton(ui.grid(1, n_x=4, n_y=4, cells_x=3), "", "") self.input.on_click = self.on_input_click self.keys = [ KeyButton(ui.grid(i + 3, n_y=4), k, self, i + 1) for i, k in enumerate(("ab", "cd", "ef", "ghij", "klm", "nopq", "rs", "tuv", "wxyz")) ] self.pending_button = None self.pending_index = 0 self.button_sequence = ""
def key_buttons(): keys = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz'] # keys = [' ', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz'] return [ Button(cell_area(i), k, normal_style=ui.BTN_KEY, active_style=ui.BTN_KEY_ACTIVE) for i, k in enumerate(keys) ]