mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-14 03:30:02 +00:00
refactor(core/rust): drop ui::macros
removing inttostr!, build_string!, and relocating include_res!
This commit is contained in:
parent
8134490e2e
commit
da37bce59d
@ -14,7 +14,6 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::layout::{LayoutFit, TextLayout, TextStyle};
|
||||
use heapless::String;
|
||||
|
||||
/// Used as an upper bound of number of different styles we may render on single
|
||||
/// page.
|
||||
@ -656,7 +655,7 @@ where
|
||||
color: Color,
|
||||
target: &mut impl Renderer<'s>,
|
||||
) {
|
||||
let numeral = build_string!(10, inttostr!(n as u8 + 1), ".");
|
||||
let numeral = uformat!("{}.", n + 1);
|
||||
shape::Text::new(base_point, numeral.as_str())
|
||||
.with_font(Font::NORMAL)
|
||||
.with_fg(color)
|
||||
|
@ -1,25 +0,0 @@
|
||||
#[allow(unused_macros)] // T1 doesn't use icons (yet)
|
||||
macro_rules! include_res {
|
||||
($filename:expr) => {
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/ui/", $filename))
|
||||
};
|
||||
}
|
||||
|
||||
/// Concatenates arbitrary amount of slices into a String.
|
||||
macro_rules! build_string {
|
||||
($max:expr, $($string:expr),+) => {
|
||||
{
|
||||
let mut new_string = String::<$max>::new();
|
||||
$(unwrap!(new_string.push_str($string));)+
|
||||
new_string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms integer into string slice. For example for printing.
|
||||
#[allow(unused_macros)] // not used in TT UI
|
||||
macro_rules! inttostr {
|
||||
($int:expr) => {{
|
||||
unwrap!(heapless::String::<10>::try_from($int)).as_str()
|
||||
}};
|
||||
}
|
@ -1,6 +1,3 @@
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
|
||||
pub mod animation;
|
||||
#[cfg(feature = "micropython")]
|
||||
pub mod backlight;
|
||||
@ -14,7 +11,6 @@ pub mod flow;
|
||||
pub mod geometry;
|
||||
pub mod lerp;
|
||||
pub mod shape;
|
||||
#[macro_use]
|
||||
pub mod util;
|
||||
|
||||
pub mod layout;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
|
||||
use crate::strutil::TString;
|
||||
use crate::ui::util::include_res;
|
||||
|
||||
|
||||
const ICON_APPLE: &[u8] = include_res!("model_mercury/res/fido/icon_apple.toif");
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
|
||||
use crate::strutil::TString;
|
||||
use crate::ui::util::include_res;
|
||||
|
||||
<%
|
||||
icons: list[tuple[str, str]] = []
|
||||
|
@ -9,12 +9,11 @@ use crate::{
|
||||
event::SwipeEvent,
|
||||
geometry::{Alignment, Alignment2D, Insets, Offset, Rect},
|
||||
model_mercury::component::Footer,
|
||||
shape,
|
||||
shape::Renderer,
|
||||
shape::{self, Renderer},
|
||||
util,
|
||||
},
|
||||
};
|
||||
use heapless::{String, Vec};
|
||||
use heapless::Vec;
|
||||
|
||||
const MAX_WORDS: usize = 33; // super-shamir has 33 words, all other have less
|
||||
const ANIMATION_DURATION_MS: Duration = Duration::from_millis(166);
|
||||
@ -158,7 +157,7 @@ impl<'a> Component for ShareWords<'a> {
|
||||
.text_font
|
||||
.visible_text_height("1"),
|
||||
);
|
||||
let ordinal = build_string!(3, inttostr!(ordinal_val), ".");
|
||||
let ordinal = uformat!("{}.", ordinal_val);
|
||||
shape::Text::new(ordinal_pos, &ordinal)
|
||||
.with_font(theme::TEXT_SUB_GREY_LIGHT.text_font)
|
||||
.with_fg(theme::GREY)
|
||||
@ -204,8 +203,7 @@ impl<'a> crate::trace::Trace for ShareWords<'a> {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("ShareWords");
|
||||
let word = &self.share_words[self.page_index as usize];
|
||||
let content =
|
||||
word.map(|w| build_string!(50, inttostr!(self.page_index as u8 + 1), ". ", w, "\n"));
|
||||
let content = word.map(|w| uformat!("{}. {}\n", self.page_index + 1, w));
|
||||
t.string("screen_content", content.as_str().into());
|
||||
t.int("page_count", self.share_words.len() as i64)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::ui::{
|
||||
component::{text::TextStyle, LineBreaking::BreakWordsNoHyphen},
|
||||
constant::{HEIGHT, WIDTH},
|
||||
display::{Color, Font},
|
||||
geometry::{Offset, Point, Rect},
|
||||
geometry::{Offset, Point, Rect}, util::include_res,
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
|
@ -9,8 +9,8 @@ use crate::{
|
||||
text::{layout::Chunks, LineBreaking, PageBreaking, TextStyle},
|
||||
FixedHeightBar,
|
||||
},
|
||||
display::{Color, Font, Icon},
|
||||
geometry::Insets,
|
||||
display::{Color, Font},
|
||||
geometry::Insets, util::include_icon,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
display::Font,
|
||||
geometry::{Alignment, Point, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
util::long_line_content_with_ellipsis,
|
||||
use crate::{
|
||||
strutil::ShortString,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
display::Font,
|
||||
geometry::{Alignment, Point, Rect},
|
||||
shape::{self, Renderer},
|
||||
util::long_line_content_with_ellipsis,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{common, theme};
|
||||
@ -12,9 +14,9 @@ use super::{common, theme};
|
||||
/// Component that allows for "allocating" a standalone line of text anywhere
|
||||
/// on the screen and updating it arbitrarily - without affecting the rest
|
||||
/// and without being affected by other components.
|
||||
pub struct ChangingTextLine<T> {
|
||||
pub struct ChangingTextLine {
|
||||
pad: Pad,
|
||||
text: T,
|
||||
text: ShortString,
|
||||
font: Font,
|
||||
/// Whether to show the text. Can be disabled.
|
||||
show_content: bool,
|
||||
@ -25,11 +27,10 @@ pub struct ChangingTextLine<T> {
|
||||
text_at_the_top: bool,
|
||||
}
|
||||
|
||||
impl<T> ChangingTextLine<T>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
pub fn new(text: T, font: Font, alignment: Alignment) -> Self {
|
||||
impl ChangingTextLine {
|
||||
pub fn new(text: &str, font: Font, alignment: Alignment, max_len: usize) -> Self {
|
||||
let text = unwrap!(ShortString::try_from(text));
|
||||
debug_assert!(text.capacity() >= max_len);
|
||||
Self {
|
||||
pad: Pad::with_background(theme::BG),
|
||||
text,
|
||||
@ -41,12 +42,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn center_mono(text: T) -> Self {
|
||||
Self::new(text, Font::MONO, Alignment::Center)
|
||||
pub fn center_mono(text: &str, max_len: usize) -> Self {
|
||||
Self::new(text, Font::MONO, Alignment::Center, max_len)
|
||||
}
|
||||
|
||||
pub fn center_bold(text: T) -> Self {
|
||||
Self::new(text, Font::BOLD_UPPER, Alignment::Center)
|
||||
pub fn center_bold(text: &str, max_len: usize) -> Self {
|
||||
Self::new(text, Font::BOLD_UPPER, Alignment::Center, max_len)
|
||||
}
|
||||
|
||||
/// Not showing ellipsis at the beginning of longer texts.
|
||||
@ -62,13 +63,14 @@ where
|
||||
}
|
||||
|
||||
/// Update the text to be displayed in the line.
|
||||
pub fn update_text(&mut self, text: T) {
|
||||
self.text = text;
|
||||
pub fn update_text(&mut self, text: &str) {
|
||||
self.text.clear();
|
||||
unwrap!(self.text.push_str(text));
|
||||
}
|
||||
|
||||
/// Get current text.
|
||||
pub fn get_text(&self) -> &T {
|
||||
&self.text
|
||||
pub fn get_text(&self) -> &str {
|
||||
self.text.as_str()
|
||||
}
|
||||
|
||||
/// Changing the current font
|
||||
@ -155,21 +157,14 @@ where
|
||||
// Creating the notion of motion by shifting the text left and right with
|
||||
// each new text character.
|
||||
// (So that it is apparent for the user that the text is changing.)
|
||||
let x_offset = if self.text.as_ref().len() % 2 == 0 {
|
||||
0
|
||||
} else {
|
||||
2
|
||||
};
|
||||
let x_offset = if self.text.len() % 2 == 0 { 0 } else { 2 };
|
||||
|
||||
let baseline = Point::new(self.pad.area.x0 + x_offset, self.y_baseline());
|
||||
common::display_left(baseline, &text_to_display, self.font);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Component for ChangingTextLine<T>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
impl Component for ChangingTextLine {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
strutil::TString,
|
||||
strutil::{ShortString, TString},
|
||||
translations::TR,
|
||||
trezorhal::random,
|
||||
ui::{
|
||||
@ -270,7 +270,7 @@ impl ChoiceFactory for ChoiceFactoryPassphrase {
|
||||
/// Component for entering a passphrase.
|
||||
pub struct PassphraseEntry {
|
||||
choice_page: ChoicePage<ChoiceFactoryPassphrase, PassphraseAction>,
|
||||
passphrase_dots: Child<ChangingTextLine<String<MAX_PASSPHRASE_LENGTH>>>,
|
||||
passphrase_dots: Child<ChangingTextLine>,
|
||||
show_plain_passphrase: bool,
|
||||
show_last_digit: bool,
|
||||
textbox: TextBox<MAX_PASSPHRASE_LENGTH>,
|
||||
@ -283,7 +283,7 @@ impl PassphraseEntry {
|
||||
choice_page: ChoicePage::new(ChoiceFactoryPassphrase::new(ChoiceCategory::Menu, true))
|
||||
.with_carousel(true)
|
||||
.with_initial_page_counter(random_menu_position()),
|
||||
passphrase_dots: Child::new(ChangingTextLine::center_mono(String::new())),
|
||||
passphrase_dots: Child::new(ChangingTextLine::center_mono("", MAX_PASSPHRASE_LENGTH)),
|
||||
show_plain_passphrase: false,
|
||||
show_last_digit: false,
|
||||
textbox: TextBox::empty(),
|
||||
@ -298,7 +298,7 @@ impl PassphraseEntry {
|
||||
unwrap!(String::try_from(""))
|
||||
} else {
|
||||
// Showing asterisks and possibly the last digit.
|
||||
let mut dots: String<MAX_PASSPHRASE_LENGTH> = String::new();
|
||||
let mut dots: ShortString = String::new();
|
||||
for _ in 0..self.textbox.len() - 1 {
|
||||
unwrap!(dots.push('*'));
|
||||
}
|
||||
@ -311,7 +311,7 @@ impl PassphraseEntry {
|
||||
dots
|
||||
};
|
||||
self.passphrase_dots.mutate(ctx, |ctx, passphrase_dots| {
|
||||
passphrase_dots.update_text(text_to_show);
|
||||
passphrase_dots.update_text(&text_to_show);
|
||||
passphrase_dots.request_complete_repaint(ctx);
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
strutil::TString,
|
||||
strutil::{ShortString, TString},
|
||||
translations::TR,
|
||||
trezorhal::random,
|
||||
ui::{
|
||||
@ -132,8 +132,8 @@ impl ChoiceFactory for ChoiceFactoryPIN {
|
||||
/// Component for entering a PIN.
|
||||
pub struct PinEntry<'a> {
|
||||
choice_page: ChoicePage<ChoiceFactoryPIN, PinAction>,
|
||||
header_line: Child<ChangingTextLine<String<MAX_PIN_LENGTH>>>,
|
||||
pin_line: Child<ChangingTextLine<String<MAX_PIN_LENGTH>>>,
|
||||
header_line: Child<ChangingTextLine>,
|
||||
pin_line: Child<ChangingTextLine>,
|
||||
prompt: TString<'a>,
|
||||
subprompt: TString<'a>,
|
||||
/// Whether we already show the "real" prompt (not the warning).
|
||||
@ -151,20 +151,13 @@ impl<'a> PinEntry<'a> {
|
||||
// any button click.)
|
||||
let show_subprompt = !subprompt.is_empty();
|
||||
let (showing_real_prompt, header_line_content, pin_line_content) = if show_subprompt {
|
||||
(
|
||||
false,
|
||||
TR::pin__title_wrong_pin.map_translated(|t| unwrap!(String::try_from(t))),
|
||||
subprompt.map(|s| unwrap!(String::try_from(s))),
|
||||
)
|
||||
(false, TR::pin__title_wrong_pin.into(), subprompt)
|
||||
} else {
|
||||
(
|
||||
true,
|
||||
prompt.map(|s| unwrap!(String::try_from(s))),
|
||||
unwrap!(String::try_from(EMPTY_PIN_STR)),
|
||||
)
|
||||
(true, prompt, EMPTY_PIN_STR.into())
|
||||
};
|
||||
|
||||
let mut pin_line = ChangingTextLine::center_bold(pin_line_content).without_ellipsis();
|
||||
let mut pin_line = pin_line_content
|
||||
.map(|s| ChangingTextLine::center_bold(s, MAX_PIN_LENGTH).without_ellipsis());
|
||||
if show_subprompt {
|
||||
pin_line.update_font(Font::NORMAL);
|
||||
}
|
||||
@ -175,7 +168,8 @@ impl<'a> PinEntry<'a> {
|
||||
.with_initial_page_counter(get_random_digit_position())
|
||||
.with_carousel(true),
|
||||
header_line: Child::new(
|
||||
ChangingTextLine::center_bold(header_line_content)
|
||||
header_line_content
|
||||
.map(|s| ChangingTextLine::center_bold(s, MAX_PIN_LENGTH))
|
||||
.without_ellipsis()
|
||||
.with_text_at_the_top(),
|
||||
),
|
||||
@ -209,7 +203,7 @@ impl<'a> PinEntry<'a> {
|
||||
unwrap!(String::try_from(self.pin()))
|
||||
} else {
|
||||
// Showing asterisks and possibly the last digit.
|
||||
let mut dots: String<MAX_PIN_LENGTH> = String::new();
|
||||
let mut dots = ShortString::new();
|
||||
for _ in 0..self.textbox.len() - 1 {
|
||||
unwrap!(dots.push('*'));
|
||||
}
|
||||
@ -224,7 +218,7 @@ impl<'a> PinEntry<'a> {
|
||||
|
||||
self.pin_line.mutate(ctx, |ctx, pin_line| {
|
||||
pin_line.update_font(used_font);
|
||||
pin_line.update_text(pin_line_text);
|
||||
pin_line.update_text(&pin_line_text);
|
||||
pin_line.request_complete_repaint(ctx);
|
||||
});
|
||||
}
|
||||
@ -232,7 +226,7 @@ impl<'a> PinEntry<'a> {
|
||||
/// Showing the real prompt instead of WRONG PIN
|
||||
fn show_prompt(&mut self, ctx: &mut EventCtx) {
|
||||
self.header_line.mutate(ctx, |ctx, header_line| {
|
||||
header_line.update_text(self.prompt.map(|s| unwrap!(String::try_from(s))));
|
||||
self.prompt.map(|s| header_line.update_text(s));
|
||||
header_line.request_complete_repaint(ctx);
|
||||
});
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ enum WordlistAction {
|
||||
}
|
||||
|
||||
const MAX_WORD_LENGTH: usize = 10;
|
||||
const LINE_CAPACITY: usize = MAX_WORD_LENGTH + 1;
|
||||
|
||||
/// Offer words when there will be fewer of them than this
|
||||
const OFFER_WORDS_THRESHOLD: usize = 10;
|
||||
@ -156,7 +157,7 @@ impl ChoiceFactory for ChoiceFactoryWordlist {
|
||||
/// Component for entering a mnemonic from a wordlist - BIP39 or SLIP39.
|
||||
pub struct WordlistEntry {
|
||||
choice_page: ChoicePage<ChoiceFactoryWordlist, WordlistAction>,
|
||||
chosen_letters: Child<ChangingTextLine<String<{ MAX_WORD_LENGTH + 1 }>>>,
|
||||
chosen_letters: Child<ChangingTextLine>,
|
||||
textbox: TextBox<MAX_WORD_LENGTH>,
|
||||
offer_words: bool,
|
||||
wordlist_type: WordlistType,
|
||||
@ -174,9 +175,7 @@ impl WordlistEntry {
|
||||
.with_incomplete(true)
|
||||
.with_carousel(true)
|
||||
.with_initial_page_counter(get_random_position(choices_count)),
|
||||
chosen_letters: Child::new(ChangingTextLine::center_mono(unwrap!(String::try_from(
|
||||
PROMPT
|
||||
)))),
|
||||
chosen_letters: Child::new(ChangingTextLine::center_mono(PROMPT, LINE_CAPACITY)),
|
||||
textbox: TextBox::empty(),
|
||||
offer_words: false,
|
||||
wordlist_type,
|
||||
@ -196,9 +195,7 @@ impl WordlistEntry {
|
||||
choice_page: ChoicePage::new(choices)
|
||||
.with_incomplete(true)
|
||||
.with_initial_page_counter(1),
|
||||
chosen_letters: Child::new(ChangingTextLine::center_mono(unwrap!(String::try_from(
|
||||
word
|
||||
)))),
|
||||
chosen_letters: Child::new(ChangingTextLine::center_mono(word, LINE_CAPACITY)),
|
||||
textbox: TextBox::new(unwrap!(String::try_from(word))),
|
||||
offer_words: false,
|
||||
wordlist_type,
|
||||
@ -263,9 +260,9 @@ impl WordlistEntry {
|
||||
|
||||
/// Reflects currently chosen letters in the textbox.
|
||||
fn update_chosen_letters(&mut self, ctx: &mut EventCtx) {
|
||||
let text = build_string!({ MAX_WORD_LENGTH + 1 }, self.textbox.content(), PROMPT);
|
||||
let text = uformat!("{}{}", self.textbox.content(), PROMPT);
|
||||
self.chosen_letters.mutate(ctx, |ctx, chosen_letters| {
|
||||
chosen_letters.update_text(text);
|
||||
chosen_letters.update_text(&text);
|
||||
chosen_letters.request_complete_repaint(ctx);
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
strutil::StringType,
|
||||
strutil::{ShortString, StringType, TString},
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{
|
||||
@ -8,12 +8,12 @@ use crate::{
|
||||
},
|
||||
display::Font,
|
||||
geometry::{Alignment, Offset, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
shape::{self, Renderer},
|
||||
},
|
||||
};
|
||||
|
||||
use heapless::{String, Vec};
|
||||
use heapless::Vec;
|
||||
use ufmt::uwrite;
|
||||
|
||||
use super::{common::display_left, scrollbar::SCROLLBAR_SPACE, theme, ScrollBar};
|
||||
|
||||
@ -72,15 +72,10 @@ where
|
||||
word_screens + 1
|
||||
}
|
||||
|
||||
fn get_final_text(&self) -> String<50> {
|
||||
fn get_final_text(&self) -> ShortString {
|
||||
TR::share_words__wrote_down_all.map_translated(|wrote_down_all| {
|
||||
TR::share_words__words_in_order.map_translated(|in_order| {
|
||||
build_string!(
|
||||
50,
|
||||
wrote_down_all,
|
||||
inttostr!(self.share_words.len() as u8),
|
||||
in_order
|
||||
)
|
||||
uformat!("{}{}{}", wrote_down_all, self.share_words.len(), in_order)
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -124,7 +119,7 @@ where
|
||||
}
|
||||
let word = &self.share_words[index];
|
||||
let baseline = self.area.top_left() + Offset::y(y_offset);
|
||||
let ordinal = build_string!(5, inttostr!(index as u8 + 1), ".");
|
||||
let ordinal = uformat!("{}.", index + 1);
|
||||
display_left(baseline + Offset::x(NUMBER_X_OFFSET), &ordinal, NUMBER_FONT);
|
||||
display_left(baseline + Offset::x(WORD_X_OFFSET), word, WORD_FONT);
|
||||
}
|
||||
@ -142,7 +137,7 @@ where
|
||||
}
|
||||
let word = &self.share_words[index];
|
||||
let baseline = self.area.top_left() + Offset::y(y_offset);
|
||||
let ordinal = build_string!(5, inttostr!(index as u8 + 1), ".");
|
||||
let ordinal = uformat!("{}.", index + 1);
|
||||
|
||||
shape::Text::new(baseline + Offset::x(NUMBER_X_OFFSET), &ordinal)
|
||||
.with_font(NUMBER_FONT)
|
||||
@ -230,16 +225,14 @@ where
|
||||
let content = if self.is_final_page() {
|
||||
self.get_final_text()
|
||||
} else {
|
||||
let mut content = String::<50>::new();
|
||||
let mut content = ShortString::new();
|
||||
for i in 0..WORDS_PER_PAGE {
|
||||
let index = self.word_index() + i;
|
||||
if index >= self.share_words.len() {
|
||||
break;
|
||||
}
|
||||
let word = &self.share_words[index];
|
||||
let current_line =
|
||||
build_string!(50, inttostr!(index as u8 + 1), ". ", word.as_ref(), "\n");
|
||||
unwrap!(content.push_str(¤t_line));
|
||||
let word: TString = self.share_words[index].clone().into();
|
||||
unwrap!(uwrite!(content, "{}. {}\n", index + 1, word));
|
||||
}
|
||||
content
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::ui::{
|
||||
component::text::TextStyle,
|
||||
display::{toif::Icon, Color, Font},
|
||||
display::{Color, Font},
|
||||
util::include_icon,
|
||||
};
|
||||
|
||||
pub use super::super::theme::{BLACK, WHITE};
|
||||
|
@ -3,8 +3,9 @@ use crate::ui::{
|
||||
text::{layout::Chunks, TextStyle},
|
||||
LineBreaking, PageBreaking,
|
||||
},
|
||||
display::{toif::Icon, Color, Font},
|
||||
display::{Color, Font},
|
||||
geometry::Offset,
|
||||
util::include_icon,
|
||||
};
|
||||
|
||||
use num_traits::FromPrimitive;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
|
||||
use crate::strutil::TString;
|
||||
use crate::ui::util::include_res;
|
||||
|
||||
|
||||
const ICON_APPLE: &[u8] = include_res!("model_tt/res/fido/icon_apple.toif");
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
|
||||
use crate::strutil::TString;
|
||||
use crate::ui::util::include_res;
|
||||
|
||||
<%
|
||||
icons: list[tuple[str, str]] = []
|
||||
|
@ -6,7 +6,7 @@ use crate::ui::{
|
||||
model_tt::{
|
||||
component::{ButtonStyle, ButtonStyleSheet, ResultStyle},
|
||||
theme::{BLACK, FG, GREY_DARK, GREY_LIGHT, WHITE},
|
||||
},
|
||||
}, util::include_res,
|
||||
};
|
||||
|
||||
pub const BLD_BG: Color = Color::rgb(0x00, 0x1E, 0xAD);
|
||||
|
@ -8,8 +8,9 @@ use crate::{
|
||||
text::{layout::Chunks, LineBreaking, PageBreaking, TextStyle},
|
||||
FixedHeightBar,
|
||||
},
|
||||
display::{Color, Font, Icon},
|
||||
display::{Color, Font},
|
||||
geometry::{Insets, Offset},
|
||||
util::{include_icon, include_res},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -155,20 +155,29 @@ pub fn long_line_content_with_ellipsis(
|
||||
let remaining_available_width = available_width - ellipsis_width;
|
||||
let chars_from_right = text_font.longest_suffix(remaining_available_width, text);
|
||||
|
||||
build_string!(50, ellipsis, &text[text.len() - chars_from_right..])
|
||||
let mut s = ShortString::new();
|
||||
unwrap!(s.push_str(ellipsis));
|
||||
unwrap!(s.push_str(&text[text.len() - chars_from_right..]));
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
/// Create the `Icon` constant with given name and path.
|
||||
/// Possibly users can supply `true` as a third argument and this
|
||||
/// will signify that the icon has empty right column.
|
||||
macro_rules! include_icon {
|
||||
($name:ident, $path:expr, empty_right_col = $empty:expr) => {
|
||||
pub const $name: Icon = if $empty {
|
||||
Icon::debug_named(include_res!($path), stringify!($name)).with_empty_right_column()
|
||||
pub const $name: $crate::ui::display::toif::Icon = if $empty {
|
||||
$crate::ui::display::toif::Icon::debug_named(
|
||||
$crate::ui::util::include_res!($path),
|
||||
stringify!($name),
|
||||
)
|
||||
.with_empty_right_column()
|
||||
} else {
|
||||
Icon::debug_named(include_res!($path), stringify!($name))
|
||||
$crate::ui::display::toif::Icon::debug_named(
|
||||
$crate::ui::util::include_res!($path),
|
||||
stringify!($name),
|
||||
)
|
||||
};
|
||||
};
|
||||
// No empty right column by default.
|
||||
@ -176,6 +185,14 @@ macro_rules! include_icon {
|
||||
include_icon!($name, $path, empty_right_col = false);
|
||||
};
|
||||
}
|
||||
pub(crate) use include_icon;
|
||||
|
||||
macro_rules! include_res {
|
||||
($filename:expr) => {
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/ui/", $filename))
|
||||
};
|
||||
}
|
||||
pub(crate) use include_res;
|
||||
|
||||
pub const SLIDE_DURATION_MS: Duration = Duration::from_millis(333);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user