mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-15 18:00:59 +00:00
commit
1a0233af9d
@ -33,13 +33,13 @@
|
|||||||
#define FONT_SIZE 20
|
#define FONT_SIZE 20
|
||||||
|
|
||||||
#ifdef TREZOR_FONT_MONO_ENABLE
|
#ifdef TREZOR_FONT_MONO_ENABLE
|
||||||
#define FONT_MONO 0
|
#define FONT_MONO 1
|
||||||
#endif
|
#endif
|
||||||
#ifdef TREZOR_FONT_NORMAL_ENABLE
|
#ifdef TREZOR_FONT_NORMAL_ENABLE
|
||||||
#define FONT_NORMAL 1
|
#define FONT_NORMAL 2
|
||||||
#endif
|
#endif
|
||||||
#ifdef TREZOR_FONT_BOLD_ENABLE
|
#ifdef TREZOR_FONT_BOLD_ENABLE
|
||||||
#define FONT_BOLD 2
|
#define FONT_BOLD 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define AVATAR_IMAGE_SIZE 144
|
#define AVATAR_IMAGE_SIZE 144
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
#define FONT_PY_TO_C(f) (-(f))
|
||||||
|
#define FONT_C_TO_PY(f) (-(f))
|
||||||
|
|
||||||
/// class Display:
|
/// class Display:
|
||||||
/// '''
|
/// '''
|
||||||
/// Provide access to device display.
|
/// Provide access to device display.
|
||||||
@ -194,17 +197,19 @@ STATIC mp_obj_t mod_trezorui_Display_print(mp_obj_t self, mp_obj_t text) {
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_print_obj, mod_trezorui_Display_print);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_print_obj, mod_trezorui_Display_print);
|
||||||
|
|
||||||
/// def text(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> None:
|
/// def text(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> int:
|
||||||
/// '''
|
/// '''
|
||||||
/// Renders left-aligned text at position (x,y) where x is left position and y is baseline.
|
/// Renders left-aligned text at position (x,y) where x is left position and y is baseline.
|
||||||
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
||||||
|
/// Fills at least minwidth pixels with bgcolor.
|
||||||
|
/// Returns width of rendered text in pixels.
|
||||||
/// '''
|
/// '''
|
||||||
STATIC mp_obj_t mod_trezorui_Display_text(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t mod_trezorui_Display_text(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_int_t x = mp_obj_get_int(args[1]);
|
mp_int_t x = mp_obj_get_int(args[1]);
|
||||||
mp_int_t y = mp_obj_get_int(args[2]);
|
mp_int_t y = mp_obj_get_int(args[2]);
|
||||||
mp_buffer_info_t text;
|
mp_buffer_info_t text;
|
||||||
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
|
||||||
mp_int_t font = mp_obj_get_int(args[4]);
|
mp_int_t font = FONT_PY_TO_C(mp_obj_get_int(args[4]));
|
||||||
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
||||||
mp_int_t bgcolor = mp_obj_get_int(args[6]);
|
mp_int_t bgcolor = mp_obj_get_int(args[6]);
|
||||||
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
|
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
|
||||||
@ -214,21 +219,23 @@ STATIC mp_obj_t mod_trezorui_Display_text(size_t n_args, const mp_obj_t *args) {
|
|||||||
display_bar(x, y - 18, barwidth, 23, bgcolor);
|
display_bar(x, y - 18, barwidth, 23, bgcolor);
|
||||||
// prefill end
|
// prefill end
|
||||||
display_text(x, y, text.buf, text.len, font, fgcolor, bgcolor);
|
display_text(x, y, text.buf, text.len, font, fgcolor, bgcolor);
|
||||||
return mp_const_none;
|
return mp_obj_new_int(w);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_obj, 7, 8, mod_trezorui_Display_text);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_obj, 7, 8, mod_trezorui_Display_text);
|
||||||
|
|
||||||
/// def text_center(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> None:
|
/// def text_center(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> int:
|
||||||
/// '''
|
/// '''
|
||||||
/// Renders text centered at position (x,y) where x is text center and y is baseline.
|
/// Renders text centered at position (x,y) where x is text center and y is baseline.
|
||||||
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
||||||
|
/// Fills at least minwidth pixels with bgcolor.
|
||||||
|
/// Returns width of rendered text in pixels.
|
||||||
/// '''
|
/// '''
|
||||||
STATIC mp_obj_t mod_trezorui_Display_text_center(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t mod_trezorui_Display_text_center(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_int_t x = mp_obj_get_int(args[1]);
|
mp_int_t x = mp_obj_get_int(args[1]);
|
||||||
mp_int_t y = mp_obj_get_int(args[2]);
|
mp_int_t y = mp_obj_get_int(args[2]);
|
||||||
mp_buffer_info_t text;
|
mp_buffer_info_t text;
|
||||||
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
|
||||||
mp_int_t font = mp_obj_get_int(args[4]);
|
mp_int_t font = FONT_PY_TO_C(mp_obj_get_int(args[4]));
|
||||||
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
||||||
mp_int_t bgcolor = mp_obj_get_int(args[6]);
|
mp_int_t bgcolor = mp_obj_get_int(args[6]);
|
||||||
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
|
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
|
||||||
@ -238,21 +245,23 @@ STATIC mp_obj_t mod_trezorui_Display_text_center(size_t n_args, const mp_obj_t *
|
|||||||
display_bar(x - barwidth / 2, y - 18, barwidth, 23, bgcolor);
|
display_bar(x - barwidth / 2, y - 18, barwidth, 23, bgcolor);
|
||||||
// prefill end
|
// prefill end
|
||||||
display_text_center(x, y, text.buf, text.len, font, fgcolor, bgcolor);
|
display_text_center(x, y, text.buf, text.len, font, fgcolor, bgcolor);
|
||||||
return mp_const_none;
|
return mp_obj_new_int(w);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_center_obj, 7, 8, mod_trezorui_Display_text_center);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_center_obj, 7, 8, mod_trezorui_Display_text_center);
|
||||||
|
|
||||||
/// def text_right(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> None:
|
/// def text_right(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> int:
|
||||||
/// '''
|
/// '''
|
||||||
/// Renders right-aligned text at position (x,y) where x is right position and y is baseline.
|
/// Renders right-aligned text at position (x,y) where x is right position and y is baseline.
|
||||||
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
||||||
|
/// Fills at least minwidth pixels with bgcolor.
|
||||||
|
/// Returns width of rendered text in pixels.
|
||||||
/// '''
|
/// '''
|
||||||
STATIC mp_obj_t mod_trezorui_Display_text_right(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t mod_trezorui_Display_text_right(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_int_t x = mp_obj_get_int(args[1]);
|
mp_int_t x = mp_obj_get_int(args[1]);
|
||||||
mp_int_t y = mp_obj_get_int(args[2]);
|
mp_int_t y = mp_obj_get_int(args[2]);
|
||||||
mp_buffer_info_t text;
|
mp_buffer_info_t text;
|
||||||
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
|
||||||
mp_int_t font = mp_obj_get_int(args[4]);
|
mp_int_t font = FONT_PY_TO_C(mp_obj_get_int(args[4]));
|
||||||
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
mp_int_t fgcolor = mp_obj_get_int(args[5]);
|
||||||
mp_int_t bgcolor = mp_obj_get_int(args[6]);
|
mp_int_t bgcolor = mp_obj_get_int(args[6]);
|
||||||
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
|
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
|
||||||
@ -262,7 +271,7 @@ STATIC mp_obj_t mod_trezorui_Display_text_right(size_t n_args, const mp_obj_t *a
|
|||||||
display_bar(x - barwidth, y - 18, barwidth, 23, bgcolor);
|
display_bar(x - barwidth, y - 18, barwidth, 23, bgcolor);
|
||||||
// prefill end
|
// prefill end
|
||||||
display_text_right(x, y, text.buf, text.len, font, fgcolor, bgcolor);
|
display_text_right(x, y, text.buf, text.len, font, fgcolor, bgcolor);
|
||||||
return mp_const_none;
|
return mp_obj_new_int(w);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_right_obj, 7, 8, mod_trezorui_Display_text_right);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_right_obj, 7, 8, mod_trezorui_Display_text_right);
|
||||||
|
|
||||||
@ -273,9 +282,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_right_obj,
|
|||||||
STATIC mp_obj_t mod_trezorui_Display_text_width(mp_obj_t self, mp_obj_t text, mp_obj_t font) {
|
STATIC mp_obj_t mod_trezorui_Display_text_width(mp_obj_t self, mp_obj_t text, mp_obj_t font) {
|
||||||
mp_buffer_info_t txt;
|
mp_buffer_info_t txt;
|
||||||
mp_get_buffer_raise(text, &txt, MP_BUFFER_READ);
|
mp_get_buffer_raise(text, &txt, MP_BUFFER_READ);
|
||||||
mp_int_t f = mp_obj_get_int(font);
|
mp_int_t f = FONT_PY_TO_C(mp_obj_get_int(font));
|
||||||
int w = display_text_width(txt.buf, txt.len, f);
|
int w = display_text_width(txt.buf, txt.len, f);
|
||||||
return MP_OBJ_NEW_SMALL_INT(w);
|
return mp_obj_new_int(w);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorui_Display_text_width_obj, mod_trezorui_Display_text_width);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorui_Display_text_width_obj, mod_trezorui_Display_text_width);
|
||||||
|
|
||||||
@ -450,9 +459,9 @@ STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = {
|
|||||||
{ MP_ROM_QSTR(MP_QSTR_WIDTH), MP_OBJ_NEW_SMALL_INT(DISPLAY_RESX) },
|
{ MP_ROM_QSTR(MP_QSTR_WIDTH), MP_OBJ_NEW_SMALL_INT(DISPLAY_RESX) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_OBJ_NEW_SMALL_INT(DISPLAY_RESY) },
|
{ MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_OBJ_NEW_SMALL_INT(DISPLAY_RESY) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_FONT_SIZE), MP_OBJ_NEW_SMALL_INT(FONT_SIZE) },
|
{ MP_ROM_QSTR(MP_QSTR_FONT_SIZE), MP_OBJ_NEW_SMALL_INT(FONT_SIZE) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_FONT_MONO), MP_OBJ_NEW_SMALL_INT(FONT_MONO) },
|
{ MP_ROM_QSTR(MP_QSTR_FONT_MONO), MP_OBJ_NEW_SMALL_INT(FONT_C_TO_PY(FONT_MONO)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_FONT_NORMAL), MP_OBJ_NEW_SMALL_INT(FONT_NORMAL) },
|
{ MP_ROM_QSTR(MP_QSTR_FONT_NORMAL), MP_OBJ_NEW_SMALL_INT(FONT_C_TO_PY(FONT_NORMAL)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_FONT_BOLD), MP_OBJ_NEW_SMALL_INT(FONT_BOLD) },
|
{ MP_ROM_QSTR(MP_QSTR_FONT_BOLD), MP_OBJ_NEW_SMALL_INT(FONT_C_TO_PY(FONT_BOLD)) },
|
||||||
};
|
};
|
||||||
STATIC MP_DEFINE_CONST_DICT(mod_trezorui_Display_locals_dict, mod_trezorui_Display_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(mod_trezorui_Display_locals_dict, mod_trezorui_Display_locals_dict_table);
|
||||||
|
|
||||||
|
@ -4,36 +4,111 @@ from trezor import ui
|
|||||||
TEXT_HEADER_HEIGHT = const(48)
|
TEXT_HEADER_HEIGHT = const(48)
|
||||||
TEXT_LINE_HEIGHT = const(26)
|
TEXT_LINE_HEIGHT = const(26)
|
||||||
TEXT_MARGIN_LEFT = const(14)
|
TEXT_MARGIN_LEFT = const(14)
|
||||||
|
TEXT_MAX_LINES = const(4)
|
||||||
|
|
||||||
|
# needs to be different from all colors and font ids
|
||||||
|
BR = const(-256)
|
||||||
|
|
||||||
|
|
||||||
|
def render_words(words: list, new_lines: bool, max_lines: int) -> None:
|
||||||
|
# initial rendering state
|
||||||
|
font = ui.NORMAL
|
||||||
|
fg = ui.FG
|
||||||
|
bg = ui.BG
|
||||||
|
offset_x = TEXT_MARGIN_LEFT
|
||||||
|
offset_y = TEXT_HEADER_HEIGHT + TEXT_LINE_HEIGHT
|
||||||
|
OFFSET_X_MAX = ui.WIDTH
|
||||||
|
OFFSET_Y_MAX = TEXT_HEADER_HEIGHT + TEXT_LINE_HEIGHT * max_lines
|
||||||
|
|
||||||
|
# sizes of common glyphs
|
||||||
|
SPACE = ui.display.text_width(' ', font)
|
||||||
|
DASH = ui.display.text_width('-', ui.BOLD)
|
||||||
|
ELLIPSIS = ui.display.text_width('...', ui.BOLD)
|
||||||
|
|
||||||
|
for word in words:
|
||||||
|
if isinstance(word, int):
|
||||||
|
if word == BR:
|
||||||
|
# line break
|
||||||
|
if not offset_y < OFFSET_Y_MAX:
|
||||||
|
ui.display.text(offset_x, offset_y, '...', ui.BOLD, ui.GREY, bg)
|
||||||
|
return
|
||||||
|
offset_x = TEXT_MARGIN_LEFT
|
||||||
|
offset_y += TEXT_LINE_HEIGHT
|
||||||
|
elif word == ui.NORMAL or word == ui.BOLD or word == ui.MONO:
|
||||||
|
# change of font style
|
||||||
|
font = word
|
||||||
|
else:
|
||||||
|
# change of foreground color
|
||||||
|
fg = word
|
||||||
|
continue
|
||||||
|
|
||||||
|
width = ui.display.text_width(word, font)
|
||||||
|
|
||||||
|
while offset_x + width + SPACE + ELLIPSIS > OFFSET_X_MAX:
|
||||||
|
space_for_another_line = offset_y < OFFSET_Y_MAX
|
||||||
|
word_fits_in_one_line = width < (OFFSET_X_MAX - TEXT_MARGIN_LEFT)
|
||||||
|
if space_for_another_line and word_fits_in_one_line:
|
||||||
|
# line break
|
||||||
|
offset_x = TEXT_MARGIN_LEFT
|
||||||
|
offset_y += TEXT_LINE_HEIGHT
|
||||||
|
break
|
||||||
|
# word split
|
||||||
|
if space_for_another_line:
|
||||||
|
split = '-'
|
||||||
|
splitw = DASH
|
||||||
|
else:
|
||||||
|
split = '...'
|
||||||
|
splitw = ELLIPSIS
|
||||||
|
# find span that fits
|
||||||
|
for index in range(len(word) - 1, 0, -1):
|
||||||
|
letter = word[index]
|
||||||
|
width -= ui.display.text_width(letter, font)
|
||||||
|
if offset_x + width + splitw < OFFSET_X_MAX:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
index = 0
|
||||||
|
span = word[:index]
|
||||||
|
# render word span
|
||||||
|
ui.display.text(offset_x, offset_y, span, font, fg, bg)
|
||||||
|
ui.display.text(offset_x + width, offset_y, split, ui.BOLD, ui.GREY, bg)
|
||||||
|
# line break
|
||||||
|
if not space_for_another_line:
|
||||||
|
return
|
||||||
|
offset_x = TEXT_MARGIN_LEFT
|
||||||
|
offset_y += TEXT_LINE_HEIGHT
|
||||||
|
# continue with the rest
|
||||||
|
word = word[index:]
|
||||||
|
width = ui.display.text_width(word, font)
|
||||||
|
|
||||||
|
# render word
|
||||||
|
ui.display.text(offset_x, offset_y, word, font, fg, bg)
|
||||||
|
offset_x += width
|
||||||
|
offset_x += SPACE
|
||||||
|
|
||||||
|
# line break
|
||||||
|
if new_lines:
|
||||||
|
if not offset_y < OFFSET_Y_MAX:
|
||||||
|
ui.display.text(offset_x, offset_y, '...', ui.BOLD, ui.GREY, bg)
|
||||||
|
return
|
||||||
|
offset_x = TEXT_MARGIN_LEFT
|
||||||
|
offset_y += TEXT_LINE_HEIGHT
|
||||||
|
|
||||||
|
|
||||||
class Text(ui.Widget):
|
class Text(ui.Widget):
|
||||||
|
def __init__(self,
|
||||||
def __init__(self, header_text, header_icon, *content, icon_color=ui.ORANGE_ICON, max_lines=None):
|
header_text: str,
|
||||||
|
header_icon: bytes,
|
||||||
|
*content: list,
|
||||||
|
new_lines: bool = True,
|
||||||
|
max_lines: int = TEXT_MAX_LINES,
|
||||||
|
icon_color: int = ui.ORANGE_ICON):
|
||||||
self.header_text = header_text
|
self.header_text = header_text
|
||||||
self.header_icon = header_icon
|
self.header_icon = header_icon
|
||||||
self.icon_color = icon_color
|
|
||||||
self.content = content
|
self.content = content
|
||||||
|
self.new_lines = new_lines
|
||||||
self.max_lines = max_lines
|
self.max_lines = max_lines
|
||||||
|
self.icon_color = icon_color
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
offset_x = TEXT_MARGIN_LEFT
|
|
||||||
offset_y = TEXT_LINE_HEIGHT + TEXT_HEADER_HEIGHT
|
|
||||||
style = ui.NORMAL
|
|
||||||
fg = ui.FG
|
|
||||||
bg = ui.BG
|
|
||||||
ui.header(self.header_text, self.header_icon, ui.TITLE_GREY, ui.BG, self.icon_color)
|
ui.header(self.header_text, self.header_icon, ui.TITLE_GREY, ui.BG, self.icon_color)
|
||||||
|
render_words(self.content, self.new_lines, self.max_lines)
|
||||||
line = 1
|
|
||||||
for item in self.content:
|
|
||||||
if isinstance(item, str):
|
|
||||||
if self.max_lines is not None and line >= self.max_lines:
|
|
||||||
ui.display.text(offset_x, offset_y, item + '...', style, fg, bg)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
ui.display.text(offset_x, offset_y, item, style, fg, bg)
|
|
||||||
offset_y += TEXT_LINE_HEIGHT
|
|
||||||
line += 1
|
|
||||||
elif item == ui.MONO or item == ui.NORMAL or item == ui.BOLD:
|
|
||||||
style = item
|
|
||||||
else:
|
|
||||||
fg = item
|
|
||||||
|
Loading…
Reference in New Issue
Block a user