From 005e4203a73c77829564f83e48e62043ef565ba8 Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Tue, 23 Aug 2022 22:18:00 +0200 Subject: [PATCH] refactor(core/rust/ui): text theme struct [no changelog] --- .../rust/src/ui/component/text/formatted.rs | 36 +- .../rust/src/ui/component/text/layout.rs | 118 +-- core/embed/rust/src/ui/component/text/mod.rs | 2 + .../rust/src/ui/component/text/paragraphs.rs | 8 +- core/embed/rust/src/ui/model_t1/layout.rs | 17 +- core/embed/rust/src/ui/model_t1/theme.rs | 27 +- .../src/ui/model_tr/component/result_popup.rs | 27 +- core/embed/rust/src/ui/model_tr/layout.rs | 17 +- core/embed/rust/src/ui/model_tr/theme.rs | 27 +- .../rust/src/ui/model_tt/component/page.rs | 24 +- core/embed/rust/src/ui/model_tt/layout.rs | 71 +- core/embed/rust/src/ui/model_tt/theme.rs | 30 +- core/src/trezor/ui/layouts/tt_v2/__init__.py | 8 +- tests/ui_tests/fixtures.json | 883 +++++++++--------- 14 files changed, 647 insertions(+), 648 deletions(-) diff --git a/core/embed/rust/src/ui/component/text/formatted.rs b/core/embed/rust/src/ui/component/text/formatted.rs index f74486b7ec..9cc870c809 100644 --- a/core/embed/rust/src/ui/component/text/formatted.rs +++ b/core/embed/rust/src/ui/component/text/formatted.rs @@ -12,24 +12,36 @@ use crate::ui::{ }; use super::layout::{ - DefaultTextTheme, LayoutFit, LayoutSink, LineBreaking, Op, PageBreaking, TextLayout, - TextRenderer, + LayoutFit, LayoutSink, LineBreaking, Op, PageBreaking, TextLayout, TextRenderer, TextStyle, }; pub const MAX_ARGUMENTS: usize = 6; pub struct FormattedText { layout: TextLayout, + fonts: FormattedFonts, format: F, args: LinearMap<&'static str, T, MAX_ARGUMENTS>, 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 FormattedText { - pub fn new(format: F) -> Self { + pub fn new(style: TextStyle, fonts: FormattedFonts, format: F) -> Self { Self { format, - layout: TextLayout::new::(), + fonts, + layout: TextLayout::new(style), args: LinearMap::new(), char_offset: 0, } @@ -49,22 +61,22 @@ impl FormattedText { } 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 } 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 } 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 } 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 } @@ -91,10 +103,10 @@ where let mut ops = Op::skip_n_text_bytes( Tokenizer::new(self.format.as_ref()).flat_map(|arg| match arg { Token::Literal(literal) => Some(Op::Text(literal)), - Token::Argument("mono") => Some(Op::Font(self.layout.mono_font)), - Token::Argument("bold") => Some(Op::Font(self.layout.bold_font)), - Token::Argument("normal") => Some(Op::Font(self.layout.normal_font)), - Token::Argument("medium") => Some(Op::Font(self.layout.medium_font)), + Token::Argument("mono") => Some(Op::Font(self.fonts.mono)), + Token::Argument("bold") => Some(Op::Font(self.fonts.bold)), + Token::Argument("normal") => Some(Op::Font(self.fonts.normal)), + Token::Argument("medium") => Some(Op::Font(self.fonts.medium)), Token::Argument(argument) => self .args .get(argument) diff --git a/core/embed/rust/src/ui/component/text/layout.rs b/core/embed/rust/src/ui/component/text/layout.rs index a0278df11b..dafe4e7e42 100644 --- a/core/embed/rust/src/ui/component/text/layout.rs +++ b/core/embed/rust/src/ui/component/text/layout.rs @@ -37,72 +37,59 @@ pub struct TextLayout { /// negative. pub padding_bottom: i32, - /// Background color. - pub background_color: Color, - /// Text color. Can be overridden by `Op::Color`. - pub text_color: Color, + /// Fonts, colors, line/page breaking behavior. + pub style: TextStyle, +} + +#[derive(Copy, Clone)] +pub struct TextStyle { /// Text font ID. Can be overridden by `Op::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. 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. pub ellipsis_color: Color, - /// Font used to format `{normal}`. - pub normal_font: Font, - /// Font used to format `{medium}`. - pub medium_font: Font, - /// Font used to format `{bold}`. - pub bold_font: Font, - /// Font used to format `{mono}`. - pub mono_font: Font, + /// Specifies which line-breaking strategy to use. + pub line_breaking: LineBreaking, + /// Specifies what to do at the end of the page. + pub page_breaking: PageBreaking, } -pub trait DefaultTextTheme { - const BACKGROUND_COLOR: Color; - const TEXT_FONT: Font; - const TEXT_COLOR: Color; - const HYPHEN_FONT: Font; - const HYPHEN_COLOR: Color; - const ELLIPSIS_FONT: Font; - const ELLIPSIS_COLOR: Color; - const NORMAL_FONT: Font; - const MEDIUM_FONT: Font; - const BOLD_FONT: Font; - const MONO_FONT: Font; +impl TextStyle { + pub const fn new( + text_font: Font, + text_color: Color, + background_color: Color, + hyphen_color: Color, + ellipsis_color: Color, + ) -> Self { + TextStyle { + text_font, + text_color, + background_color, + hyphen_color, + ellipsis_color, + line_breaking: LineBreaking::BreakAtWhitespace, + page_breaking: PageBreaking::CutAndInsertEllipsis, + } + } } impl TextLayout { /// Create a new text layout, with empty size and default text parameters /// filled from `T`. - pub fn new() -> Self { + pub fn new(style: TextStyle) -> Self { Self { bounds: Rect::zero(), padding_top: 0, padding_bottom: 0, - background_color: T::BACKGROUND_COLOR, - 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, + style, } } @@ -112,7 +99,7 @@ impl TextLayout { } 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 { @@ -135,10 +122,10 @@ impl TextLayout { for op in ops { match op { Op::Color(color) => { - self.text_color = color; + self.style.text_color = color; } Op::Font(font) => { - self.text_font = font; + self.style.text_font = font; } Op::Text(text) => match self.layout_text(text, cursor, sink) { LayoutFit::Fitting { @@ -189,9 +176,8 @@ impl TextLayout { let span = Span::fit_horizontally( remaining_text, self.bounds.x1 - cursor.x, - self.text_font, - self.hyphen_font, - self.line_breaking, + self.style.text_font, + self.style.line_breaking, ); // 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 // haven't already appended a hyphen. let should_append_ellipsis = - matches!(self.page_breaking, PageBreaking::CutAndInsertEllipsis) + matches!(self.style.page_breaking, PageBreaking::CutAndInsertEllipsis) && !span.insert_hyphen_before_line_break; if should_append_ellipsis { sink.ellipsis(*cursor, self); @@ -253,7 +239,7 @@ impl TextLayout { fn layout_height(&self, init_cursor: Point, end_cursor: Point) -> i32 { self.padding_top - + self.text_font.text_height() + + self.style.text_font.text_height() + (end_cursor.y - init_cursor.y) + self.padding_bottom } @@ -295,9 +281,9 @@ impl LayoutSink for TextRenderer { display::text( cursor, text, - layout.text_font, - layout.text_color, - layout.background_color, + layout.style.text_font, + layout.style.text_color, + layout.style.background_color, ); } @@ -305,9 +291,9 @@ impl LayoutSink for TextRenderer { display::text( cursor, "-", - layout.hyphen_font, - layout.hyphen_color, - layout.background_color, + layout.style.text_font, + layout.style.hyphen_color, + layout.style.background_color, ); } @@ -315,9 +301,9 @@ impl LayoutSink for TextRenderer { display::text( cursor, "...", - layout.ellipsis_font, - layout.ellipsis_color, - layout.background_color, + layout.style.text_font, + layout.style.ellipsis_color, + layout.style.background_color, ); } } @@ -401,7 +387,6 @@ impl Span { text: &str, max_width: i32, text_font: impl GlyphMetrics, - hyphen_font: impl GlyphMetrics, breaking: LineBreaking, ) -> Self { const ASCII_LF: char = '\n'; @@ -413,7 +398,7 @@ impl Span { 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 // possible break points, and its initial value is returned in case no text @@ -563,7 +548,6 @@ mod tests { remaining_text, max_width, FIXED_FONT, - FIXED_FONT, LineBreaking::BreakAtWhitespace, ); spans.push(( diff --git a/core/embed/rust/src/ui/component/text/mod.rs b/core/embed/rust/src/ui/component/text/mod.rs index 8e143a897c..86b1eb53c5 100644 --- a/core/embed/rust/src/ui/component/text/mod.rs +++ b/core/embed/rust/src/ui/component/text/mod.rs @@ -2,3 +2,5 @@ pub mod formatted; mod iter; pub mod layout; pub mod paragraphs; + +pub use layout::TextStyle; diff --git a/core/embed/rust/src/ui/component/text/paragraphs.rs b/core/embed/rust/src/ui/component/text/paragraphs.rs index d45c945bb2..4c86c9fd96 100644 --- a/core/embed/rust/src/ui/component/text/paragraphs.rs +++ b/core/embed/rust/src/ui/component/text/paragraphs.rs @@ -2,11 +2,10 @@ use heapless::Vec; use crate::ui::{ component::{Component, Event, EventCtx, Never, Paginate}, - display::Font, geometry::{Dimensions, Insets, LinearPlacement, Rect}, }; -use super::layout::{DefaultTextTheme, LayoutFit, TextLayout}; +use super::layout::{LayoutFit, TextLayout, TextStyle}; pub const MAX_PARAGRAPHS: usize = 6; /// Maximum space between paragraphs. Actual result may be smaller (even 0) if @@ -53,17 +52,16 @@ where self } - pub fn add(mut self, text_font: Font, content: T) -> Self { + pub fn add(mut self, style: TextStyle, content: T) -> Self { if content.as_ref().is_empty() { return self; } let paragraph = Paragraph::new( content, TextLayout { - text_font, padding_top: PARAGRAPH_TOP_SPACE, padding_bottom: PARAGRAPH_BOTTOM_SPACE, - ..TextLayout::new::() + ..TextLayout::new(style) }, ); if self.list.push(paragraph).is_err() { diff --git a/core/embed/rust/src/ui/model_t1/layout.rs b/core/embed/rust/src/ui/model_t1/layout.rs index 8fc4683431..3917f7b536 100644 --- a/core/embed/rust/src/ui/model_t1/layout.rs +++ b/core/embed/rust/src/ui/model_t1/layout.rs @@ -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( title, ButtonPage::new( - FormattedText::new::(format) + FormattedText::new(theme::TEXT_NORMAL, theme::FORMATTED, format) .with("action", action.unwrap_or_default()) .with("description", description.unwrap_or_default()), theme::BG, @@ -94,11 +94,8 @@ extern "C" fn new_confirm_text(n_args: usize, args: *const Obj, kwargs: *mut Map title, ButtonPage::new( Paragraphs::new() - .add::( - theme::FONT_NORMAL, - description.unwrap_or_default(), - ) - .add::(theme::FONT_BOLD, data), + .add(theme::TEXT_NORMAL, description.unwrap_or_default()) + .add(theme::TEXT_BOLD, data), theme::BG, ), ))?; @@ -178,7 +175,9 @@ mod tests { #[test] fn trace_example_layout() { let mut layout = Dialog::new( - FormattedText::new::( + FormattedText::new( + theme::TEXT_NORMAL, + theme::FORMATTED, "Testing text layout, with some text, and some more text. And {param}", ) .with("param", "parameters!"), @@ -208,7 +207,9 @@ arameters! > left: