1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-09 23:11:10 +00:00

refactor(core/rust/ui): text theme struct

[no changelog]
This commit is contained in:
Martin Milata 2022-08-23 22:18:00 +02:00
parent 20ac679651
commit 005e4203a7
14 changed files with 647 additions and 648 deletions

View File

@ -12,24 +12,36 @@ use crate::ui::{
}; };
use super::layout::{ use super::layout::{
DefaultTextTheme, LayoutFit, LayoutSink, LineBreaking, Op, PageBreaking, TextLayout, LayoutFit, LayoutSink, LineBreaking, Op, PageBreaking, TextLayout, TextRenderer, TextStyle,
TextRenderer,
}; };
pub const MAX_ARGUMENTS: usize = 6; pub const MAX_ARGUMENTS: usize = 6;
pub struct FormattedText<F, T> { pub struct FormattedText<F, T> {
layout: TextLayout, layout: TextLayout,
fonts: FormattedFonts,
format: F, format: F,
args: LinearMap<&'static str, T, MAX_ARGUMENTS>, args: LinearMap<&'static str, T, MAX_ARGUMENTS>,
char_offset: usize, char_offset: usize,
} }
pub struct FormattedFonts {
/// Font used to format `{normal}`.
pub normal: Font,
/// Font used to format `{medium}`.
pub medium: Font,
/// Font used to format `{bold}`.
pub bold: Font,
/// Font used to format `{mono}`.
pub mono: Font,
}
impl<F, T> FormattedText<F, T> { impl<F, T> FormattedText<F, T> {
pub fn new<D: DefaultTextTheme>(format: F) -> Self { pub fn new(style: TextStyle, fonts: FormattedFonts, format: F) -> Self {
Self { Self {
format, format,
layout: TextLayout::new::<D>(), fonts,
layout: TextLayout::new(style),
args: LinearMap::new(), args: LinearMap::new(),
char_offset: 0, char_offset: 0,
} }
@ -49,22 +61,22 @@ impl<F, T> FormattedText<F, T> {
} }
pub fn with_text_font(mut self, text_font: Font) -> Self { pub fn with_text_font(mut self, text_font: Font) -> Self {
self.layout.text_font = text_font; self.layout.style.text_font = text_font;
self self
} }
pub fn with_text_color(mut self, text_color: Color) -> Self { pub fn with_text_color(mut self, text_color: Color) -> Self {
self.layout.text_color = text_color; self.layout.style.text_color = text_color;
self self
} }
pub fn with_line_breaking(mut self, line_breaking: LineBreaking) -> Self { pub fn with_line_breaking(mut self, line_breaking: LineBreaking) -> Self {
self.layout.line_breaking = line_breaking; self.layout.style.line_breaking = line_breaking;
self self
} }
pub fn with_page_breaking(mut self, page_breaking: PageBreaking) -> Self { pub fn with_page_breaking(mut self, page_breaking: PageBreaking) -> Self {
self.layout.page_breaking = page_breaking; self.layout.style.page_breaking = page_breaking;
self self
} }
@ -91,10 +103,10 @@ where
let mut ops = Op::skip_n_text_bytes( let mut ops = Op::skip_n_text_bytes(
Tokenizer::new(self.format.as_ref()).flat_map(|arg| match arg { Tokenizer::new(self.format.as_ref()).flat_map(|arg| match arg {
Token::Literal(literal) => Some(Op::Text(literal)), Token::Literal(literal) => Some(Op::Text(literal)),
Token::Argument("mono") => Some(Op::Font(self.layout.mono_font)), Token::Argument("mono") => Some(Op::Font(self.fonts.mono)),
Token::Argument("bold") => Some(Op::Font(self.layout.bold_font)), Token::Argument("bold") => Some(Op::Font(self.fonts.bold)),
Token::Argument("normal") => Some(Op::Font(self.layout.normal_font)), Token::Argument("normal") => Some(Op::Font(self.fonts.normal)),
Token::Argument("medium") => Some(Op::Font(self.layout.medium_font)), Token::Argument("medium") => Some(Op::Font(self.fonts.medium)),
Token::Argument(argument) => self Token::Argument(argument) => self
.args .args
.get(argument) .get(argument)

View File

@ -37,72 +37,59 @@ pub struct TextLayout {
/// negative. /// negative.
pub padding_bottom: i32, pub padding_bottom: i32,
/// Background color. /// Fonts, colors, line/page breaking behavior.
pub background_color: Color, pub style: TextStyle,
/// Text color. Can be overridden by `Op::Color`. }
pub text_color: Color,
#[derive(Copy, Clone)]
pub struct TextStyle {
/// Text font ID. Can be overridden by `Op::Font`. /// Text font ID. Can be overridden by `Op::Font`.
pub text_font: Font, pub text_font: Font,
/// Text color. Can be overridden by `Op::Color`.
pub text_color: Color,
/// Background color.
pub background_color: Color,
/// Specifies which line-breaking strategy to use.
pub line_breaking: LineBreaking,
/// Font used for drawing the word-breaking hyphen.
pub hyphen_font: Font,
/// Foreground color used for drawing the hyphen. /// Foreground color used for drawing the hyphen.
pub hyphen_color: Color, pub hyphen_color: Color,
/// Specifies what to do at the end of the page.
pub page_breaking: PageBreaking,
/// Font used for drawing the ellipsis.
pub ellipsis_font: Font,
/// Foreground color used for drawing the ellipsis. /// Foreground color used for drawing the ellipsis.
pub ellipsis_color: Color, pub ellipsis_color: Color,
/// Font used to format `{normal}`. /// Specifies which line-breaking strategy to use.
pub normal_font: Font, pub line_breaking: LineBreaking,
/// Font used to format `{medium}`. /// Specifies what to do at the end of the page.
pub medium_font: Font, pub page_breaking: PageBreaking,
/// Font used to format `{bold}`.
pub bold_font: Font,
/// Font used to format `{mono}`.
pub mono_font: Font,
} }
pub trait DefaultTextTheme { impl TextStyle {
const BACKGROUND_COLOR: Color; pub const fn new(
const TEXT_FONT: Font; text_font: Font,
const TEXT_COLOR: Color; text_color: Color,
const HYPHEN_FONT: Font; background_color: Color,
const HYPHEN_COLOR: Color; hyphen_color: Color,
const ELLIPSIS_FONT: Font; ellipsis_color: Color,
const ELLIPSIS_COLOR: Color; ) -> Self {
const NORMAL_FONT: Font; TextStyle {
const MEDIUM_FONT: Font; text_font,
const BOLD_FONT: Font; text_color,
const MONO_FONT: Font; background_color,
hyphen_color,
ellipsis_color,
line_breaking: LineBreaking::BreakAtWhitespace,
page_breaking: PageBreaking::CutAndInsertEllipsis,
}
}
} }
impl TextLayout { impl TextLayout {
/// Create a new text layout, with empty size and default text parameters /// Create a new text layout, with empty size and default text parameters
/// filled from `T`. /// filled from `T`.
pub fn new<T: DefaultTextTheme>() -> Self { pub fn new(style: TextStyle) -> Self {
Self { Self {
bounds: Rect::zero(), bounds: Rect::zero(),
padding_top: 0, padding_top: 0,
padding_bottom: 0, padding_bottom: 0,
background_color: T::BACKGROUND_COLOR, style,
text_color: T::TEXT_COLOR,
text_font: T::TEXT_FONT,
line_breaking: LineBreaking::BreakAtWhitespace,
hyphen_font: T::HYPHEN_FONT,
hyphen_color: T::HYPHEN_COLOR,
page_breaking: PageBreaking::CutAndInsertEllipsis,
ellipsis_font: T::ELLIPSIS_FONT,
ellipsis_color: T::ELLIPSIS_COLOR,
normal_font: T::NORMAL_FONT,
medium_font: T::MEDIUM_FONT,
bold_font: T::BOLD_FONT,
mono_font: T::MONO_FONT,
} }
} }
@ -112,7 +99,7 @@ impl TextLayout {
} }
pub fn initial_cursor(&self) -> Point { pub fn initial_cursor(&self) -> Point {
self.bounds.top_left() + Offset::y(self.text_font.text_height() + self.padding_top) self.bounds.top_left() + Offset::y(self.style.text_font.text_height() + self.padding_top)
} }
pub fn fit_text(&self, text: &str) -> LayoutFit { pub fn fit_text(&self, text: &str) -> LayoutFit {
@ -135,10 +122,10 @@ impl TextLayout {
for op in ops { for op in ops {
match op { match op {
Op::Color(color) => { Op::Color(color) => {
self.text_color = color; self.style.text_color = color;
} }
Op::Font(font) => { Op::Font(font) => {
self.text_font = font; self.style.text_font = font;
} }
Op::Text(text) => match self.layout_text(text, cursor, sink) { Op::Text(text) => match self.layout_text(text, cursor, sink) {
LayoutFit::Fitting { LayoutFit::Fitting {
@ -189,9 +176,8 @@ impl TextLayout {
let span = Span::fit_horizontally( let span = Span::fit_horizontally(
remaining_text, remaining_text,
self.bounds.x1 - cursor.x, self.bounds.x1 - cursor.x,
self.text_font, self.style.text_font,
self.hyphen_font, self.style.line_breaking,
self.line_breaking,
); );
// Report the span at the cursor position. // Report the span at the cursor position.
@ -216,7 +202,7 @@ impl TextLayout {
// Append ellipsis to indicate more content is available, but only if we // Append ellipsis to indicate more content is available, but only if we
// haven't already appended a hyphen. // haven't already appended a hyphen.
let should_append_ellipsis = let should_append_ellipsis =
matches!(self.page_breaking, PageBreaking::CutAndInsertEllipsis) matches!(self.style.page_breaking, PageBreaking::CutAndInsertEllipsis)
&& !span.insert_hyphen_before_line_break; && !span.insert_hyphen_before_line_break;
if should_append_ellipsis { if should_append_ellipsis {
sink.ellipsis(*cursor, self); sink.ellipsis(*cursor, self);
@ -253,7 +239,7 @@ impl TextLayout {
fn layout_height(&self, init_cursor: Point, end_cursor: Point) -> i32 { fn layout_height(&self, init_cursor: Point, end_cursor: Point) -> i32 {
self.padding_top self.padding_top
+ self.text_font.text_height() + self.style.text_font.text_height()
+ (end_cursor.y - init_cursor.y) + (end_cursor.y - init_cursor.y)
+ self.padding_bottom + self.padding_bottom
} }
@ -295,9 +281,9 @@ impl LayoutSink for TextRenderer {
display::text( display::text(
cursor, cursor,
text, text,
layout.text_font, layout.style.text_font,
layout.text_color, layout.style.text_color,
layout.background_color, layout.style.background_color,
); );
} }
@ -305,9 +291,9 @@ impl LayoutSink for TextRenderer {
display::text( display::text(
cursor, cursor,
"-", "-",
layout.hyphen_font, layout.style.text_font,
layout.hyphen_color, layout.style.hyphen_color,
layout.background_color, layout.style.background_color,
); );
} }
@ -315,9 +301,9 @@ impl LayoutSink for TextRenderer {
display::text( display::text(
cursor, cursor,
"...", "...",
layout.ellipsis_font, layout.style.text_font,
layout.ellipsis_color, layout.style.ellipsis_color,
layout.background_color, layout.style.background_color,
); );
} }
} }
@ -401,7 +387,6 @@ impl Span {
text: &str, text: &str,
max_width: i32, max_width: i32,
text_font: impl GlyphMetrics, text_font: impl GlyphMetrics,
hyphen_font: impl GlyphMetrics,
breaking: LineBreaking, breaking: LineBreaking,
) -> Self { ) -> Self {
const ASCII_LF: char = '\n'; const ASCII_LF: char = '\n';
@ -413,7 +398,7 @@ impl Span {
ch == ASCII_SPACE || ch == ASCII_LF || ch == ASCII_CR ch == ASCII_SPACE || ch == ASCII_LF || ch == ASCII_CR
} }
let hyphen_width = hyphen_font.char_width(ASCII_HYPHEN); let hyphen_width = text_font.char_width(ASCII_HYPHEN);
// The span we return in case the line has to break. We mutate it in the // The span we return in case the line has to break. We mutate it in the
// possible break points, and its initial value is returned in case no text // possible break points, and its initial value is returned in case no text
@ -563,7 +548,6 @@ mod tests {
remaining_text, remaining_text,
max_width, max_width,
FIXED_FONT, FIXED_FONT,
FIXED_FONT,
LineBreaking::BreakAtWhitespace, LineBreaking::BreakAtWhitespace,
); );
spans.push(( spans.push((

View File

@ -2,3 +2,5 @@ pub mod formatted;
mod iter; mod iter;
pub mod layout; pub mod layout;
pub mod paragraphs; pub mod paragraphs;
pub use layout::TextStyle;

View File

@ -2,11 +2,10 @@ use heapless::Vec;
use crate::ui::{ use crate::ui::{
component::{Component, Event, EventCtx, Never, Paginate}, component::{Component, Event, EventCtx, Never, Paginate},
display::Font,
geometry::{Dimensions, Insets, LinearPlacement, Rect}, geometry::{Dimensions, Insets, LinearPlacement, Rect},
}; };
use super::layout::{DefaultTextTheme, LayoutFit, TextLayout}; use super::layout::{LayoutFit, TextLayout, TextStyle};
pub const MAX_PARAGRAPHS: usize = 6; pub const MAX_PARAGRAPHS: usize = 6;
/// Maximum space between paragraphs. Actual result may be smaller (even 0) if /// Maximum space between paragraphs. Actual result may be smaller (even 0) if
@ -53,17 +52,16 @@ where
self self
} }
pub fn add<D: DefaultTextTheme>(mut self, text_font: Font, content: T) -> Self { pub fn add(mut self, style: TextStyle, content: T) -> Self {
if content.as_ref().is_empty() { if content.as_ref().is_empty() {
return self; return self;
} }
let paragraph = Paragraph::new( let paragraph = Paragraph::new(
content, content,
TextLayout { TextLayout {
text_font,
padding_top: PARAGRAPH_TOP_SPACE, padding_top: PARAGRAPH_TOP_SPACE,
padding_bottom: PARAGRAPH_BOTTOM_SPACE, padding_bottom: PARAGRAPH_BOTTOM_SPACE,
..TextLayout::new::<D>() ..TextLayout::new(style)
}, },
); );
if self.list.push(paragraph).is_err() { if self.list.push(paragraph).is_err() {

View File

@ -72,7 +72,7 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
let obj = LayoutObj::new(Frame::new( let obj = LayoutObj::new(Frame::new(
title, title,
ButtonPage::new( ButtonPage::new(
FormattedText::new::<theme::T1DefaultText>(format) FormattedText::new(theme::TEXT_NORMAL, theme::FORMATTED, format)
.with("action", action.unwrap_or_default()) .with("action", action.unwrap_or_default())
.with("description", description.unwrap_or_default()), .with("description", description.unwrap_or_default()),
theme::BG, theme::BG,
@ -94,11 +94,8 @@ extern "C" fn new_confirm_text(n_args: usize, args: *const Obj, kwargs: *mut Map
title, title,
ButtonPage::new( ButtonPage::new(
Paragraphs::new() Paragraphs::new()
.add::<theme::T1DefaultText>( .add(theme::TEXT_NORMAL, description.unwrap_or_default())
theme::FONT_NORMAL, .add(theme::TEXT_BOLD, data),
description.unwrap_or_default(),
)
.add::<theme::T1DefaultText>(theme::FONT_BOLD, data),
theme::BG, theme::BG,
), ),
))?; ))?;
@ -178,7 +175,9 @@ mod tests {
#[test] #[test]
fn trace_example_layout() { fn trace_example_layout() {
let mut layout = Dialog::new( let mut layout = Dialog::new(
FormattedText::new::<theme::T1DefaultText>( FormattedText::new(
theme::TEXT_NORMAL,
theme::FORMATTED,
"Testing text layout, with some text, and some more text. And {param}", "Testing text layout, with some text, and some more text. And {param}",
) )
.with("param", "parameters!"), .with("param", "parameters!"),
@ -208,7 +207,9 @@ arameters! > left:<Button text:Left > right:<Button text:Right > >"#
let mut layout = Frame::new( let mut layout = Frame::new(
"Please confirm", "Please confirm",
Dialog::new( Dialog::new(
FormattedText::new::<theme::T1DefaultText>( FormattedText::new(
theme::TEXT_NORMAL,
theme::FORMATTED,
"Testing text layout, with some text, and some more text. And {param}", "Testing text layout, with some text, and some more text. And {param}",
) )
.with("param", "parameters!"), .with("param", "parameters!"),

View File

@ -1,5 +1,5 @@
use crate::ui::{ use crate::ui::{
component::text::layout::DefaultTextTheme, component::text::{formatted::FormattedFonts, TextStyle},
display::{Color, Font}, display::{Color, Font},
}; };
@ -48,19 +48,14 @@ pub fn button_cancel() -> ButtonStyleSheet {
} }
} }
pub struct T1DefaultText; pub const TEXT_NORMAL: TextStyle = TextStyle::new(FONT_NORMAL, FG, BG, FG, FG);
pub const TEXT_MEDIUM: TextStyle = TextStyle::new(FONT_MEDIUM, FG, BG, FG, FG);
pub const TEXT_BOLD: TextStyle = TextStyle::new(FONT_BOLD, FG, BG, FG, FG);
pub const TEXT_MONO: TextStyle = TextStyle::new(FONT_MONO, FG, BG, FG, FG);
impl DefaultTextTheme for T1DefaultText { pub const FORMATTED: FormattedFonts = FormattedFonts {
const BACKGROUND_COLOR: Color = BG; normal: FONT_NORMAL,
const TEXT_FONT: Font = FONT_NORMAL; medium: FONT_MEDIUM,
const TEXT_COLOR: Color = FG; bold: FONT_BOLD,
const HYPHEN_FONT: Font = FONT_NORMAL; mono: FONT_MONO,
const HYPHEN_COLOR: Color = FG; };
const ELLIPSIS_FONT: Font = FONT_NORMAL;
const ELLIPSIS_COLOR: Color = FG;
const NORMAL_FONT: Font = FONT_NORMAL;
const MEDIUM_FONT: Font = FONT_MEDIUM;
const BOLD_FONT: Font = FONT_BOLD;
const MONO_FONT: Font = FONT_MONO;
}

View File

@ -2,16 +2,14 @@ use crate::{
time::Instant, time::Instant,
ui::{ ui::{
component::{ component::{
text::{layout::DefaultTextTheme, paragraphs::Paragraphs}, text::paragraphs::Paragraphs, Child, Component, ComponentExt, Event, EventCtx, Label,
Child, Component, ComponentExt, Event, EventCtx, Label, LabelStyle, Pad, LabelStyle, Pad,
}, },
constant::screen, constant::screen,
display::{Color, Font},
geometry::{Alignment, Insets, LinearPlacement, Point, Rect}, geometry::{Alignment, Insets, LinearPlacement, Point, Rect},
model_tr::{ model_tr::{
component::{Button, ButtonMsg, ButtonPos, ResultAnim, ResultAnimMsg}, component::{Button, ButtonMsg, ButtonPos, ResultAnim, ResultAnimMsg},
theme, theme::{self, FONT_BOLD},
theme::{TRDefaultText, FONT_BOLD, FONT_MEDIUM},
}, },
}, },
}; };
@ -31,23 +29,6 @@ pub struct ResultPopup {
autoclose: bool, autoclose: bool,
} }
pub struct MessageText;
impl DefaultTextTheme for MessageText {
const BACKGROUND_COLOR: Color = theme::BG;
const TEXT_FONT: Font = FONT_MEDIUM;
const TEXT_COLOR: Color = theme::FG;
const HYPHEN_FONT: Font = FONT_MEDIUM;
const HYPHEN_COLOR: Color = theme::FG;
const ELLIPSIS_FONT: Font = FONT_MEDIUM;
const ELLIPSIS_COLOR: Color = theme::FG;
const NORMAL_FONT: Font = FONT_MEDIUM;
const MEDIUM_FONT: Font = theme::FONT_MEDIUM;
const BOLD_FONT: Font = theme::FONT_BOLD;
const MONO_FONT: Font = theme::FONT_MONO;
}
const ANIM_SIZE: i32 = 18; const ANIM_SIZE: i32 = 18;
const BUTTON_HEIGHT: i32 = 13; const BUTTON_HEIGHT: i32 = 13;
const ANIM_SPACE: i32 = 11; const ANIM_SPACE: i32 = 11;
@ -63,7 +44,7 @@ impl ResultPopup {
button_text: Option<&'static str>, button_text: Option<&'static str>,
) -> Self { ) -> Self {
let p1 = Paragraphs::new() let p1 = Paragraphs::new()
.add::<TRDefaultText>(FONT_MEDIUM, text) .add(theme::TEXT_MEDIUM, text)
.with_placement(LinearPlacement::vertical().align_at_center()); .with_placement(LinearPlacement::vertical().align_at_center());
let button = button_text.map(|t| { let button = button_text.map(|t| {

View File

@ -72,7 +72,7 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
let obj = LayoutObj::new(Frame::new( let obj = LayoutObj::new(Frame::new(
title, title,
ButtonPage::new( ButtonPage::new(
FormattedText::new::<theme::TRDefaultText>(format) FormattedText::new(theme::TEXT_NORMAL, theme::FORMATTED, format)
.with("action", action.unwrap_or_default()) .with("action", action.unwrap_or_default())
.with("description", description.unwrap_or_default()), .with("description", description.unwrap_or_default()),
theme::BG, theme::BG,
@ -94,11 +94,8 @@ extern "C" fn new_confirm_text(n_args: usize, args: *const Obj, kwargs: *mut Map
title, title,
ButtonPage::new( ButtonPage::new(
Paragraphs::new() Paragraphs::new()
.add::<theme::TRDefaultText>( .add(theme::TEXT_NORMAL, description.unwrap_or_default())
theme::FONT_NORMAL, .add(theme::TEXT_BOLD, data),
description.unwrap_or_default(),
)
.add::<theme::TRDefaultText>(theme::FONT_BOLD, data),
theme::BG, theme::BG,
), ),
))?; ))?;
@ -178,7 +175,9 @@ mod tests {
#[test] #[test]
fn trace_example_layout() { fn trace_example_layout() {
let mut layout = Dialog::new( let mut layout = Dialog::new(
FormattedText::new::<theme::TRDefaultText>( FormattedText::new(
theme::TEXT_NORMAL,
theme::FORMATTED,
"Testing text layout, with some text, and some more text. And {param}", "Testing text layout, with some text, and some more text. And {param}",
) )
.with("param", "parameters!"), .with("param", "parameters!"),
@ -208,7 +207,9 @@ arameters! > left:<Button text:Left > right:<Button text:Right > >"#
let mut layout = Frame::new( let mut layout = Frame::new(
"Please confirm", "Please confirm",
Dialog::new( Dialog::new(
FormattedText::new::<theme::TRDefaultText>( FormattedText::new(
theme::TEXT_NORMAL,
theme::FORMATTED,
"Testing text layout, with some text, and some more text. And {param}", "Testing text layout, with some text, and some more text. And {param}",
) )
.with("param", "parameters!"), .with("param", "parameters!"),

View File

@ -1,5 +1,5 @@
use crate::ui::{ use crate::ui::{
component::text::layout::DefaultTextTheme, component::text::{formatted::FormattedFonts, TextStyle},
display::{Color, Font}, display::{Color, Font},
model_tr::component::{LoaderStyle, LoaderStyleSheet}, model_tr::component::{LoaderStyle, LoaderStyleSheet},
}; };
@ -62,19 +62,14 @@ pub fn loader_default() -> LoaderStyleSheet {
} }
} }
pub struct TRDefaultText; pub const TEXT_NORMAL: TextStyle = TextStyle::new(FONT_NORMAL, FG, BG, FG, FG);
pub const TEXT_MEDIUM: TextStyle = TextStyle::new(FONT_MEDIUM, FG, BG, FG, FG);
pub const TEXT_BOLD: TextStyle = TextStyle::new(FONT_BOLD, FG, BG, FG, FG);
pub const TEXT_MONO: TextStyle = TextStyle::new(FONT_MONO, FG, BG, FG, FG);
impl DefaultTextTheme for TRDefaultText { pub const FORMATTED: FormattedFonts = FormattedFonts {
const BACKGROUND_COLOR: Color = BG; normal: FONT_NORMAL,
const TEXT_FONT: Font = FONT_NORMAL; medium: FONT_MEDIUM,
const TEXT_COLOR: Color = FG; bold: FONT_BOLD,
const HYPHEN_FONT: Font = FONT_NORMAL; mono: FONT_MONO,
const HYPHEN_COLOR: Color = FG; };
const ELLIPSIS_FONT: Font = FONT_NORMAL;
const ELLIPSIS_COLOR: Color = FG;
const NORMAL_FONT: Font = FONT_NORMAL;
const MEDIUM_FONT: Font = FONT_MEDIUM;
const BOLD_FONT: Font = FONT_BOLD;
const MONO_FONT: Font = FONT_MONO;
}

View File

@ -380,12 +380,12 @@ mod tests {
fn paragraphs_single() { fn paragraphs_single() {
let mut page = SwipePage::new( let mut page = SwipePage::new(
Paragraphs::new() Paragraphs::new()
.add::<theme::TTDefaultText>( .add(
theme::FONT_NORMAL, theme::TEXT_NORMAL,
"This is the first paragraph and it should fit on the screen entirely.", "This is the first paragraph and it should fit on the screen entirely.",
) )
.add::<theme::TTDefaultText>( .add(
theme::FONT_BOLD, theme::TEXT_BOLD,
"Second, bold, paragraph should also fit on the screen whole I think.", "Second, bold, paragraph should also fit on the screen whole I think.",
), ),
Empty, Empty,
@ -406,8 +406,8 @@ mod tests {
fn paragraphs_one_long() { fn paragraphs_one_long() {
let mut page = SwipePage::new( let mut page = SwipePage::new(
Paragraphs::new() Paragraphs::new()
.add::<theme::TTDefaultText>( .add(
theme::FONT_BOLD, theme::TEXT_BOLD,
"This is somewhat long paragraph that goes on and on and on and on and on and will definitely not fit on just a single screen. You have to swipe a bit to see all the text it contains I guess. There's just so much letters in it.", "This is somewhat long paragraph that goes on and on and on and on and on and will definitely not fit on just a single screen. You have to swipe a bit to see all the text it contains I guess. There's just so much letters in it.",
), ),
Empty, Empty,
@ -433,16 +433,16 @@ mod tests {
fn paragraphs_three_long() { fn paragraphs_three_long() {
let mut page = SwipePage::new( let mut page = SwipePage::new(
Paragraphs::new() Paragraphs::new()
.add::<theme::TTDefaultText>( .add(
theme::FONT_BOLD, theme::TEXT_BOLD,
"This paragraph is using a bold font. It doesn't need to be all that long.", "This paragraph is using a bold font. It doesn't need to be all that long.",
) )
.add::<theme::TTDefaultText>( .add(
theme::FONT_MONO, theme::TEXT_MONO,
"And this one is using MONO. Monospace is nice for numbers, they have the same width and can be scanned quickly. Even if they span several pages or something.", "And this one is using MONO. Monospace is nice for numbers, they have the same width and can be scanned quickly. Even if they span several pages or something.",
) )
.add::<theme::TTDefaultText>( .add(
theme::FONT_BOLD, theme::TEXT_BOLD,
"Let's add another one for a good measure. This one should overflow all the way to the third page with a bit of luck.", "Let's add another one for a good measure. This one should overflow all the way to the third page with a bit of luck.",
), ),
Empty, Empty,

View File

@ -206,12 +206,12 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
let mut paragraphs = Paragraphs::new(); let mut paragraphs = Paragraphs::new();
if !reverse { if !reverse {
paragraphs = paragraphs paragraphs = paragraphs
.add::<theme::TTDefaultText>(theme::FONT_BOLD, action) .add(theme::TEXT_BOLD, action)
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, description); .add(theme::TEXT_NORMAL, description);
} else { } else {
paragraphs = paragraphs paragraphs = paragraphs
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, description) .add(theme::TEXT_NORMAL, description)
.add::<theme::TTDefaultText>(theme::FONT_BOLD, action); .add(theme::TEXT_BOLD, action);
} }
paragraphs paragraphs
}; };
@ -246,9 +246,9 @@ extern "C" fn new_confirm_blob(n_args: usize, args: *const Obj, kwargs: *mut Map
let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?;
let paragraphs = Paragraphs::new() let paragraphs = Paragraphs::new()
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, description) .add(theme::TEXT_NORMAL, description)
.add::<theme::TTDefaultText>(theme::FONT_BOLD, extra) .add(theme::TEXT_BOLD, extra)
.add::<theme::TTDefaultText>(theme::FONT_MONO, data); .add(theme::TEXT_MONO, data);
let obj = if hold { let obj = if hold {
LayoutObj::new( LayoutObj::new(
@ -302,8 +302,8 @@ extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut M
let verb = "NEXT"; let verb = "NEXT";
let paragraphs = Paragraphs::new() let paragraphs = Paragraphs::new()
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, description) .add(theme::TEXT_NORMAL, description)
.add::<theme::TTDefaultText>(theme::FONT_MONO, value); .add(theme::TEXT_MONO, value);
let buttons = Button::cancel_confirm( let buttons = Button::cancel_confirm(
Button::with_icon(theme::ICON_CANCEL), Button::with_icon(theme::ICON_CANCEL),
@ -326,8 +326,8 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma
let value: StrBuffer = kwargs.get(Qstr::MP_QSTR_value)?.try_into()?; let value: StrBuffer = kwargs.get(Qstr::MP_QSTR_value)?.try_into()?;
let paragraphs = Paragraphs::new() let paragraphs = Paragraphs::new()
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, description) .add(theme::TEXT_NORMAL, description)
.add::<theme::TTDefaultText>(theme::FONT_MONO, value); .add(theme::TEXT_MONO, value);
let obj = LayoutObj::new( let obj = LayoutObj::new(
Frame::new(title, SwipeHoldPage::new(paragraphs, theme::BG)).into_child(), Frame::new(title, SwipeHoldPage::new(paragraphs, theme::BG)).into_child(),
@ -343,10 +343,10 @@ extern "C" fn new_confirm_joint_total(n_args: usize, args: *const Obj, kwargs: *
let total_amount: StrBuffer = kwargs.get(Qstr::MP_QSTR_total_amount)?.try_into()?; let total_amount: StrBuffer = kwargs.get(Qstr::MP_QSTR_total_amount)?.try_into()?;
let paragraphs = Paragraphs::new() let paragraphs = Paragraphs::new()
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, "You are contributing:".into()) .add(theme::TEXT_NORMAL, "You are contributing:".into())
.add::<theme::TTDefaultText>(theme::FONT_MONO, spending_amount) .add(theme::TEXT_MONO, spending_amount)
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, "To the total amount:".into()) .add(theme::TEXT_NORMAL, "To the total amount:".into())
.add::<theme::TTDefaultText>(theme::FONT_MONO, total_amount); .add(theme::TEXT_MONO, total_amount);
let obj = LayoutObj::new( let obj = LayoutObj::new(
Frame::new( Frame::new(
@ -374,13 +374,13 @@ extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs:
}; };
let paragraphs = Paragraphs::new() let paragraphs = Paragraphs::new()
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, "Address:".into()) .add(theme::TEXT_NORMAL, "Address:".into())
.add::<theme::TTDefaultText>(theme::FONT_MONO, address) .add(theme::TEXT_MONO, address)
// FIXME pagebreak // FIXME pagebreak
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, description.into()) .add(theme::TEXT_NORMAL, description.into())
.add::<theme::TTDefaultText>(theme::FONT_MONO, amount_change) .add(theme::TEXT_MONO, amount_change)
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, "New amount:".into()) .add(theme::TEXT_NORMAL, "New amount:".into())
.add::<theme::TTDefaultText>(theme::FONT_MONO, amount_new); .add(theme::TEXT_MONO, amount_new);
let buttons = Button::cancel_confirm( let buttons = Button::cancel_confirm(
Button::with_icon(theme::ICON_CANCEL), Button::with_icon(theme::ICON_CANCEL),
@ -413,10 +413,10 @@ extern "C" fn new_confirm_modify_fee(n_args: usize, args: *const Obj, kwargs: *m
}; };
let paragraphs = Paragraphs::new() let paragraphs = Paragraphs::new()
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, description.into()) .add(theme::TEXT_NORMAL, description.into())
.add::<theme::TTDefaultText>(theme::FONT_MONO, change) .add(theme::TEXT_MONO, change)
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, "\nTransaction fee:".into()) .add(theme::TEXT_NORMAL, "\nTransaction fee:".into())
.add::<theme::TTDefaultText>(theme::FONT_MONO, total_fee_new); .add(theme::TEXT_MONO, total_fee_new);
let buttons = Button::cancel_confirm( let buttons = Button::cancel_confirm(
Button::with_icon(theme::ICON_CANCEL), Button::with_icon(theme::ICON_CANCEL),
@ -481,14 +481,13 @@ extern "C" fn new_confirm_payment_request(
let description: StrBuffer = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; let description: StrBuffer = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
let memos: Obj = kwargs.get(Qstr::MP_QSTR_memos)?; let memos: Obj = kwargs.get(Qstr::MP_QSTR_memos)?;
let mut paragraphs = let mut paragraphs = Paragraphs::new().add(theme::TEXT_NORMAL, description);
Paragraphs::new().add::<theme::TTDefaultText>(theme::FONT_NORMAL, description);
let mut iter_buf = IterBuf::new(); let mut iter_buf = IterBuf::new();
let iter = Iter::try_from_obj_with_buf(memos, &mut iter_buf)?; let iter = Iter::try_from_obj_with_buf(memos, &mut iter_buf)?;
for memo in iter { for memo in iter {
let text: StrBuffer = memo.try_into()?; let text: StrBuffer = memo.try_into()?;
paragraphs = paragraphs.add::<theme::TTDefaultText>(theme::FONT_NORMAL, text); paragraphs = paragraphs.add(theme::TEXT_NORMAL, text);
} }
let buttons = Button::cancel_info_confirm("CONFIRM", "DETAILS"); let buttons = Button::cancel_info_confirm("CONFIRM", "DETAILS");
@ -512,12 +511,12 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut
let max_feerate: StrBuffer = kwargs.get(Qstr::MP_QSTR_max_feerate)?.try_into()?; let max_feerate: StrBuffer = kwargs.get(Qstr::MP_QSTR_max_feerate)?.try_into()?;
let paragraphs = Paragraphs::new() let paragraphs = Paragraphs::new()
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, "Coin name:".into()) .add(theme::TEXT_NORMAL, "Coin name:".into())
.add::<theme::TTDefaultText>(theme::FONT_BOLD, coin_name) .add(theme::TEXT_BOLD, coin_name)
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, "Maximum rounds:".into()) .add(theme::TEXT_NORMAL, "Maximum rounds:".into())
.add::<theme::TTDefaultText>(theme::FONT_BOLD, max_rounds) .add(theme::TEXT_BOLD, max_rounds)
.add::<theme::TTDefaultText>(theme::FONT_NORMAL, "Maximum mining fee:".into()) .add(theme::TEXT_NORMAL, "Maximum mining fee:".into())
.add::<theme::TTDefaultText>(theme::FONT_BOLD, max_feerate); .add(theme::TEXT_BOLD, max_feerate);
let obj = LayoutObj::new( let obj = LayoutObj::new(
Frame::new( Frame::new(
@ -761,7 +760,9 @@ mod tests {
let buttons = let buttons =
Button::cancel_confirm(Button::with_text("Left"), Button::with_text("Right"), 1); Button::cancel_confirm(Button::with_text("Left"), Button::with_text("Right"), 1);
let mut layout = Dialog::new( let mut layout = Dialog::new(
FormattedText::new::<theme::TTDefaultText>( FormattedText::new(
theme::TEXT_NORMAL,
theme::FORMATTED,
"Testing text layout, with some text, and some more text. And {param}", "Testing text layout, with some text, and some more text. And {param}",
) )
.with("param", "parameters!"), .with("param", "parameters!"),

View File

@ -1,5 +1,8 @@
use crate::ui::{ use crate::ui::{
component::{label::LabelStyle, text::layout::DefaultTextTheme}, component::{
label::LabelStyle,
text::{formatted::FormattedFonts, TextStyle},
},
display::{Color, Font}, display::{Color, Font},
geometry::Insets, geometry::Insets,
}; };
@ -298,22 +301,17 @@ pub fn loader_default() -> LoaderStyleSheet {
} }
} }
pub struct TTDefaultText; pub const TEXT_NORMAL: TextStyle = TextStyle::new(FONT_NORMAL, FG, BG, GREY_LIGHT, GREY_LIGHT);
pub const TEXT_MEDIUM: TextStyle = TextStyle::new(FONT_MEDIUM, FG, BG, GREY_LIGHT, GREY_LIGHT);
pub const TEXT_BOLD: TextStyle = TextStyle::new(FONT_BOLD, FG, BG, GREY_LIGHT, GREY_LIGHT);
pub const TEXT_MONO: TextStyle = TextStyle::new(FONT_MONO, FG, BG, GREY_LIGHT, GREY_LIGHT);
impl DefaultTextTheme for TTDefaultText { pub const FORMATTED: FormattedFonts = FormattedFonts {
const BACKGROUND_COLOR: Color = BG; normal: FONT_NORMAL,
const TEXT_FONT: Font = FONT_NORMAL; medium: FONT_MEDIUM,
const TEXT_COLOR: Color = FG; bold: FONT_BOLD,
const HYPHEN_FONT: Font = FONT_BOLD; mono: FONT_MONO,
const HYPHEN_COLOR: Color = GREY_LIGHT; };
const ELLIPSIS_FONT: Font = FONT_BOLD;
const ELLIPSIS_COLOR: Color = GREY_LIGHT;
const NORMAL_FONT: Font = FONT_NORMAL;
const MEDIUM_FONT: Font = FONT_MEDIUM;
const BOLD_FONT: Font = FONT_BOLD;
const MONO_FONT: Font = FONT_MONO;
}
pub const CONTENT_BORDER: i32 = 5; pub const CONTENT_BORDER: i32 = 5;
pub const KEYBOARD_SPACING: i32 = 8; pub const KEYBOARD_SPACING: i32 = 8;

View File

@ -6,8 +6,6 @@ from trezor.enums import ButtonRequestType
import trezorui2 import trezorui2
from ...components.tt.confirm import Confirm
from ...constants.tt import MONO_ADDR_PER_LINE
from ..common import button_request, interact from ..common import button_request, interact
if TYPE_CHECKING: if TYPE_CHECKING:
@ -419,8 +417,8 @@ async def confirm_output(
color_to: int = ui.FG, # TODO cleanup @ redesign color_to: int = ui.FG, # TODO cleanup @ redesign
to_str: str = " to\n", # TODO cleanup @ redesign to_str: str = " to\n", # TODO cleanup @ redesign
to_paginated: bool = False, # TODO cleanup @ redesign to_paginated: bool = False, # TODO cleanup @ redesign
width: int = MONO_ADDR_PER_LINE, width: int = 0, # TODO cleanup @ redesign
width_paginated: int = MONO_ADDR_PER_LINE - 1, width_paginated: int = 0, # TODO cleanup @ redesign
br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput, br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput,
icon: str = ui.ICON_SEND, icon: str = ui.ICON_SEND,
) -> None: ) -> None:
@ -495,7 +493,7 @@ async def should_show_more(
br_code: ButtonRequestType = ButtonRequestType.Other, br_code: ButtonRequestType = ButtonRequestType.Other,
icon: str = ui.ICON_DEFAULT, icon: str = ui.ICON_DEFAULT,
icon_color: int = ui.ORANGE_ICON, icon_color: int = ui.ORANGE_ICON,
confirm: ButtonContent = Confirm.DEFAULT_CONFIRM, confirm: ButtonContent = None,
major_confirm: bool = False, major_confirm: bool = False,
) -> bool: ) -> bool:
raise NotImplementedError raise NotImplementedError

File diff suppressed because it is too large Load Diff