You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/src/trezor/ui/components/tt/swipe.py

115 lines
3.9 KiB

from micropython import const
from typing import Generator
from trezor import io, loop, ui
from trezor.ui.components.common import SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT, SWIPE_UP
SWIPE_VERTICAL = SWIPE_UP | SWIPE_DOWN
SWIPE_HORIZONTAL = SWIPE_LEFT | SWIPE_RIGHT
SWIPE_ALL = SWIPE_VERTICAL | SWIPE_HORIZONTAL
_SWIPE_DISTANCE = const(120)
_SWIPE_TRESHOLD = const(30)
class Swipe(ui.Component):
def __init__(
self, directions: int = SWIPE_ALL, area: ui.Area | None = None
) -> None:
super().__init__()
if area is None:
area = (0, 0, ui.WIDTH, ui.HEIGHT)
self.area = area
self.directions = directions
self.started = False
self.start_x = 0
self.start_y = 0
self.light_origin = ui.BACKLIGHT_NORMAL
self.light_target = ui.BACKLIGHT_NONE
def on_touch_start(self, x: int, y: int) -> None:
if ui.in_area(self.area, x, y):
self.start_x = x
self.start_y = y
self.light_origin = ui.BACKLIGHT_NORMAL
self.started = True
def on_touch_move(self, x: int, y: int) -> None:
if not self.started:
return # not started in our area
dirs = self.directions
pdx = x - self.start_x
pdy = y - self.start_y
pdxa = abs(pdx)
pdya = abs(pdy)
if pdxa > pdya and dirs & SWIPE_HORIZONTAL:
# horizontal direction
if (pdx > 0 and dirs & SWIPE_RIGHT) or (pdx < 0 and dirs & SWIPE_LEFT):
ui.display.backlight(
ui.lerpi(
self.light_origin,
self.light_target,
min(pdxa / _SWIPE_DISTANCE, 1),
)
)
elif pdxa < pdya and dirs & SWIPE_VERTICAL:
# vertical direction
if (pdy > 0 and dirs & SWIPE_DOWN) or (pdy < 0 and dirs & SWIPE_UP):
ui.display.backlight(
ui.lerpi(
self.light_origin,
self.light_target,
min(pdya / _SWIPE_DISTANCE, 1),
)
)
def on_touch_end(self, x: int, y: int) -> None:
if not self.started:
return # not started in our area
dirs = self.directions
pdx = x - self.start_x
pdy = y - self.start_y
pdxa = abs(pdx)
pdya = abs(pdy)
if pdxa > pdya and dirs & SWIPE_HORIZONTAL:
# horizontal direction
ratio = min(pdxa / _SWIPE_DISTANCE, 1)
if ratio * 100 >= _SWIPE_TRESHOLD:
if pdx > 0 and dirs & SWIPE_RIGHT:
self.on_swipe(SWIPE_RIGHT)
return
elif pdx < 0 and dirs & SWIPE_LEFT:
self.on_swipe(SWIPE_LEFT)
return
elif pdxa < pdya and dirs & SWIPE_VERTICAL:
# vertical direction
ratio = min(pdya / _SWIPE_DISTANCE, 1)
if ratio * 100 >= _SWIPE_TRESHOLD:
if pdy > 0 and dirs & SWIPE_DOWN:
self.on_swipe(SWIPE_DOWN)
return
elif pdy < 0 and dirs & SWIPE_UP:
self.on_swipe(SWIPE_UP)
return
# no swipe detected, reset the state
ui.display.backlight(self.light_origin)
self.started = False
def on_swipe(self, swipe: int) -> None:
raise ui.Result(swipe)
def __await__(self) -> Generator:
return self.__iter__() # type: ignore [Expression of type "Task" cannot be assigned to return type "Generator[Unknown, Unknown, Unknown]"]
def __iter__(self) -> loop.Task: # type: ignore [awaitable-is-generator]
try:
touch = loop.wait(io.TOUCH)
while True:
event, x, y = yield touch
self.dispatch(event, x, y)
except ui.Result as result:
return result.value