diff --git a/core/embed/rust/src/ui/model_mercury/component/binary_selection.rs b/core/embed/rust/src/ui/model_mercury/component/binary_selection.rs new file mode 100644 index 0000000000..3761970795 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/binary_selection.rs @@ -0,0 +1,90 @@ +use crate::ui::{ + component::{Component, Event, EventCtx}, + geometry::{Alignment2D, Offset, Rect}, + shape::Renderer, +}; + +use super::{super::cshape, theme, Button, ButtonContent, ButtonMsg, ButtonStyleSheet}; + +pub enum BinarySelectionMsg { + Left, + Right, +} + +/// Component presenting a binary choice represented as two buttons, left and +/// right. Both buttons are parameterized with content and style. +#[derive(Clone)] +pub struct BinarySelection { + buttons_area: Rect, + button_left: Button, + button_right: Button, +} + +impl BinarySelection { + pub fn new( + left_content: ButtonContent, + right_content: ButtonContent, + left_style: ButtonStyleSheet, + right_style: ButtonStyleSheet, + ) -> Self { + Self { + buttons_area: Rect::zero(), + button_left: Button::new(left_content).styled(left_style), + button_right: Button::new(right_content).styled(right_style), + } + } +} + +impl Component for BinarySelection { + type Msg = BinarySelectionMsg; + + fn place(&mut self, bounds: Rect) -> Rect { + // Ensure reasonable space. Other than that, this component fits itself into any + // bounds. + let bounds_width = bounds.width(); + let bounds_height = bounds.height(); + assert!(bounds_width > 62); + assert!(bounds_height > 30); + + let buttons_area = Rect::snap( + bounds.center(), + Offset::new(bounds_width, theme::BUTTON_HEIGHT.min(bounds_height)), + Alignment2D::CENTER, + ); + let (left_area, _, right_area) = buttons_area.split_center(theme::SPACING); + self.button_left.place(left_area); + self.button_right.place(right_area); + + self.buttons_area = buttons_area; + bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> { + if let Some(ButtonMsg::Clicked) = self.button_left.event(ctx, event) { + return Some(BinarySelectionMsg::Left); + } + if let Some(ButtonMsg::Clicked) = self.button_right.event(ctx, event) { + return Some(BinarySelectionMsg::Right); + } + None + } + + fn paint(&mut self) { + unimplemented!() + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.button_left.render(target); + self.button_right.render(target); + cshape::KeyboardOverlay::new(self.buttons_area).render(target); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for BinarySelection { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("BinarySelection"); + t.child("button_left", &self.button_left); + t.child("button_right", &self.button_right); + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/mod.rs b/core/embed/rust/src/ui/model_mercury/component/mod.rs index 864a20357d..abb63435e5 100644 --- a/core/embed/rust/src/ui/model_mercury/component/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/component/mod.rs @@ -1,5 +1,7 @@ #[cfg(feature = "translations")] mod address_details; +#[cfg(feature = "ui_overlay")] +mod binary_selection; pub mod bl_confirm; mod button; #[cfg(feature = "translations")] @@ -41,6 +43,8 @@ mod welcome_screen; #[cfg(feature = "translations")] pub use address_details::AddressDetails; +#[cfg(feature = "ui_overlay")] +pub use binary_selection::{BinarySelection, BinarySelectionMsg}; pub use button::{ Button, ButtonContent, ButtonMsg, ButtonStyle, ButtonStyleSheet, CancelConfirmMsg, CancelInfoConfirmMsg, IconText,