コード例 #1
0
ファイル: scroll.py プロジェクト: vhud/trezor-firmware
class PageWithButtons(ui.Component):
    def __init__(
        self,
        content: ui.Component,
        paginated: "PaginatedWithButtons",
        index: int,
        count: int,
    ) -> None:
        super().__init__()
        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()

    if __debug__:

        def read_content(self) -> List[str]:
            return self.content.read_content()
コード例 #2
0
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 - 58, 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 create_tasks(self) -> Tuple[loop.Task, ...]:
            return super().create_tasks() + (confirm_signal(), )
コード例 #3
0
ファイル: confirm.py プロジェクト: tomtau/trezor-firmware
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:
        super().dispatch(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) -> None:
        raise ui.Result(CONFIRMED)

    def on_cancel(self) -> None:
        raise ui.Result(CANCELLED)
コード例 #4
0
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)
コード例 #5
0
ファイル: info.py プロジェクト: vhud/trezor-firmware
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)
コード例 #6
0
class PageWithButtons(ui.Control):
    def __init__(self, content, paginated, index, count):
        self.content = content
        self.paginated = paginated
        self.index = index
        self.count = count

        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
        else:
            # 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

        self.left = Button(ui.grid(8, n_x=2), left, left_style)
        self.left.on_click = self.on_left

        self.right = Button(ui.grid(9, n_x=2), right, right_style)
        self.right.on_click = self.on_right

    def dispatch(self, event, x, y):
        self.content.dispatch(event, x, y)
        self.left.dispatch(event, x, y)
        self.right.dispatch(event, x, y)

    def on_left(self):
        if self.index == 0:
            self.paginated.on_cancel()
        else:
            self.paginated.on_down()

    def on_right(self):
        if self.index == self.count - 1:
            self.paginated.on_confirm()
        else:
            self.paginated.on_up()
コード例 #7
0
class NumInput(ui.Component):
    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 dispatch(self, event: int, x: int, y: int) -> None:
        self.minus.dispatch(event, x, y)
        self.plus.dispatch(event, x, y)
        self.text.dispatch(event, x, y)

    def on_minus(self) -> None:
        self.edit(self.count - 1)

    def on_plus(self) -> None:
        self.edit(self.count + 1)

    def edit(self, count: int) -> None:
        count = max(count, self.min_count)
        count = min(count, self.max_count)
        if self.count != count:
            self.on_change(count)
        self.count = count
        self.text.content = str(count)
        self.text.repaint = True
        if self.count == self.min_count:
            self.minus.disable()
        else:
            self.minus.enable()
        if self.count == self.max_count:
            self.plus.disable()
        else:
            self.plus.enable()

    def on_change(self, count: int) -> None:
        pass
コード例 #8
0
class HoldToConfirm(ui.Layout):
    DEFAULT_CONFIRM = "Hold To Confirm"
    DEFAULT_CONFIRM_STYLE = ButtonConfirm
    DEFAULT_LOADER_STYLE = LoaderDefault

    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 _on_press_start(self):
        self.loader.start()

    def _on_press_end(self):
        self.loader.stop()

    def _on_loader_start(self):
        # 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):
        if self.loader.elapsed_ms() >= self.loader.target_ms:
            self.on_confirm()

    def dispatch(self, event, x, y):
        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):
        raise ui.Result(CONFIRMED)
コード例 #9
0
class WordSelector(ui.Layout):
    def __init__(self, content: ui.Component) -> None:
        super().__init__()
        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 dispatch(self, event: int, x: int, y: int) -> None:
        self.content.dispatch(event, x, y)
        self.w12.dispatch(event, x, y)
        self.w18.dispatch(event, x, y)
        self.w20.dispatch(event, x, y)
        self.w24.dispatch(event, x, y)
        self.w33.dispatch(event, x, y)

    def on_w12(self) -> None:
        raise ui.Result(12)

    def on_w18(self) -> None:
        raise ui.Result(18)

    def on_w20(self) -> None:
        raise ui.Result(20)

    def on_w24(self) -> None:
        raise ui.Result(24)

    def on_w33(self) -> None:
        raise ui.Result(33)

    if __debug__:

        def create_tasks(self) -> Tuple[loop.Task, ...]:
            from apps.debug import input_signal

            return super().create_tasks() + (input_signal(), )
コード例 #10
0
class PassphraseSource(ui.Layout):
    def __init__(self, content: ui.Control) -> None:
        self.content = content

        self.device = Button(ui.grid(8, n_y=4, n_x=4, cells_x=4), "Device")
        self.device.on_click = self.on_device  # type: ignore

        self.host = Button(ui.grid(12, n_y=4, n_x=4, cells_x=4), "Host")
        self.host.on_click = self.on_host  # type: ignore

    def dispatch(self, event: int, x: int, y: int) -> None:
        self.content.dispatch(event, x, y)
        self.device.dispatch(event, x, y)
        self.host.dispatch(event, x, y)

    def on_device(self) -> None:
        raise ui.Result(PassphraseSourceType.DEVICE)

    def on_host(self) -> None:
        raise ui.Result(PassphraseSourceType.HOST)
コード例 #11
0
class PinDialog(ui.Layout):
    def __init__(self, prompt, subprompt, allow_cancel=True, maxlength=9):
        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

        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

        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
        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 dispatch(self, event, x, y):
        for btn in self.pin_buttons:
            btn.dispatch(event, x, y)
        self.input.dispatch(event, x, y)
        self.confirm_button.dispatch(event, x, y)
        if self.input.pin:
            self.reset_button.dispatch(event, x, y)
        else:
            self.cancel_button.dispatch(event, x, y)

    def assign(self, pin):
        if len(pin) > self.maxlength:
            return
        for btn in self.pin_buttons:
            if len(pin) < self.maxlength:
                btn.enable()
            else:
                btn.disable()
        if pin:
            self.reset_button.enable()
            self.cancel_button.disable()
        else:
            self.reset_button.disable()
            self.cancel_button.enable()
        self.input.pin = pin
        self.input.repaint = True

    def on_reset(self):
        self.assign("")

    def on_cancel(self):
        raise ui.Result(CANCELLED)

    def on_confirm(self):
        raise ui.Result(self.input.pin)
コード例 #12
0
class WordSelector(ui.Layout):
    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

    def dispatch(self, event, x, y):
        self.content.dispatch(event, x, y)
        self.w12.dispatch(event, x, y)
        self.w18.dispatch(event, x, y)
        self.w20.dispatch(event, x, y)
        self.w24.dispatch(event, x, y)
        self.w33.dispatch(event, x, y)

    def on_w12(self):
        raise ui.Result(12)

    def on_w18(self):
        raise ui.Result(18)

    def on_w20(self):
        raise ui.Result(20)

    def on_w24(self):
        raise ui.Result(24)

    def on_w33(self):
        raise ui.Result(33)
コード例 #13
0
class InfoConfirm(ui.Layout):
    DEFAULT_CONFIRM = res.load(ui.ICON_CONFIRM)
    DEFAULT_CONFIRM_STYLE = ButtonConfirm
    DEFAULT_CANCEL = res.load(ui.ICON_CANCEL)
    DEFAULT_CANCEL_STYLE = ButtonCancel
    DEFAULT_INFO = res.load(
        ui.ICON_CLICK)  # TODO: this should be (i) icon, not click
    DEFAULT_INFO_STYLE = ButtonDefault

    def __init__(
        self,
        content: ui.Component,
        confirm: ButtonContent = DEFAULT_CONFIRM,
        confirm_style: ButtonStyleType = DEFAULT_CONFIRM_STYLE,
        cancel: ButtonContent = DEFAULT_CANCEL,
        cancel_style: ButtonStyleType = DEFAULT_CANCEL_STYLE,
        info: ButtonContent = DEFAULT_INFO,
        info_style: ButtonStyleType = DEFAULT_INFO_STYLE,
    ) -> None:
        super().__init__()
        self.content = content

        self.confirm = Button(ui.grid(14), confirm, confirm_style)
        self.confirm.on_click = self.on_confirm  # type: ignore

        self.info = Button(ui.grid(13), info, info_style)
        self.info.on_click = self.on_info  # type: ignore

        self.cancel = Button(ui.grid(12), cancel, cancel_style)
        self.cancel.on_click = self.on_cancel  # type: ignore

    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)
        if self.info is not None:
            self.info.dispatch(event, x, y)

    def on_confirm(self) -> None:
        raise ui.Result(CONFIRMED)

    def on_cancel(self) -> None:
        raise ui.Result(CANCELLED)

    def on_info(self) -> None:
        raise ui.Result(INFO)

    if __debug__:

        def read_content(self) -> List[str]:
            return self.content.read_content()

        def create_tasks(self) -> Tuple[loop.Task, ...]:
            return super().create_tasks() + (confirm_signal(), )
コード例 #14
0
class WordSelector(ui.Layout):
    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 dispatch(self, event: int, x: int, y: int) -> None:
        self.content.dispatch(event, x, y)
        self.w12.dispatch(event, x, y)
        self.w18.dispatch(event, x, y)
        self.w20.dispatch(event, x, y)
        self.w24.dispatch(event, x, y)
        self.w33.dispatch(event, x, y)

    def on_w12(self) -> None:
        raise ui.Result(12)

    def on_w18(self) -> None:
        raise ui.Result(18)

    def on_w20(self) -> None:
        raise ui.Result(20)

    def on_w24(self) -> None:
        raise ui.Result(24)

    def on_w33(self) -> None:
        raise ui.Result(33)
コード例 #15
0
ファイル: confirm.py プロジェクト: wakiyamap/trezor-firmware
class InfoConfirm(ui.Layout):
    DEFAULT_CONFIRM = res.load(ui.ICON_CONFIRM)
    DEFAULT_CONFIRM_STYLE = ButtonConfirm
    DEFAULT_CANCEL = res.load(ui.ICON_CANCEL)
    DEFAULT_CANCEL_STYLE = ButtonCancel
    DEFAULT_INFO = res.load(
        ui.ICON_CLICK)  # TODO: this should be (i) icon, not click
    DEFAULT_INFO_STYLE = ButtonDefault

    def __init__(
        self,
        content: ui.Component,
        confirm: ButtonContent = DEFAULT_CONFIRM,
        confirm_style: ButtonStyleType = DEFAULT_CONFIRM_STYLE,
        cancel: ButtonContent = DEFAULT_CANCEL,
        cancel_style: ButtonStyleType = DEFAULT_CANCEL_STYLE,
        info: ButtonContent = DEFAULT_INFO,
        info_style: ButtonStyleType = DEFAULT_INFO_STYLE,
    ) -> None:
        self.content = content

        self.confirm = Button(ui.grid(14), confirm, confirm_style)
        self.confirm.on_click = self.on_confirm  # type: ignore

        self.info = Button(ui.grid(13), info, info_style)
        self.info.on_click = self.on_info

        self.cancel = Button(ui.grid(12), cancel, cancel_style)
        self.cancel.on_click = self.on_cancel  # type: ignore

    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)
        if self.info is not None:
            self.info.dispatch(event, x, y)

    def on_confirm(self) -> None:
        raise ui.Result(CONFIRMED)

    def on_cancel(self) -> None:
        raise ui.Result(CANCELLED)

    def on_info(self) -> None:
        raise ui.Result(INFO)
コード例 #16
0
class WordSelector(ui.Layout):
    def __init__(self, content):
        self.content = content
        self.w12 = Button(ui.grid(6, n_y=4, n_x=3, cells_y=2), "12")
        self.w12.on_click = self.on_w12
        self.w18 = Button(ui.grid(7, n_y=4, n_x=3, cells_y=2), "18")
        self.w18.on_click = self.on_w18
        self.w24 = Button(ui.grid(8, n_y=4, n_x=3, cells_y=2), "24")
        self.w24.on_click = self.on_w24

    def dispatch(self, event, x, y):
        self.content.dispatch(event, x, y)
        self.w12.dispatch(event, x, y)
        self.w18.dispatch(event, x, y)
        self.w24.dispatch(event, x, y)

    def on_w12(self):
        raise ui.Result(12)

    def on_w18(self):
        raise ui.Result(18)

    def on_w24(self):
        raise ui.Result(24)
コード例 #17
0
class PassphraseKeyboard(ui.Layout):
    def __init__(self, prompt, max_length, page=1):
        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
        self.back.disable()

        self.done = Button(ui.grid(14), res.load(ui.ICON_CONFIRM),
                           ButtonConfirm)
        self.done.on_click = self.on_confirm

        self.keys = key_buttons(KEYBOARD_KEYS[self.page], self)
        self.pending_button = None
        self.pending_index = 0

    def dispatch(self, event, x, y):
        if self.input.content:
            self.input.dispatch(event, x, y)
        else:
            self.prompt.dispatch(event, x, y)
        self.back.dispatch(event, x, y)
        self.done.dispatch(event, x, y)
        for btn in self.keys:
            btn.dispatch(event, x, y)

        if event == ui.RENDER:
            render_scrollbar(self.page)

    def on_back_click(self):
        # Backspace was clicked.  If we have any content in the input, let's delete
        # the last character.  Otherwise cancel.
        content = self.input.content
        if content:
            self.edit(content[:-1])
        else:
            self.on_cancel()

    def on_key_click(self, button: KeyButton):
        # Key button was clicked.  If this button is pending, let's cycle the
        # pending character in input.  If not, let's just append the first
        # character.
        button_text = button.get_text_content()
        if self.pending_button is button:
            index = (self.pending_index + 1) % len(button_text)
            prefix = self.input.content[:-1]
        else:
            index = 0
            prefix = self.input.content
        if len(button_text) > 1:
            self.edit(prefix + button_text[index], button, index)
        else:
            self.edit(prefix + button_text[index])

    def on_timeout(self):
        # Timeout occurred, let's just reset the pending marker.
        self.edit(self.input.content)

    def edit(self, content: str, button: Button = None, index: int = 0):
        if len(content) > self.max_length:
            return

        self.pending_button = button
        self.pending_index = index

        # modify the input state
        pending = button is not None
        self.input.edit(content, pending)

        if content:
            self.back.enable()
        else:
            self.back.disable()
            self.prompt.repaint = True

    async def handle_input(self):
        touch = loop.wait(io.TOUCH)
        timeout = loop.sleep(1000 * 1000 * 1)
        spawn_touch = loop.spawn(touch)
        spawn_timeout = loop.spawn(touch, timeout)

        while True:
            if self.pending_button is not None:
                spawn = spawn_timeout
            else:
                spawn = spawn_touch
            result = await spawn

            if touch in spawn.finished:
                event, x, y = result
                self.dispatch(event, x, y)
            else:
                self.on_timeout()

    async def handle_paging(self):
        swipe = await Swipe(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)
        self.back.repaint = True
        self.done.repaint = True
        self.input.repaint = True
        self.prompt.repaint = True

    def on_cancel(self):
        raise ui.Result(CANCELLED)

    def on_confirm(self):
        raise ui.Result(self.input.content)

    def create_tasks(self):
        return self.handle_input(), self.handle_rendering(
        ), self.handle_paging()
コード例 #18
0
class Slip39Keyboard(ui.Layout):
    def __init__(self, prompt: str) -> None:
        super().__init__()
        self.prompt = Prompt(prompt)

        icon_back = res.load(ui.ICON_BACK)
        self.back = Button(ui.grid(0, n_x=3, n_y=4), icon_back, ButtonClear)
        self.back.on_click = self.on_back_click  # type: ignore

        self.input = InputButton(ui.grid(1, n_x=3, n_y=4, cells_x=2), self)
        self.input.on_click = self.on_input_click  # type: ignore

        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: Optional[Button] = None
        self.pending_index = 0
        self.button_sequence = ""
        self.mask = slip39.KEYBOARD_FULL_MASK

    def dispatch(self, event: int, x: int, y: int) -> None:
        for btn in self.keys:
            btn.dispatch(event, x, y)
        if self.input.text:
            self.input.dispatch(event, x, y)
            self.back.dispatch(event, x, y)
        else:
            self.prompt.dispatch(event, x, y)

    def on_back_click(self) -> None:
        # Backspace was clicked, let's delete the last character of input.
        self.button_sequence = self.button_sequence[:-1]
        self.edit()

    def on_input_click(self) -> None:
        # Input button was clicked. If the content matches the suggested word,
        # let's confirm it, otherwise just auto-complete.
        result = self.input.word
        if self.is_input_final():
            self.button_sequence = ""
            self.edit()
            self.on_confirm(result)

    def on_key_click(self, btn: KeyButton) -> None:
        # Key button was clicked.  If this button is pending, let's cycle the
        # pending character in input.  If not, let's just append the first
        # character.
        if self.pending_button is btn:
            index = (self.pending_index + 1) % len(btn.text)
        else:
            index = 0
            self.button_sequence += str(btn.index)
        self.edit(btn, index)

    def on_timeout(self) -> None:
        # Timeout occurred. Let's redraw to draw asterisks.
        self.edit()

    def on_confirm(self, word: str) -> None:
        # Word was confirmed by the user.
        raise ui.Result(word)

    def edit(self, button: Button = None, index: int = 0) -> None:
        self.pending_button = button
        self.pending_index = index

        # find the completions
        word = ""
        self.mask = slip39.word_completion_mask(self.button_sequence)
        if self.is_input_final():
            word = slip39.button_sequence_to_word(self.button_sequence)

        # modify the input state
        self.input.edit(
            self.button_sequence, word, self.pending_button, self.pending_index
        )

        # enable or disable key buttons
        for btn in self.keys:
            if self.is_input_final():
                btn.disable()
            elif btn is button or self.check_mask(btn.index):
                btn.enable()
            else:
                btn.disable()

        # invalidate the prompt if we display it next frame
        if not self.input.text:
            self.prompt.repaint = True

    def is_input_final(self) -> bool:
        # returns True if mask has exactly one bit set to 1 or is 0
        return not (self.mask & (self.mask - 1))

    def check_mask(self, index: int) -> bool:
        return bool((1 << (index - 1)) & self.mask)

    async def handle_input(self) -> None:
        touch = loop.wait(io.TOUCH)
        timeout = loop.sleep(1000)
        race_touch = loop.race(touch)
        race_timeout = loop.race(touch, timeout)

        while True:
            if self.pending_button is not None:
                race = race_timeout
            else:
                race = race_touch
            result = await race

            if touch in race.finished:
                event, x, y = result
                workflow.idle_timer.touch()
                self.dispatch(event, x, y)
            else:
                self.on_timeout()

    if __debug__:

        def create_tasks(self) -> Tuple[loop.Task, ...]:
            from apps.debug import input_signal

            return super().create_tasks() + (input_signal(),)
コード例 #19
0
class Bip39Keyboard(ui.Layout):
    def __init__(self, prompt: str) -> None:
        self.prompt = Prompt(prompt)

        icon_back = res.load(ui.ICON_BACK)
        self.back = Button(ui.grid(0, n_x=3, n_y=4), icon_back, ButtonClear)
        self.back.on_click = self.on_back_click  # type: ignore

        self.input = InputButton(ui.grid(1, n_x=3, n_y=4, cells_x=2), "", "")
        self.input.on_click = self.on_input_click  # type: ignore

        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  # type: Optional[Button]
        self.pending_index = 0

    def dispatch(self, event: int, x: int, y: int) -> None:
        for btn in self.keys:
            btn.dispatch(event, x, y)
        if self.input.text:
            self.input.dispatch(event, x, y)
            self.back.dispatch(event, x, y)
        else:
            self.prompt.dispatch(event, x, y)

    def on_back_click(self) -> None:
        # Backspace was clicked, let's delete the last character of input.
        self.edit(self.input.text[:-1])

    def on_input_click(self) -> None:
        # Input button was clicked.  If the content matches the suggested word,
        # let's confirm it, otherwise just auto-complete.
        text = self.input.text
        word = self.input.word
        if word and word == text:
            self.edit("")
            self.on_confirm(word)
        else:
            self.edit(word)

    def on_key_click(self, btn: Button) -> None:
        # Key button was clicked.  If this button is pending, let's cycle the
        # pending character in input.  If not, let's just append the first
        # character.
        if self.pending_button is btn:
            index = (self.pending_index + 1) % len(btn.text)
            text = self.input.text[:-1] + btn.text[index]
        else:
            index = 0
            text = self.input.text + btn.text[0]
        self.edit(text, btn, index)

    def on_timeout(self) -> None:
        # Timeout occurred.  If we can auto-complete current input, let's just
        # reset the pending marker.  If not, input is invalid, let's backspace
        # the last character.
        if self.input.word:
            self.edit(self.input.text)
        else:
            self.edit(self.input.text[:-1])

    def on_confirm(self, word: str) -> None:
        # Word was confirmed by the user.
        raise ui.Result(word)

    def edit(self, text: str, button: Button = None, index: int = 0) -> None:
        self.pending_button = button
        self.pending_index = index

        # find the completions
        pending = button is not None
        word = bip39.complete_word(text) or ""
        mask = bip39.word_completion_mask(text)

        # modify the input state
        self.input.edit(text, word, pending)

        # enable or disable key buttons
        for btn in self.keys:
            if btn is button or compute_mask(btn.text) & mask:
                btn.enable()
            else:
                btn.disable()

        # invalidate the prompt if we display it next frame
        if not self.input.text:
            self.prompt.repaint = True

    async def handle_input(self) -> None:
        touch = loop.wait(io.TOUCH)
        timeout = loop.sleep(1000 * 1000 * 1)
        race_touch = loop.race(touch)
        race_timeout = loop.race(touch, timeout)

        while True:
            if self.pending_button is not None:
                race = race_timeout
            else:
                race = race_touch
            result = await race

            if touch in race.finished:
                event, x, y = result
                self.dispatch(event, x, y)
            else:
                self.on_timeout()
コード例 #20
0
class PassphraseKeyboard(ui.Layout):
    def __init__(self, prompt: str, max_length: int, page: int = 1) -> None:
        super().__init__()
        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: Optional[KeyButton] = None
        self.pending_index = 0

    def dispatch(self, event: int, x: int, y: int) -> None:
        if self.input.text:
            self.input.dispatch(event, x, y)
        else:
            self.prompt.dispatch(event, x, y)
        self.back.dispatch(event, x, y)
        self.done.dispatch(event, x, y)
        for btn in self.keys:
            btn.dispatch(event, x, y)

        if event == ui.RENDER:
            render_scrollbar(self.page)

    def on_back_click(self) -> None:
        # Backspace was clicked.  If we have any content in the input, let's delete
        # the last character.  Otherwise cancel.
        text = self.input.text
        if text:
            self.edit(text[:-1])
        else:
            self.on_cancel()

    def on_key_click(self, button: KeyButton) -> None:
        # Key button was clicked.  If this button is pending, let's cycle the
        # pending character in input.  If not, let's just append the first
        # character.
        button_text = button.get_text_content()
        if self.pending_button is button:
            index = (self.pending_index + 1) % len(button_text)
            prefix = self.input.text[:-1]
        else:
            index = 0
            prefix = self.input.text
        if len(button_text) > 1:
            self.edit(prefix + button_text[index], button, index)
        else:
            self.edit(prefix + button_text[index])

    def on_timeout(self) -> None:
        # Timeout occurred, let's just reset the pending marker.
        self.edit(self.input.text)

    def edit(self,
             text: str,
             button: KeyButton = None,
             index: int = 0) -> None:
        if len(text) > self.max_length:
            return

        self.pending_button = button
        self.pending_index = index

        # modify the input state
        pending = button is not None
        self.input.edit(text, pending)

        if text:
            self.back.enable()
        else:
            self.back.disable()
            self.prompt.repaint = True

    async def handle_input(self) -> None:
        touch = loop.wait(io.TOUCH)
        timeout = loop.sleep(1000)
        race_touch = loop.race(touch)
        race_timeout = loop.race(touch, timeout)

        while True:
            if self.pending_button is not None:
                race = race_timeout
            else:
                race = race_touch
            result = await race

            if touch in race.finished:
                event, x, y = result
                workflow.idle_timer.touch()
                self.dispatch(event, x, y)
            else:
                self.on_timeout()

    async def handle_paging(self) -> None:
        swipe = await Swipe(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)
        self.back.repaint = True
        self.done.repaint = True
        self.input.repaint = True
        self.prompt.repaint = True

    def on_cancel(self) -> None:
        raise ui.Result(CANCELLED)

    def on_confirm(self) -> None:
        raise ui.Result(self.input.text)

    def create_tasks(self) -> Tuple[loop.Task, ...]:
        tasks: Tuple[loop.Task, ...] = (
            self.handle_input(),
            self.handle_rendering(),
            self.handle_paging(),
        )

        if __debug__:
            from apps.debug import input_signal

            return tasks + (input_signal(), )
        else:
            return tasks
コード例 #21
0
ファイル: pin.py プロジェクト: vhud/trezor-firmware
class PinDialog(ui.Layout):
    def __init__(
        self,
        prompt: str,
        subprompt: Optional[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_CANCEL if config.is_unlocked() else 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 dispatch(self, event: int, x: int, y: int) -> None:
        self.input.dispatch(event, x, y)
        if self.input.pin:
            self.reset_button.dispatch(event, x, y)
        else:
            self.cancel_button.dispatch(event, x, y)
        self.confirm_button.dispatch(event, x, y)
        for btn in self.pin_buttons:
            btn.dispatch(event, x, y)

    def assign(self, pin: str) -> None:
        if len(pin) > self.maxlength:
            return
        for btn in self.pin_buttons:
            if len(pin) < self.maxlength:
                btn.enable()
            else:
                btn.disable()
        if pin:
            self.confirm_button.enable()
            self.reset_button.enable()
            self.cancel_button.disable()
        else:
            self.confirm_button.disable()
            self.reset_button.disable()
            self.cancel_button.enable()
        self.input.pin = pin
        self.input.repaint = True

    def on_reset(self) -> None:
        self.assign("")

    def on_cancel(self) -> None:
        raise ui.Result(CANCELLED)

    def on_confirm(self) -> None:
        if self.input.pin:
            raise ui.Result(self.input.pin)

    if __debug__:

        def create_tasks(self) -> Tuple[loop.Task, ...]:
            from apps.debug import input_signal

            return super().create_tasks() + (input_signal(), )
コード例 #22
0
class Slip39Keyboard(ui.Layout):
    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 dispatch(self, event: int, x: int, y: int):
        for btn in self.keys:
            btn.dispatch(event, x, y)
        if self.input.content:
            self.input.dispatch(event, x, y)
            self.back.dispatch(event, x, y)
        else:
            self.prompt.dispatch(event, x, y)

    def on_back_click(self):
        # Backspace was clicked, let's delete the last character of input.
        self.button_sequence = self.button_sequence[:-1]
        self.edit()

    def on_input_click(self):
        # Input button was clicked. If the content matches the suggested word,
        # let's confirm it, otherwise just auto-complete.
        result = self.input.word
        if _is_final(self.input.content):
            self.button_sequence = ""
            self.edit()
            self.on_confirm(result)

    def on_key_click(self, btn: KeyButton):
        # Key button was clicked.  If this button is pending, let's cycle the
        # pending character in input.  If not, let's just append the first
        # character.
        if self.pending_button is btn:
            index = (self.pending_index + 1) % len(btn.content)
        else:
            index = 0
            self.button_sequence += str(btn.index)
        self.edit(btn, index)

    def on_timeout(self):
        # Timeout occurred. Let's redraw to draw asterisks.
        self.edit()

    def on_confirm(self, word):
        # Word was confirmed by the user.
        raise ui.Result(word)

    def edit(self, button: KeyButton = None, index: int = 0):
        self.pending_button = button
        self.pending_index = index

        # find the completions
        mask = 0
        word = ""
        if _is_final(self.button_sequence):
            word = slip39.button_sequence_to_word(self.button_sequence)
        else:
            mask = slip39.compute_mask(self.button_sequence)

        # modify the input state
        self.input.edit(self.button_sequence, word, self.pending_button,
                        self.pending_index)

        # enable or disable key buttons
        for btn in self.keys:
            if (not _is_final(self.button_sequence)
                    and btn is button) or check_mask(mask, btn.index):
                btn.enable()
            else:
                btn.disable()

        # invalidate the prompt if we display it next frame
        if not self.input.content:
            self.prompt.repaint = True

    async def handle_input(self):
        touch = loop.wait(io.TOUCH)
        timeout = loop.sleep(1000 * 1000 * 1)
        spawn_touch = loop.spawn(touch)
        spawn_timeout = loop.spawn(touch, timeout)

        while True:
            if self.pending_button is not None:
                spawn = spawn_timeout
            else:
                spawn = spawn_touch
            result = await spawn

            if touch in spawn.finished:
                event, x, y = result
                self.dispatch(event, x, y)
            else:
                self.on_timeout()