diff --git a/core/embed/rust/src/ui/model_t1/component/dialog.rs b/core/embed/rust/src/ui/model_t1/component/dialog.rs index 02af53a1b..27f709e1b 100644 --- a/core/embed/rust/src/ui/model_t1/component/dialog.rs +++ b/core/embed/rust/src/ui/model_t1/component/dialog.rs @@ -4,8 +4,7 @@ use super::{ }; use crate::ui::{ component::{Child, Component, Event, EventCtx}, - display, - geometry::{Offset, Rect}, + geometry::Rect, }; pub enum DialogMsg { @@ -15,7 +14,6 @@ pub enum DialogMsg { } pub struct Dialog { - header: Option<(U, Rect)>, content: Child, left_btn: Option>>, right_btn: Option>>, @@ -27,46 +25,22 @@ impl> Dialog { content: impl FnOnce(Rect) -> T, left: Option Button>, right: Option Button>, - header: Option, ) -> Self { - let (header_area, content_area, button_area) = Self::areas(area, &header); + let (content_area, button_area) = Self::areas(area); let content = Child::new(content(content_area)); let left_btn = left.map(|f| Child::new(f(button_area, ButtonPos::Left))); let right_btn = right.map(|f| Child::new(f(button_area, ButtonPos::Right))); Self { - header: header.zip(header_area), content, left_btn, right_btn, } } - fn paint_header(&self) { - if let Some((title, area)) = &self.header { - display::text( - area.bottom_left() + Offset::new(0, -2), - title.as_ref(), - theme::FONT_BOLD, - theme::FG, - theme::BG, - ); - display::dotted_line(area.bottom_left(), area.width(), theme::FG) - } - } - - fn areas(area: Rect, header: &Option) -> (Option, Rect, Rect) { - const HEADER_SPACE: i32 = 4; + fn areas(area: Rect) -> (Rect, Rect) { let button_height = theme::FONT_BOLD.line_height() + 2; - let header_height = theme::FONT_BOLD.line_height(); - let (content_area, button_area) = area.hsplit(-button_height); - if header.is_none() { - (None, content_area, button_area) - } else { - let (header_area, content_area) = content_area.hsplit(header_height); - let (_space, content_area) = content_area.hsplit(HEADER_SPACE); - (Some(header_area), content_area, button_area) - } + (content_area, button_area) } } @@ -86,7 +60,6 @@ impl> Component for Dialog { } fn paint(&mut self) { - self.paint_header(); self.content.paint(); if let Some(b) = self.left_btn.as_mut() { b.paint(); diff --git a/core/embed/rust/src/ui/model_t1/component/mod.rs b/core/embed/rust/src/ui/model_t1/component/mod.rs index 9a4eb1129..89307f4b1 100644 --- a/core/embed/rust/src/ui/model_t1/component/mod.rs +++ b/core/embed/rust/src/ui/model_t1/component/mod.rs @@ -1,7 +1,9 @@ mod button; mod dialog; +mod title; use super::{event, theme}; pub use button::{Button, ButtonContent, ButtonMsg, ButtonPos, ButtonStyle, ButtonStyleSheet}; pub use dialog::{Dialog, DialogMsg}; +pub use title::Title; diff --git a/core/embed/rust/src/ui/model_t1/component/title.rs b/core/embed/rust/src/ui/model_t1/component/title.rs new file mode 100644 index 000000000..83fe0cbba --- /dev/null +++ b/core/embed/rust/src/ui/model_t1/component/title.rs @@ -0,0 +1,67 @@ +use super::theme; +use crate::ui::{ + component::{Child, Component, ComponentExt, Event, EventCtx}, + display, + geometry::{Offset, Rect}, +}; + +pub struct Title { + area: Rect, + title: U, + content: Child, +} + +impl> Title { + pub fn new(area: Rect, title: U, content: impl FnOnce(Rect) -> T) -> Self { + let (title_area, content_area) = Self::areas(area); + Self { + area: title_area, + title, + content: content(content_area).into_child(), + } + } + + fn areas(area: Rect) -> (Rect, Rect) { + const HEADER_SPACE: i32 = 4; + let header_height = theme::FONT_BOLD.line_height(); + + let (header_area, content_area) = area.hsplit(header_height); + let (_space, content_area) = content_area.hsplit(HEADER_SPACE); + + (header_area, content_area) + } +} + +impl> Component for Title { + type Msg = T::Msg; + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + self.content.event(ctx, event) + } + + fn paint(&mut self) { + display::text( + self.area.bottom_left() + Offset::new(0, -2), + self.title.as_ref(), + theme::FONT_BOLD, + theme::FG, + theme::BG, + ); + display::dotted_line(self.area.bottom_left(), self.area.width(), theme::FG); + self.content.paint(); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for Title +where + T: crate::trace::Trace, + U: crate::trace::Trace + AsRef<[u8]>, +{ + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.open("Title"); + t.field("title", &self.title); + t.field("content", &self.content); + t.close(); + } +} diff --git a/core/embed/rust/src/ui/model_t1/layout.rs b/core/embed/rust/src/ui/model_t1/layout.rs index 1bcec5eff..43c8c3e3f 100644 --- a/core/embed/rust/src/ui/model_t1/layout.rs +++ b/core/embed/rust/src/ui/model_t1/layout.rs @@ -12,7 +12,7 @@ use crate::{ }; use super::{ - component::{Button, Dialog, DialogMsg}, + component::{Button, Dialog, DialogMsg, Title}, theme, }; @@ -64,13 +64,14 @@ extern "C" fn ui_layout_new_confirm_action( let obj = LayoutObj::new(Child::new(Dialog::new( display::screen(), |area| { - FormattedText::new::(area, format) - .with(b"action", action.unwrap_or("".into())) - .with(b"description", description.unwrap_or("".into())) + Title::new(area, title, |area| { + FormattedText::new::(area, format) + .with(b"action", action.unwrap_or("".into())) + .with(b"description", description.unwrap_or("".into())) + }) }, left, right, - Some(title), )))?; Ok(obj.into()) }; @@ -137,7 +138,6 @@ mod tests { }, Some(|area, pos| Button::with_text(area, pos, "Left", theme::button_cancel())), Some(|area, pos| Button::with_text(area, pos, "Right", theme::button_default())), - None, )); assert_eq!( trace(&layout), @@ -147,4 +147,29 @@ some more text. And p- arameters! > left: