You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/rust/src/ui/component/text/util.rs

128 lines
3.9 KiB

use crate::{
strutil::TString,
ui::{
display::{Color, Font},
geometry::{Alignment, Rect},
shape::Renderer,
},
};
use super::{
layout::{LayoutFit, TextLayout},
TextStyle,
};
/// Draws longer multiline texts inside an area.
/// Splits lines on word boundaries/whitespace.
/// When a word is too long to fit one line, splitting
/// it on multiple lines with "-" at the line-ends.
///
/// If it fits, returns the rest of the area.
/// If it does not fit, returns `None`.
pub fn text_multiline(
area: Rect,
text: TString<'_>,
font: Font,
fg_color: Color,
bg_color: Color,
alignment: Alignment,
) -> Option<Rect> {
let text_style = TextStyle::new(font, fg_color, bg_color, fg_color, fg_color);
let text_layout = TextLayout::new(text_style)
.with_bounds(area)
.with_align(alignment);
let layout_fit = text.map(|t| text_layout.render_text(t));
match layout_fit {
LayoutFit::Fitting { height, .. } => Some(area.split_top(height).1),
LayoutFit::OutOfBounds { .. } => None,
}
}
/// Draws longer multiline texts inside an area.
/// Splits lines on word boundaries/whitespace.
/// When a word is too long to fit one line, splitting
/// it on multiple lines with "-" at the line-ends.
///
/// If it fits, returns the rest of the area.
/// If it does not fit, returns `None`.
pub fn text_multiline2<'s>(
target: &mut impl Renderer<'s>,
area: Rect,
text: TString<'_>,
font: Font,
fg_color: Color,
bg_color: Color,
alignment: Alignment,
) -> Option<Rect> {
let text_style = TextStyle::new(font, fg_color, bg_color, fg_color, fg_color);
let text_layout = TextLayout::new(text_style)
.with_bounds(area)
.with_align(alignment);
let layout_fit = text.map(|t| text_layout.render_text2(t, target));
match layout_fit {
LayoutFit::Fitting { height, .. } => Some(area.split_top(height).1),
LayoutFit::OutOfBounds { .. } => None,
}
}
/// Same as `text_multiline` above, but aligns the text to the bottom of the
/// area.
pub fn text_multiline_bottom(
area: Rect,
text: TString<'_>,
font: Font,
fg_color: Color,
bg_color: Color,
alignment: Alignment,
) -> Option<Rect> {
let text_style = TextStyle::new(font, fg_color, bg_color, fg_color, fg_color);
let mut text_layout = TextLayout::new(text_style)
.with_bounds(area)
.with_align(alignment);
// When text fits the area, displaying it in the bottom part.
// When not, render it "normally".
text.map(|t| match text_layout.fit_text(t) {
LayoutFit::Fitting { height, .. } => {
let (top, bottom) = area.split_bottom(height);
text_layout = text_layout.with_bounds(bottom);
text_layout.render_text(t);
Some(top)
}
LayoutFit::OutOfBounds { .. } => {
text_layout.render_text(t);
None
}
})
}
/// Same as `text_multiline` above, but aligns the text to the bottom of the
/// area.
pub fn text_multiline_bottom2<'s>(
target: &mut impl Renderer<'s>,
area: Rect,
text: TString<'_>,
font: Font,
fg_color: Color,
bg_color: Color,
alignment: Alignment,
) -> Option<Rect> {
let text_style = TextStyle::new(font, fg_color, bg_color, fg_color, fg_color);
let mut text_layout = TextLayout::new(text_style)
.with_bounds(area)
.with_align(alignment);
// When text fits the area, displaying it in the bottom part.
// When not, render it "normally".
text.map(|t| match text_layout.fit_text(t) {
LayoutFit::Fitting { height, .. } => {
let (top, bottom) = area.split_bottom(height);
text_layout = text_layout.with_bounds(bottom);
text_layout.render_text2(t, target);
Some(top)
}
LayoutFit::OutOfBounds { .. } => {
text_layout.render_text2(t, target);
None
}
})
}