diff --git a/core/embed/rust/src/ui/display/font.rs b/core/embed/rust/src/ui/display/font.rs index 255727b26..ba9edb9f4 100644 --- a/core/embed/rust/src/ui/display/font.rs +++ b/core/embed/rust/src/ui/display/font.rs @@ -129,15 +129,43 @@ impl Font { display::text_width(text, self.into()) } - /// Width of the text that is visible, not including the space - /// after the last character. + /// Width of the text that is visible. + /// Not including the spaces before the first and after the last character. pub fn visible_text_width(self, text: &str) -> i16 { - let text_minus_one = &text[..text.len() - 1]; + match text.len() { + 0 => 0, + 1 => { + let char = unwrap!(text.chars().last()); + let char_glyph = unwrap!(self.get_glyph(char as u8)); + char_glyph.width + }, + _ => { + let first_char = unwrap!(text.chars().next()); + let first_char_glyph = unwrap!(self.get_glyph(first_char as u8)); + let first_char_visible_width = first_char_glyph.adv - first_char_glyph.bearing_x; - let last_char = unwrap!(text.chars().last()); - let last_char_glyph = unwrap!(self.get_glyph(last_char as u8)); + let middle_chars = &text[1..text.len() - 1]; + let middle_chars_width = self.text_width(middle_chars); - self.text_width(text_minus_one) + last_char_glyph.width + let last_char = unwrap!(text.chars().last()); + let last_char_glyph = unwrap!(self.get_glyph(last_char as u8)); + let last_char_visible_width = last_char_glyph.width + last_char_glyph.bearing_x; + + first_char_visible_width + middle_chars_width + last_char_visible_width + } + } + } + + /// Returning the x-bearing (offset) of the first character. + /// Useful to enforce that the text is positioned correctly (e.g. centered). + pub fn start_x_bearing(self, text: &str) -> i16 { + if text.is_empty() { + return 0; + } + + let first_char = unwrap!(text.chars().next()); + let first_char_glyph = unwrap!(self.get_glyph(first_char as u8)); + first_char_glyph.bearing_x } pub fn char_width(self, ch: char) -> i16 { diff --git a/core/embed/rust/src/ui/model_tr/component/input_methods/choice_item.rs b/core/embed/rust/src/ui/model_tr/component/input_methods/choice_item.rs index 589e72ed2..5cbdedb27 100644 --- a/core/embed/rust/src/ui/model_tr/component/input_methods/choice_item.rs +++ b/core/embed/rust/src/ui/model_tr/component/input_methods/choice_item.rs @@ -57,23 +57,24 @@ impl ChoiceItem { } } - /// Getting the text width in pixels. - fn text_width(&self) -> i16 { - self.font.text_width(&self.text) - } - /// Getting the visible text width in pixels. fn visible_text_width(&self) -> i16 { self.font.visible_text_width(&self.text) } + /// Getting the initial x-bearing of the text in pixels, + /// so that we can adjust its positioning to center it properly. + fn text_x_bearing(&self) -> i16 { + self.font.start_x_bearing(&self.text) + } + /// Getting the non-central width in pixels. /// It will show an icon if defined, otherwise the text, not both. fn width_side(&self) -> i16 { if let Some(icon) = self.icon { icon.toif.width() } else { - self.text_width() + self.visible_text_width() } } @@ -89,12 +90,7 @@ impl ChoiceItem { let bound = theme::BUTTON_OUTLINE; let left_bottom = area.bottom_center() + Offset::new(-self.width_center() / 2 - bound, bound + 1); - let mut x_size = self.width_center() + 2 * bound; - // Shortening the x-size by one pixel when visible text width is even to center - // it properly. - if self.visible_text_width() % 2 == 0 { - x_size -= 1; - } + let x_size = self.width_center() + 2 * bound; let y_size = self.font.text_height() + 2 * bound; let outline_size = Offset::new(x_size, y_size); let outline = Rect::from_bottom_left_and_size(left_bottom, outline_size); @@ -175,6 +171,9 @@ impl Choice for ChoiceItem { ); baseline = baseline + Offset::x(icon.toif.width() + ICON_RIGHT_PADDING); } + // Possibly shifting the baseline left, when there is a text bearing. + // This is to center the text properly. + baseline = baseline - Offset::x(self.text_x_bearing()); if inverse { display_inverse(baseline, &self.text, self.font); } else { @@ -190,7 +189,7 @@ impl Choice for ChoiceItem { } else { 0 }; - icon_width + self.text_width() + icon_width + self.visible_text_width() } /// Painting item on the side if it fits, otherwise paint incomplete if