mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-25 16:08:32 +00:00
WIP - simplify the flow_helpers, consider moving more things into layout.rs
This commit is contained in:
parent
96d0a7b2e7
commit
e8c8c7d053
@ -68,6 +68,9 @@ pub struct TextStyle {
|
|||||||
pub line_breaking: LineBreaking,
|
pub line_breaking: LineBreaking,
|
||||||
/// Specifies what to do at the end of the page.
|
/// Specifies what to do at the end of the page.
|
||||||
pub page_breaking: PageBreaking,
|
pub page_breaking: PageBreaking,
|
||||||
|
|
||||||
|
/// Specifies how to align text on the line.
|
||||||
|
pub line_alignment: Alignment,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextStyle {
|
impl TextStyle {
|
||||||
@ -86,6 +89,7 @@ impl TextStyle {
|
|||||||
ellipsis_color,
|
ellipsis_color,
|
||||||
line_breaking: LineBreaking::BreakAtWhitespace,
|
line_breaking: LineBreaking::BreakAtWhitespace,
|
||||||
page_breaking: PageBreaking::CutAndInsertEllipsis,
|
page_breaking: PageBreaking::CutAndInsertEllipsis,
|
||||||
|
line_alignment: Alignment::Start,
|
||||||
ellipsis_icon: None,
|
ellipsis_icon: None,
|
||||||
prev_page_icon: None,
|
prev_page_icon: None,
|
||||||
}
|
}
|
||||||
@ -261,7 +265,7 @@ impl TextLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Overall height of the content, including paddings.
|
/// Overall height of the content, including paddings.
|
||||||
fn layout_height(&self, init_cursor: Point, end_cursor: Point) -> i16 {
|
pub fn layout_height(&self, init_cursor: Point, end_cursor: Point) -> i16 {
|
||||||
self.padding_top
|
self.padding_top
|
||||||
+ self.style.text_font.text_height()
|
+ self.style.text_font.text_height()
|
||||||
+ (end_cursor.y - init_cursor.y)
|
+ (end_cursor.y - init_cursor.y)
|
||||||
@ -413,7 +417,7 @@ pub struct Span {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Span {
|
impl Span {
|
||||||
fn fit_horizontally(
|
pub fn fit_horizontally(
|
||||||
text: &str,
|
text: &str,
|
||||||
max_width: i16,
|
max_width: i16,
|
||||||
text_font: impl GlyphMetrics,
|
text_font: impl GlyphMetrics,
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
micropython::buffer::StrBuffer,
|
micropython::buffer::StrBuffer,
|
||||||
ui::{
|
ui::{
|
||||||
component::Paginate,
|
component::{
|
||||||
|
text::{layout::LayoutFit, TextStyle},
|
||||||
|
Paginate, TextLayout,
|
||||||
|
},
|
||||||
display::{Font, Icon, IconAndName},
|
display::{Font, Icon, IconAndName},
|
||||||
geometry::{Alignment, Offset, Point, Rect},
|
geometry::{Alignment, Offset, Point, Rect},
|
||||||
model_tr::theme,
|
model_tr::theme,
|
||||||
@ -12,10 +15,7 @@ use crate::{
|
|||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
flow_pages_poc_helpers::{
|
flow_pages_helpers::{LayoutSink, Op, QrCodeInfo, TextNoOp, TextRenderer, ToDisplay},
|
||||||
LayoutFit, LayoutSink, Op, QrCodeInfo, TextLayout, TextNoOp, TextRenderer, TextStyle,
|
|
||||||
ToDisplay,
|
|
||||||
},
|
|
||||||
ButtonActions, ButtonDetails, ButtonLayout,
|
ButtonActions, ButtonDetails, ButtonLayout,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -340,7 +340,7 @@ impl<const M: usize> Paginate for Page<M> {
|
|||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
pub mod trace {
|
pub mod trace {
|
||||||
use crate::ui::model_tr::component::flow_pages_poc_helpers::TraceSink;
|
use crate::ui::model_tr::component::flow_pages_helpers::TraceSink;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -1,12 +1,27 @@
|
|||||||
//! Mostly copy-pasted stuff from ui/component/text,
|
//! Mostly extending TextLayout from ui/component/text/layout.rs
|
||||||
//! but with small modifications.
|
|
||||||
//! (support for more Ops like icon drawing or arbitrary offsets)
|
//! (support for more Ops like icon drawing or arbitrary offsets)
|
||||||
|
//! - unfortunately means there is quite a lot of duplication at the
|
||||||
|
//! benefit of not polluting the original code things not used there
|
||||||
|
//! (icons, QR codes)
|
||||||
|
//!
|
||||||
|
//! TODO: CONSIDERATION:
|
||||||
|
//! A) maintain this little dirty state
|
||||||
|
//! - biggest duplications are in `layout_text`, which needed to be
|
||||||
|
//! completely copied and renamed to `layout_text_new` just to use the new
|
||||||
|
//! `Sink` here, which supports the icon and QR code
|
||||||
|
//! B) move all the new code into ui/component/text/layout.rs
|
||||||
|
//! - would mean moving there QrCodeInfo, Sink::QrCode, Sink::Icon, etc.
|
||||||
|
//! My preference is B, but we need to agree on that
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
micropython::buffer::StrBuffer,
|
micropython::buffer::StrBuffer,
|
||||||
ui::{
|
ui::{
|
||||||
|
component::{
|
||||||
|
text::layout::{LayoutFit, Span},
|
||||||
|
PageBreaking, TextLayout,
|
||||||
|
},
|
||||||
display::{self, Color, Font, Icon},
|
display::{self, Color, Font, Icon},
|
||||||
geometry::{Alignment, Offset, Point, Rect},
|
geometry::{Alignment, Offset, Point},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -76,134 +91,7 @@ pub enum Op {
|
|||||||
NextPage,
|
NextPage,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum LineBreaking {
|
|
||||||
/// Break line only at whitespace, if possible. If we don't find any
|
|
||||||
/// whitespace, break words.
|
|
||||||
BreakAtWhitespace,
|
|
||||||
/// Break words, adding a hyphen before the line-break. Does not use any
|
|
||||||
/// smart algorithm, just char-by-char.
|
|
||||||
BreakWordsAndInsertHyphen,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum PageBreaking {
|
|
||||||
/// Stop after hitting the bottom-right edge of the bounds.
|
|
||||||
Cut,
|
|
||||||
/// Before stopping at the bottom-right edge, insert ellipsis to signify
|
|
||||||
/// more content is available, but only if no hyphen has been inserted yet.
|
|
||||||
CutAndInsertEllipsis,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Visual instructions for laying out a formatted block of text.
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct TextLayout {
|
|
||||||
/// Bounding box restricting the layout dimensions.
|
|
||||||
pub bounds: Rect,
|
|
||||||
|
|
||||||
/// Additional space before beginning of text, can be negative to shift text
|
|
||||||
/// upwards.
|
|
||||||
pub padding_top: i16,
|
|
||||||
/// Additional space between end of text and bottom of bounding box, can be
|
|
||||||
/// negative.
|
|
||||||
pub padding_bottom: i16,
|
|
||||||
|
|
||||||
/// Fonts, colors, line/page breaking behavior.
|
|
||||||
pub style: TextStyle,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct TextStyle {
|
|
||||||
/// Text font ID. Can be overridden by `Op::Font`.
|
|
||||||
pub text_font: Font,
|
|
||||||
/// Text color. Can be overridden by `Op::Color`.
|
|
||||||
pub text_color: Color,
|
|
||||||
/// Background color.
|
|
||||||
pub background_color: Color,
|
|
||||||
|
|
||||||
/// Foreground color used for drawing the hyphen.
|
|
||||||
pub hyphen_color: Color,
|
|
||||||
/// Foreground color used for drawing the ellipsis.
|
|
||||||
pub ellipsis_color: Color,
|
|
||||||
|
|
||||||
/// Optional icon shown as ellipsis.
|
|
||||||
pub ellipsis_icon: Option<&'static [u8]>,
|
|
||||||
/// Optional icon to signal content continues from previous page.
|
|
||||||
pub prev_page_icon: Option<&'static [u8]>,
|
|
||||||
|
|
||||||
/// Specifies which line-breaking strategy to use.
|
|
||||||
pub line_breaking: LineBreaking,
|
|
||||||
/// Specifies what to do at the end of the page.
|
|
||||||
pub page_breaking: PageBreaking,
|
|
||||||
|
|
||||||
/// Specifies how to align text on the line.
|
|
||||||
pub line_alignment: Alignment,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TextStyle {
|
|
||||||
pub const fn new(
|
|
||||||
text_font: Font,
|
|
||||||
text_color: Color,
|
|
||||||
background_color: Color,
|
|
||||||
hyphen_color: Color,
|
|
||||||
ellipsis_color: Color,
|
|
||||||
) -> Self {
|
|
||||||
TextStyle {
|
|
||||||
text_font,
|
|
||||||
text_color,
|
|
||||||
background_color,
|
|
||||||
hyphen_color,
|
|
||||||
ellipsis_color,
|
|
||||||
line_breaking: LineBreaking::BreakAtWhitespace,
|
|
||||||
page_breaking: PageBreaking::CutAndInsertEllipsis,
|
|
||||||
line_alignment: Alignment::Start,
|
|
||||||
ellipsis_icon: None,
|
|
||||||
prev_page_icon: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adding optional icon shown instead of "..." ellipsis.
|
|
||||||
pub const fn with_ellipsis_icon(mut self, icon: &'static [u8]) -> Self {
|
|
||||||
self.ellipsis_icon = Some(icon);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adding optional icon signalling content continues from previous page.
|
|
||||||
pub const fn with_prev_page_icon(mut self, icon: &'static [u8]) -> Self {
|
|
||||||
self.prev_page_icon = Some(icon);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TextLayout {
|
impl TextLayout {
|
||||||
/// Create a new text layout, with empty size and default text parameters
|
|
||||||
/// filled from `T`.
|
|
||||||
pub fn new(style: TextStyle) -> Self {
|
|
||||||
Self {
|
|
||||||
bounds: Rect::zero(),
|
|
||||||
padding_top: 0,
|
|
||||||
padding_bottom: 0,
|
|
||||||
style,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Baseline `Point` where we are starting to draw the text.
|
|
||||||
pub fn initial_cursor(&self) -> Point {
|
|
||||||
// TODO: do NOT add the text_font height here, as it can be changed - each page
|
|
||||||
// can have its own font and the Y offset would be wrong.
|
|
||||||
self.bounds.top_left() + Offset::y(self.style.text_font.text_height() + self.padding_top)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Y coordinate of the bottom of the available space/bounds
|
|
||||||
pub fn bottom_y(&self) -> i16 {
|
|
||||||
(self.bounds.y1 - self.padding_bottom).max(self.bounds.y0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// X coordinate of the right of the available space/bounds
|
|
||||||
pub fn right_x(&self) -> i16 {
|
|
||||||
self.bounds.x1
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Perform some operations defined on `Op` for a list of those `Op`s
|
/// Perform some operations defined on `Op` for a list of those `Op`s
|
||||||
/// - e.g. changing the color, changing the font or rendering the text.
|
/// - e.g. changing the color, changing the font or rendering the text.
|
||||||
pub fn layout_ops<const M: usize>(
|
pub fn layout_ops<const M: usize>(
|
||||||
@ -316,7 +204,7 @@ impl TextLayout {
|
|||||||
// (start > 0),
|
// (start > 0),
|
||||||
// in which case we could/should start the text with
|
// in which case we could/should start the text with
|
||||||
// an arrow icon (opposite to ellipsis)
|
// an arrow icon (opposite to ellipsis)
|
||||||
self.layout_text(to_really_display, cursor, sink)
|
self.layout_text_new(to_really_display, cursor, sink)
|
||||||
} else if let Op::Icon(icon) = op {
|
} else if let Op::Icon(icon) = op {
|
||||||
self.layout_icon(icon, cursor, sink)
|
self.layout_icon(icon, cursor, sink)
|
||||||
} else {
|
} else {
|
||||||
@ -354,7 +242,7 @@ impl TextLayout {
|
|||||||
/// Loop through the `text` and try to fit it on the current screen,
|
/// Loop through the `text` and try to fit it on the current screen,
|
||||||
/// reporting events to `sink`, which may do something with them (e.g. draw
|
/// reporting events to `sink`, which may do something with them (e.g. draw
|
||||||
/// on screen).
|
/// on screen).
|
||||||
pub fn layout_text(
|
pub fn layout_text_new(
|
||||||
&self,
|
&self,
|
||||||
text: &str,
|
text: &str,
|
||||||
cursor: &mut Point,
|
cursor: &mut Point,
|
||||||
@ -379,13 +267,20 @@ impl TextLayout {
|
|||||||
// instead of the hyphen (have it `ellipsis_length`)
|
// instead of the hyphen (have it `ellipsis_length`)
|
||||||
|
|
||||||
while !remaining_text.is_empty() {
|
while !remaining_text.is_empty() {
|
||||||
|
let remaining_width = self.bounds.x1 - cursor.x;
|
||||||
let span = Span::fit_horizontally(
|
let span = Span::fit_horizontally(
|
||||||
remaining_text,
|
remaining_text,
|
||||||
self.bounds.x1 - cursor.x,
|
remaining_width,
|
||||||
self.style.text_font,
|
self.style.text_font,
|
||||||
self.style.line_breaking,
|
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.
|
// Report the span at the cursor position.
|
||||||
// Not doing it when the span length is 0, as that
|
// Not doing it when the span length is 0, as that
|
||||||
// means we encountered a newline/line-break, which we do not draw.
|
// means we encountered a newline/line-break, which we do not draw.
|
||||||
@ -411,6 +306,7 @@ impl TextLayout {
|
|||||||
}
|
}
|
||||||
// Check the amount of vertical space we have left.
|
// Check the amount of vertical space we have left.
|
||||||
if cursor.y + span.advance.y > self.bottom_y() {
|
if cursor.y + span.advance.y > self.bottom_y() {
|
||||||
|
// Not enough space on this page.
|
||||||
if !remaining_text.is_empty() {
|
if !remaining_text.is_empty() {
|
||||||
// Append ellipsis to indicate more content is available, but only if we
|
// Append ellipsis to indicate more content is available, but only if we
|
||||||
// haven't already appended a hyphen. Also not doing it if the last
|
// haven't already appended a hyphen. Also not doing it if the last
|
||||||
@ -470,7 +366,7 @@ impl TextLayout {
|
|||||||
|
|
||||||
// Icon is too wide to fit on current line.
|
// Icon is too wide to fit on current line.
|
||||||
// Trying to accommodate it on the next line, when it exists on this page.
|
// Trying to accommodate it on the next line, when it exists on this page.
|
||||||
if cursor.x + icon.width() > self.right_x() {
|
if cursor.x + icon.width() > self.bounds.x1 {
|
||||||
cursor.x = self.bounds.x0;
|
cursor.x = self.bounds.x0;
|
||||||
cursor.y += self.style.text_font.line_height();
|
cursor.y += self.style.text_font.line_height();
|
||||||
if cursor.y > self.bottom_y() {
|
if cursor.y > self.bottom_y() {
|
||||||
@ -497,33 +393,6 @@ impl TextLayout {
|
|||||||
pub fn layout_qr_code(&self, qr_code_info: QrCodeInfo, sink: &mut dyn LayoutSink) {
|
pub fn layout_qr_code(&self, qr_code_info: QrCodeInfo, sink: &mut dyn LayoutSink) {
|
||||||
sink.qrcode(qr_code_info);
|
sink.qrcode(qr_code_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overall height of the content, including paddings.
|
|
||||||
fn layout_height(&self, init_cursor: Point, end_cursor: Point) -> i16 {
|
|
||||||
self.padding_top
|
|
||||||
+ self.style.text_font.text_height()
|
|
||||||
+ (end_cursor.y - init_cursor.y)
|
|
||||||
+ self.padding_bottom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether we can fit content on the current screen.
|
|
||||||
/// Knows how many characters got processed and how high the content is.
|
|
||||||
pub enum LayoutFit {
|
|
||||||
/// Entire content fits. Vertical size is returned in `height`.
|
|
||||||
Fitting { processed_chars: usize, height: i16 },
|
|
||||||
/// Content fits partially or not at all.
|
|
||||||
OutOfBounds { processed_chars: usize, height: i16 },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LayoutFit {
|
|
||||||
/// How high is the processed/fitted content.
|
|
||||||
pub fn height(&self) -> i16 {
|
|
||||||
match self {
|
|
||||||
LayoutFit::Fitting { height, .. } => *height,
|
|
||||||
LayoutFit::OutOfBounds { height, .. } => *height,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visitor for text segment operations.
|
/// Visitor for text segment operations.
|
||||||
@ -680,123 +549,3 @@ impl<'a> LayoutSink for TraceSink<'a> {
|
|||||||
self.0.string("\n");
|
self.0.string("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GlyphMetrics {
|
|
||||||
fn char_width(&self, ch: char) -> i16;
|
|
||||||
fn line_height(&self) -> i16;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GlyphMetrics for Font {
|
|
||||||
fn char_width(&self, ch: char) -> i16 {
|
|
||||||
Font::char_width(*self, ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn line_height(&self) -> i16 {
|
|
||||||
Font::line_height(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: rename to `LineSpan`?
|
|
||||||
/// Carries info about the content that was processed
|
|
||||||
/// on the current line.
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct Span {
|
|
||||||
/// How many characters from the input text this span is laying out.
|
|
||||||
pub length: usize,
|
|
||||||
/// How many chars from the input text should we skip before fitting the
|
|
||||||
/// next span?
|
|
||||||
pub skip_next_chars: usize,
|
|
||||||
/// By how much to offset the cursor after this span. If the vertical offset
|
|
||||||
/// is bigger than zero, it means we are breaking the line.
|
|
||||||
pub advance: Offset,
|
|
||||||
/// If we are breaking the line, should we insert a hyphen right after this
|
|
||||||
/// span to indicate a word-break?
|
|
||||||
pub insert_hyphen_before_line_break: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Span {
|
|
||||||
fn fit_horizontally(
|
|
||||||
text: &str,
|
|
||||||
max_width: i16,
|
|
||||||
text_font: impl GlyphMetrics,
|
|
||||||
breaking: LineBreaking,
|
|
||||||
) -> Self {
|
|
||||||
const ASCII_LF: char = '\n';
|
|
||||||
const ASCII_CR: char = '\r';
|
|
||||||
const ASCII_SPACE: char = ' ';
|
|
||||||
const ASCII_HYPHEN: char = '-';
|
|
||||||
|
|
||||||
fn is_whitespace(ch: char) -> bool {
|
|
||||||
ch == ASCII_SPACE || ch == ASCII_LF || ch == ASCII_CR
|
|
||||||
}
|
|
||||||
|
|
||||||
let hyphen_width = text_font.char_width(ASCII_HYPHEN);
|
|
||||||
|
|
||||||
// The span we return in case the line has to break. We mutate it in the
|
|
||||||
// possible break points, and its initial value is returned in case no text
|
|
||||||
// at all is fitting the constraints: zero length, zero width, full line
|
|
||||||
// break.
|
|
||||||
let mut line = Self {
|
|
||||||
length: 0,
|
|
||||||
advance: Offset::y(text_font.line_height()),
|
|
||||||
insert_hyphen_before_line_break: false,
|
|
||||||
skip_next_chars: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut span_width = 0;
|
|
||||||
let mut found_any_whitespace = false;
|
|
||||||
|
|
||||||
let mut char_indices_iter = text.char_indices().peekable();
|
|
||||||
// Iterating manually because we need a reference to the iterator inside the
|
|
||||||
// loop.
|
|
||||||
while let Some((i, ch)) = char_indices_iter.next() {
|
|
||||||
let char_width = text_font.char_width(ch);
|
|
||||||
|
|
||||||
// Consider if we could be breaking the line at this position.
|
|
||||||
if is_whitespace(ch) {
|
|
||||||
// Break before the whitespace, without hyphen.
|
|
||||||
line.length = i;
|
|
||||||
line.advance.x = span_width;
|
|
||||||
line.insert_hyphen_before_line_break = false;
|
|
||||||
line.skip_next_chars = 1;
|
|
||||||
if ch == ASCII_CR {
|
|
||||||
// We'll be breaking the line, but advancing the cursor only by a half of the
|
|
||||||
// regular line height.
|
|
||||||
line.advance.y = text_font.line_height() / 2;
|
|
||||||
}
|
|
||||||
if ch == ASCII_LF || ch == ASCII_CR {
|
|
||||||
// End of line, break immediately.
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
found_any_whitespace = true;
|
|
||||||
} else if span_width + char_width > max_width {
|
|
||||||
// Cannot fit on this line. Return the last breakpoint.
|
|
||||||
return line;
|
|
||||||
} else {
|
|
||||||
let have_space_for_break = span_width + char_width + hyphen_width <= max_width;
|
|
||||||
let can_break_word = matches!(breaking, LineBreaking::BreakWordsAndInsertHyphen)
|
|
||||||
|| !found_any_whitespace;
|
|
||||||
if have_space_for_break && can_break_word {
|
|
||||||
// Break after this character, append hyphen.
|
|
||||||
line.length = match char_indices_iter.peek() {
|
|
||||||
Some((idx, _)) => *idx,
|
|
||||||
None => text.len(),
|
|
||||||
};
|
|
||||||
line.advance.x = span_width + char_width;
|
|
||||||
line.insert_hyphen_before_line_break = true;
|
|
||||||
line.skip_next_chars = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span_width += char_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The whole text is fitting on the current line.
|
|
||||||
Self {
|
|
||||||
length: text.len(),
|
|
||||||
advance: Offset::x(span_width),
|
|
||||||
insert_hyphen_before_line_break: false,
|
|
||||||
skip_next_chars: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ mod changing_text;
|
|||||||
mod common;
|
mod common;
|
||||||
mod flow;
|
mod flow;
|
||||||
mod flow_pages;
|
mod flow_pages;
|
||||||
mod flow_pages_poc_helpers;
|
mod flow_pages_helpers;
|
||||||
mod frame;
|
mod frame;
|
||||||
mod hold_to_confirm;
|
mod hold_to_confirm;
|
||||||
mod homescreen;
|
mod homescreen;
|
||||||
|
Loading…
Reference in New Issue
Block a user