From f0d5f9069afb494ccb0f149ef79201785c43206f Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Sun, 3 Jul 2022 16:24:06 +0200 Subject: [PATCH] refactor(core/rust/ui): text centering in Paragraphs Only works for paragraphs, not formatted text. [no changelog] --- .../rust/src/ui/component/text/layout.rs | 19 ++++++- .../rust/src/ui/component/text/paragraphs.rs | 18 +++++- .../rust/src/ui/model_tt/component/dialog.rs | 55 +++++++++---------- core/embed/rust/src/ui/model_tt/layout.rs | 2 +- 4 files changed, 62 insertions(+), 32 deletions(-) diff --git a/core/embed/rust/src/ui/component/text/layout.rs b/core/embed/rust/src/ui/component/text/layout.rs index dafe4e7e42..bbbc1658f8 100644 --- a/core/embed/rust/src/ui/component/text/layout.rs +++ b/core/embed/rust/src/ui/component/text/layout.rs @@ -2,7 +2,7 @@ use super::iter::GlyphMetrics; use crate::ui::{ display, display::{Color, Font}, - geometry::{Offset, Point, Rect}, + geometry::{Alignment, Offset, Point, Rect}, }; #[derive(Copy, Clone)] @@ -39,6 +39,8 @@ pub struct TextLayout { /// Fonts, colors, line/page breaking behavior. pub style: TextStyle, + /// Horizontal alignment. + pub align: Alignment, } #[derive(Copy, Clone)] @@ -90,6 +92,7 @@ impl TextLayout { padding_top: 0, padding_bottom: 0, style, + align: Alignment::Start, } } @@ -98,6 +101,11 @@ impl TextLayout { self } + pub fn with_align(mut self, align: Alignment) -> Self { + self.align = align; + self + } + pub fn initial_cursor(&self) -> Point { self.bounds.top_left() + Offset::y(self.style.text_font.text_height() + self.padding_top) } @@ -173,13 +181,20 @@ impl TextLayout { } while !remaining_text.is_empty() { + let remaining_width = self.bounds.x1 - cursor.x; let span = Span::fit_horizontally( remaining_text, - self.bounds.x1 - cursor.x, + remaining_width, self.style.text_font, self.style.line_breaking, ); + cursor.x += match self.align { + Alignment::Start => 0, + Alignment::Center => (remaining_width - span.advance.x) / 2, + Alignment::End => remaining_width - span.advance.x, + }; + // Report the span at the cursor position. sink.text(*cursor, self, &remaining_text[..span.length]); diff --git a/core/embed/rust/src/ui/component/text/paragraphs.rs b/core/embed/rust/src/ui/component/text/paragraphs.rs index ef8c35c08c..3c851908fa 100644 --- a/core/embed/rust/src/ui/component/text/paragraphs.rs +++ b/core/embed/rust/src/ui/component/text/paragraphs.rs @@ -2,7 +2,8 @@ use heapless::Vec; use crate::ui::{ component::{Component, Event, EventCtx, Never, Paginate}, - geometry::{Dimensions, Insets, LinearPlacement, Rect}, + display::Color, + geometry::{Alignment, Dimensions, Insets, LinearPlacement, Rect}, }; use super::layout::{LayoutFit, TextLayout, TextStyle}; @@ -52,6 +53,14 @@ where self } + pub fn add_color(self, style: TextStyle, color: Color, content: T) -> Self { + let color_style = TextStyle { + text_color: color, + ..style + }; + self.add(color_style, content) + } + pub fn add(mut self, style: TextStyle, content: T) -> Self { if content.as_ref().is_empty() { return self; @@ -71,6 +80,13 @@ where self } + pub fn centered(mut self) -> Self { + if let Some(ref mut para) = self.list.last_mut() { + para.layout.align = Alignment::Center; + }; + self + } + pub fn add_break(mut self) -> Self { if let Some(ref mut para) = self.list.last_mut() { para.break_after = true; diff --git a/core/embed/rust/src/ui/model_tt/component/dialog.rs b/core/embed/rust/src/ui/model_tt/component/dialog.rs index 58523580cd..ad138f943c 100644 --- a/core/embed/rust/src/ui/model_tt/component/dialog.rs +++ b/core/embed/rust/src/ui/model_tt/component/dialog.rs @@ -1,8 +1,6 @@ -use core::ops::Deref; - use crate::ui::{ - component::{Child, Component, Event, EventCtx, Image, Label, Never}, - geometry::{Grid, Insets, Rect}, + component::{text::paragraphs::Paragraphs, Child, Component, Event, EventCtx, Image, Never}, + geometry::{Grid, Insets, LinearPlacement, Rect}, }; use super::{theme, Button}; @@ -100,38 +98,48 @@ where pub struct IconDialog { image: Child, - title: Label, - description: Option>, + paragraphs: Paragraphs, controls: Child, } impl IconDialog where - T: Deref, + T: AsRef, U: Component, { pub fn new(icon: &'static [u8], title: T, controls: U) -> Self { Self { image: Child::new(Image::new(icon)), - title: Label::centered(title, theme::label_warning()), - description: None, + paragraphs: Paragraphs::new() + .with_placement( + LinearPlacement::vertical() + .align_at_start() + .with_spacing(Self::VALUE_SPACE), + ) + .add(theme::TEXT_MEDIUM, title) + .centered(), controls: Child::new(controls), } } pub fn with_description(mut self, description: T) -> Self { - self.description = Some(Label::centered(description, theme::label_warning_value())); + if !description.as_ref().is_empty() { + self.paragraphs = self + .paragraphs + .add_color(theme::TEXT_NORMAL, theme::OFF_WHITE, description) + .centered(); + } self } pub const ICON_AREA_HEIGHT: i32 = 64; - pub const DESCRIPTION_SPACE: i32 = 13; - pub const VALUE_SPACE: i32 = 9; + pub const DESCRIPTION_SPACE: i32 = 14; + pub const VALUE_SPACE: i32 = 5; } impl Component for IconDialog where - T: Deref, + T: AsRef, U: Component, { type Msg = DialogMsg; @@ -141,33 +149,27 @@ where let (content, buttons) = bounds.split_bottom(Button::<&str>::HEIGHT); let (image, content) = content.split_top(Self::ICON_AREA_HEIGHT); let content = content.inset(Insets::top(Self::DESCRIPTION_SPACE)); - let (title, content) = content.split_top(self.title.size().y); - let content = content.inset(Insets::top(Self::VALUE_SPACE)); self.image.place(image); - self.title.place(title); - self.description.place(content); + self.paragraphs.place(content); self.controls.place(buttons); bounds } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - self.title.event(ctx, event); - self.description.event(ctx, event); + self.paragraphs.event(ctx, event); self.controls.event(ctx, event).map(Self::Msg::Controls) } fn paint(&mut self) { self.image.paint(); - self.title.paint(); - self.description.paint(); + self.paragraphs.paint(); self.controls.paint(); } fn bounds(&self, sink: &mut dyn FnMut(Rect)) { self.image.bounds(sink); - self.title.bounds(sink); - self.description.bounds(sink); + self.paragraphs.bounds(sink); self.controls.bounds(sink); } } @@ -175,15 +177,12 @@ where #[cfg(feature = "ui_debug")] impl crate::trace::Trace for IconDialog where - T: Deref, + T: AsRef, U: crate::trace::Trace, { fn trace(&self, t: &mut dyn crate::trace::Tracer) { t.open("IconDialog"); - t.field("title", &self.title); - if let Some(ref description) = self.description { - t.field("description", description); - } + t.field("content", &self.paragraphs); t.field("controls", &self.controls); t.close(); } diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index a95d6b399e..6d77d8c73d 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -77,7 +77,7 @@ where impl ComponentMsgObj for IconDialog where - T: Deref, + T: AsRef, U: Component, ::Msg: TryInto, {