mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-17 11:58:13 +00:00
chore(core): remove legacy drawing code (rust)
[no changelog]
This commit is contained in:
parent
a4da695430
commit
2481f768f8
@ -342,23 +342,10 @@ fn generate_trezorhal_bindings() {
|
||||
.allowlist_function("translations_erase")
|
||||
.allowlist_function("translations_area_bytesize")
|
||||
// display
|
||||
.allowlist_function("display_clear")
|
||||
.allowlist_function("display_offset")
|
||||
.allowlist_function("display_refresh")
|
||||
.allowlist_function("display_backlight")
|
||||
.allowlist_function("display_text")
|
||||
.allowlist_function("display_text_render_buffer")
|
||||
.allowlist_function("display_pixeldata")
|
||||
.allowlist_function("display_pixeldata_dirty")
|
||||
.allowlist_function("display_set_window")
|
||||
.allowlist_function("display_sync")
|
||||
.allowlist_function("display_get_fb_addr")
|
||||
.allowlist_function("display_get_wr_addr")
|
||||
.allowlist_var("DISPLAY_DATA_ADDRESS")
|
||||
.allowlist_var("DISPLAY_FRAMEBUFFER_WIDTH")
|
||||
.allowlist_var("DISPLAY_FRAMEBUFFER_HEIGHT")
|
||||
.allowlist_var("DISPLAY_FRAMEBUFFER_OFFSET_X")
|
||||
.allowlist_var("DISPLAY_FRAMEBUFFER_OFFSET_Y")
|
||||
.allowlist_function("display_set_backlight")
|
||||
.allowlist_function("display_get_backlight")
|
||||
.allowlist_function("display_wait_for_sync")
|
||||
.allowlist_var("DISPLAY_RESX")
|
||||
.allowlist_var("DISPLAY_RESY")
|
||||
.allowlist_type("display_fb_info_t")
|
||||
|
@ -205,7 +205,6 @@ impl BitBltFill {
|
||||
}
|
||||
|
||||
/// Fills a rectangle on the display with the specified color.
|
||||
#[cfg(feature = "new_rendering")]
|
||||
pub fn display_fill(&self) {
|
||||
assert!(self.bitblt.dst_x + self.bitblt.width <= ffi::DISPLAY_RESX as u16);
|
||||
assert!(self.bitblt.dst_y + self.bitblt.height <= ffi::DISPLAY_RESY as u16);
|
||||
@ -426,7 +425,6 @@ impl<'a> BitBltCopy<'a> {
|
||||
/// Copies a part of the source bitmap to the display.
|
||||
///
|
||||
/// - The source bitmap uses the RGB565 format.
|
||||
#[cfg(feature = "new_rendering")]
|
||||
pub fn display_copy(&self) {
|
||||
assert!(self.bitblt.dst_x + self.bitblt.width <= ffi::DISPLAY_RESX as u16);
|
||||
assert!(self.bitblt.dst_y + self.bitblt.height <= ffi::DISPLAY_RESY as u16);
|
||||
|
@ -1,101 +0,0 @@
|
||||
use core::{
|
||||
ops::{Deref, DerefMut},
|
||||
ptr,
|
||||
};
|
||||
|
||||
use super::ffi;
|
||||
|
||||
pub use ffi::TEXT_BUFFER_HEIGHT;
|
||||
|
||||
macro_rules! buffer_wrapper {
|
||||
($rust_name: ident, $type: ident, $get: ident, $free: ident) => {
|
||||
pub struct $rust_name(ptr::NonNull<ffi::$type>);
|
||||
|
||||
impl $rust_name {
|
||||
pub fn get() -> Self {
|
||||
unsafe {
|
||||
let ptr = ffi::$get(false);
|
||||
Self(unwrap!(ptr::NonNull::new(ptr)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cleared() -> Self {
|
||||
unsafe {
|
||||
let ptr = ffi::$get(true);
|
||||
Self(unwrap!(ptr::NonNull::new(ptr)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for $rust_name {
|
||||
type Target = ffi::$type;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// SAFETY: The lifetime of the pointer is 'static and the C API
|
||||
// promises that we are the sole owner.
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for $rust_name {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
// SAFETY: The lifetime of the pointer is 'static and the C API
|
||||
// promises that we are the sole owner, and we have borrowed mutably.
|
||||
unsafe { self.0.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $rust_name {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::$free(self.0.as_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
buffer_wrapper!(
|
||||
BufferLine16bpp,
|
||||
buffer_line_16bpp_t,
|
||||
buffers_get_line_16bpp,
|
||||
buffers_free_line_16bpp
|
||||
);
|
||||
buffer_wrapper!(
|
||||
BufferLine4bpp,
|
||||
buffer_line_4bpp_t,
|
||||
buffers_get_line_4bpp,
|
||||
buffers_free_line_4bpp
|
||||
);
|
||||
buffer_wrapper!(
|
||||
BufferText,
|
||||
buffer_text_t,
|
||||
buffers_get_text,
|
||||
buffers_free_text
|
||||
);
|
||||
buffer_wrapper!(
|
||||
BufferBlurring,
|
||||
buffer_blurring_t,
|
||||
buffers_get_blurring,
|
||||
buffers_free_blurring
|
||||
);
|
||||
buffer_wrapper!(
|
||||
BufferBlurringTotals,
|
||||
buffer_blurring_totals_t,
|
||||
buffers_get_blurring_totals,
|
||||
buffers_free_blurring_totals
|
||||
);
|
||||
#[cfg(feature = "jpeg")]
|
||||
buffer_wrapper!(
|
||||
BufferJpeg,
|
||||
buffer_jpeg_t,
|
||||
buffers_get_jpeg,
|
||||
buffers_free_jpeg
|
||||
);
|
||||
#[cfg(feature = "jpeg")]
|
||||
buffer_wrapper!(
|
||||
BufferJpegWork,
|
||||
buffer_jpeg_work_t,
|
||||
buffers_get_jpeg_work,
|
||||
buffers_free_jpeg_work
|
||||
);
|
@ -1,52 +1,12 @@
|
||||
use super::ffi;
|
||||
use core::{ops::DerefMut, ptr};
|
||||
use cty::c_int;
|
||||
|
||||
use crate::trezorhal::buffers::BufferText;
|
||||
#[cfg(feature = "xframebuffer")]
|
||||
use core::ptr;
|
||||
|
||||
pub use ffi::{DISPLAY_RESX, DISPLAY_RESY};
|
||||
|
||||
#[cfg(feature = "framebuffer")]
|
||||
pub use ffi::{
|
||||
DISPLAY_FRAMEBUFFER_OFFSET_X, DISPLAY_FRAMEBUFFER_OFFSET_Y, DISPLAY_FRAMEBUFFER_WIDTH,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "framebuffer", not(feature = "framebuffer32bit")))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FrameBuffer(pub *mut u16);
|
||||
|
||||
#[cfg(all(feature = "framebuffer", feature = "framebuffer32bit"))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FrameBuffer(pub *mut u32);
|
||||
|
||||
pub fn backlight(val: i32) -> i32 {
|
||||
unsafe { ffi::display_backlight(val) }
|
||||
}
|
||||
|
||||
pub fn text(baseline_x: i16, baseline_y: i16, text: &str, font: i32, fgcolor: u16, bgcolor: u16) {
|
||||
unsafe {
|
||||
ffi::display_text(
|
||||
baseline_x.into(),
|
||||
baseline_y.into(),
|
||||
text.as_ptr() as _,
|
||||
text.len() as _,
|
||||
font,
|
||||
fgcolor,
|
||||
bgcolor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_into_buffer(text: &str, font: i32, buffer: &mut BufferText, x_offset: i16) {
|
||||
unsafe {
|
||||
ffi::display_text_render_buffer(
|
||||
text.as_ptr() as _,
|
||||
text.len() as _,
|
||||
font,
|
||||
buffer.deref_mut(),
|
||||
x_offset.into(),
|
||||
)
|
||||
}
|
||||
unsafe { ffi::display_set_backlight(val) }
|
||||
}
|
||||
|
||||
pub fn text_width(text: &str, font: i32) -> i16 {
|
||||
@ -79,95 +39,10 @@ pub fn text_baseline(font: i32) -> i16 {
|
||||
unsafe { ffi::font_baseline(font).try_into().unwrap_or(i16::MAX) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(all(
|
||||
not(feature = "framebuffer"),
|
||||
feature = "disp_i8080_16bit_dw",
|
||||
not(feature = "disp_i8080_8bit_dw")
|
||||
))]
|
||||
#[allow(unused_variables)]
|
||||
pub fn pixeldata(c: u16) {
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
unsafe {
|
||||
ffi::DISPLAY_DATA_ADDRESS.write_volatile(c);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "framebuffer")]
|
||||
pub fn get_fb_addr() -> FrameBuffer {
|
||||
unsafe { FrameBuffer(ffi::display_get_fb_addr() as _) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(all(not(feature = "framebuffer"), feature = "disp_i8080_8bit_dw"))]
|
||||
#[allow(unused_variables)]
|
||||
pub fn pixeldata(c: u16) {
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
unsafe {
|
||||
ffi::DISPLAY_DATA_ADDRESS.write_volatile((c & 0xff) as u8);
|
||||
ffi::DISPLAY_DATA_ADDRESS.write_volatile((c >> 8) as u8);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(all(feature = "framebuffer", not(feature = "framebuffer32bit")))]
|
||||
pub fn pixel(fb: FrameBuffer, x: i16, y: i16, c: u16) {
|
||||
unsafe {
|
||||
let addr = fb.0.offset(
|
||||
((y as u32 + DISPLAY_FRAMEBUFFER_OFFSET_Y) * DISPLAY_FRAMEBUFFER_WIDTH
|
||||
+ (x as u32 + DISPLAY_FRAMEBUFFER_OFFSET_X)) as isize,
|
||||
);
|
||||
addr.write_volatile(c);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(all(feature = "framebuffer", feature = "framebuffer32bit"))]
|
||||
pub fn pixel(fb: FrameBuffer, x: i16, y: i16, c: u32) {
|
||||
unsafe {
|
||||
let addr = fb.0.offset(
|
||||
((y as u32 + DISPLAY_FRAMEBUFFER_OFFSET_Y) * DISPLAY_FRAMEBUFFER_WIDTH
|
||||
+ (x as u32 + DISPLAY_FRAMEBUFFER_OFFSET_X)) as isize,
|
||||
);
|
||||
addr.write_volatile(c);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(any(
|
||||
feature = "framebuffer",
|
||||
not(any(feature = "disp_i8080_16bit_dw", feature = "disp_i8080_8bit_dw"))
|
||||
))]
|
||||
pub fn pixeldata(c: u16) {
|
||||
unsafe {
|
||||
ffi::display_pixeldata(c);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pixeldata_dirty() {
|
||||
unsafe {
|
||||
ffi::display_pixeldata_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_window(x0: u16, y0: u16, x1: u16, y1: u16) {
|
||||
unsafe {
|
||||
ffi::display_set_window(x0, y0, x1, y1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_offset() -> (i16, i16) {
|
||||
unsafe {
|
||||
let mut x: c_int = 0;
|
||||
let mut y: c_int = 0;
|
||||
ffi::display_offset(ptr::null_mut(), &mut x, &mut y);
|
||||
(x as i16, y as i16)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sync() {
|
||||
#[cfg(not(feature = "framebuffer"))]
|
||||
unsafe {
|
||||
ffi::display_sync();
|
||||
ffi::display_wait_for_sync();
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,12 +52,6 @@ pub fn refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear() {
|
||||
unsafe {
|
||||
ffi::display_clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "xframebuffer")]
|
||||
pub fn get_frame_buffer() -> (&'static mut [u8], usize) {
|
||||
let mut fb_info = ffi::display_fb_info_t {
|
||||
|
@ -1,103 +0,0 @@
|
||||
use super::ffi;
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
pub fn dma2d_setup_const() {
|
||||
unsafe { ffi::dma2d_setup_const() }
|
||||
}
|
||||
pub fn dma2d_setup_4bpp(fg_color: u16, bg_color: u16) {
|
||||
unsafe { ffi::dma2d_setup_4bpp(fg_color, bg_color) }
|
||||
}
|
||||
|
||||
pub fn dma2d_setup_16bpp() {
|
||||
unsafe { ffi::dma2d_setup_16bpp() }
|
||||
}
|
||||
|
||||
pub fn dma2d_setup_4bpp_over_4bpp(fg_color: u16, bg_color: u16, overlay_color: u16) {
|
||||
unsafe { ffi::dma2d_setup_4bpp_over_4bpp(fg_color, bg_color, overlay_color) }
|
||||
}
|
||||
|
||||
pub fn dma2d_setup_4bpp_over_16bpp(overlay_color: u16) {
|
||||
unsafe { ffi::dma2d_setup_4bpp_over_16bpp(overlay_color) }
|
||||
}
|
||||
|
||||
/// Starts dma2d transfer
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee that he:
|
||||
/// 1) doesn't mutate the buffers until the transfer is finished, which is
|
||||
/// guaranteed by calling `dma2d_wait_for_transfer`
|
||||
/// 2) the buffer doesn't get dropped until the transfer is finished
|
||||
/// 3) doesn't call this function while another transfer is running
|
||||
pub unsafe fn dma2d_start(buffer: &[u8], pixels: i16) {
|
||||
unsafe {
|
||||
ffi::dma2d_start(
|
||||
buffer.as_ptr() as _,
|
||||
ffi::display_get_wr_addr() as _,
|
||||
pixels as _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts blending
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee that he:
|
||||
/// 1) doesn't mutate the buffers until the transfer is finished, which is
|
||||
/// guaranteed by calling `dma2d_wait_for_transfer`
|
||||
/// 2) the buffer doesn't get dropped until the transfer is finished
|
||||
/// 3) doesn't call this function while another transfer is running
|
||||
pub unsafe fn dma2d_start_blend(overlay_buffer: &[u8], bg_buffer: &[u8], pixels: i16) {
|
||||
unsafe {
|
||||
ffi::dma2d_start_blend(
|
||||
overlay_buffer.as_ptr() as _,
|
||||
bg_buffer.as_ptr() as _,
|
||||
ffi::display_get_wr_addr() as _,
|
||||
pixels as _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts blending
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee that he:
|
||||
/// 1) doesn't mutate the buffers until the transfer is finished, which is
|
||||
/// guaranteed by calling `dma2d_wait_for_transfer`
|
||||
/// 2) the buffer doesn't get dropped until the transfer is finished
|
||||
/// 3) doesn't call this function while another transfer is running
|
||||
pub unsafe fn dma2d_start_const(color: u16, pixels: i16) {
|
||||
unsafe {
|
||||
ffi::dma2d_start_const(color, ffi::display_get_wr_addr() as _, pixels as _);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "framebuffer")]
|
||||
/// Starts blending
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee that he:
|
||||
/// 1) doesn't mutate the buffers until the transfer is finished, which is
|
||||
/// guaranteed by calling `dma2d_wait_for_transfer`
|
||||
/// 2) the buffer doesn't get dropped until the transfer is finished
|
||||
/// 3) doesn't call this function while another transfer is running
|
||||
pub unsafe fn dma2d_start_const_multiline(color: u16, width: i16, height: i16) {
|
||||
unsafe {
|
||||
ffi::dma2d_start_const_multiline(
|
||||
color,
|
||||
ffi::display_get_wr_addr() as _,
|
||||
width as _,
|
||||
height as _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dma2d_wait_for_transfer() {
|
||||
unsafe {
|
||||
ffi::dma2d_wait_for_transfer();
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ pub mod fatal_error;
|
||||
pub mod bitblt;
|
||||
#[cfg(feature = "ui")]
|
||||
pub mod display;
|
||||
#[cfg(feature = "dma2d")]
|
||||
pub mod dma2d;
|
||||
mod ffi;
|
||||
#[cfg(feature = "haptic")]
|
||||
pub mod haptic;
|
||||
@ -25,7 +23,6 @@ pub mod usb;
|
||||
pub mod uzlib;
|
||||
pub mod wordlist;
|
||||
|
||||
pub mod buffers;
|
||||
pub mod secbool;
|
||||
|
||||
#[cfg(not(feature = "micropython"))]
|
||||
|
@ -12,12 +12,6 @@ extern "C" fn screen_welcome() {
|
||||
ModelUI::screen_welcome();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
extern "C" fn bld_continue_label(bg_color: cty::uint16_t) {
|
||||
ModelUI::bld_continue_label(bg_color.into());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_success(
|
||||
restart_seconds: u8,
|
||||
@ -105,7 +99,6 @@ extern "C" fn screen_boot_stage_1(fading: bool) {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "new_rendering")]
|
||||
extern "C" fn screen_boot(
|
||||
warning: bool,
|
||||
vendor_str: *const cty::c_char,
|
||||
|
@ -3,14 +3,6 @@
|
||||
|
||||
use crate::ui::ui_features::{ModelUI, UIFeaturesCommon};
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
use crate::ui::{
|
||||
component::image::Image,
|
||||
display::{Color, Icon},
|
||||
geometry::{Alignment2D, Point},
|
||||
};
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
use crate::ui::shape;
|
||||
|
||||
use crate::ui::util::from_c_str;
|
||||
@ -30,10 +22,7 @@ extern "C" fn display_rsod_rust(
|
||||
// to allow nested calls to `run_with_bumps`/`render_on_display`,
|
||||
// because after the error message is displayed, the application will
|
||||
// shut down.
|
||||
#[cfg(feature = "new_rendering")]
|
||||
unsafe {
|
||||
shape::unlock_bumps_on_failure()
|
||||
};
|
||||
unsafe { shape::unlock_bumps_on_failure() };
|
||||
|
||||
ModelUI::screen_fatal_error(title, msg, footer);
|
||||
ModelUI::backlight_on();
|
||||
@ -43,36 +32,3 @@ extern "C" fn display_rsod_rust(
|
||||
extern "C" fn screen_boot_stage_2() {
|
||||
ModelUI::screen_boot_stage_2();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
extern "C" fn display_icon(
|
||||
x: cty::int16_t,
|
||||
y: cty::int16_t,
|
||||
data: *const cty::uint8_t,
|
||||
data_len: cty::uint32_t,
|
||||
fg_color: cty::uint16_t,
|
||||
bg_color: cty::uint16_t,
|
||||
) {
|
||||
let data_slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) };
|
||||
let icon = Icon::new(data_slice);
|
||||
icon.draw(
|
||||
Point::new(x, y),
|
||||
Alignment2D::TOP_LEFT,
|
||||
Color::from_u16(fg_color),
|
||||
Color::from_u16(bg_color),
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
extern "C" fn display_image(
|
||||
x: cty::int16_t,
|
||||
y: cty::int16_t,
|
||||
data: *const cty::uint8_t,
|
||||
data_len: cty::uint32_t,
|
||||
) {
|
||||
let data_slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) };
|
||||
let image = Image::new(data_slice);
|
||||
image.draw(Point::new(x, y), Alignment2D::TOP_LEFT);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
display::Color,
|
||||
geometry::Rect,
|
||||
shape,
|
||||
@ -37,10 +36,6 @@ impl Component for Bar {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
display::rect_fill_rounded(self.area, self.color, self.bg_color, self.radius as u8);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::Bar::new(self.area)
|
||||
.with_bg(self.color)
|
||||
|
@ -5,8 +5,7 @@ use crate::{
|
||||
time::Duration,
|
||||
ui::{
|
||||
button_request::{ButtonRequest, ButtonRequestCode},
|
||||
component::{maybe::PaintOverlapping, MsgMap, PageMap},
|
||||
display::Color,
|
||||
component::{MsgMap, PageMap},
|
||||
geometry::{Offset, Rect},
|
||||
shape::Renderer,
|
||||
},
|
||||
@ -60,11 +59,6 @@ pub trait Component {
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg>;
|
||||
|
||||
/// Render to screen, based on current internal state.
|
||||
///
|
||||
/// To prevent unnecessary over-draw, dirty state checking is performed in
|
||||
/// the `Child` wrapper.
|
||||
fn paint(&mut self);
|
||||
|
||||
fn render<'s>(&'s self, _target: &mut impl Renderer<'s>);
|
||||
}
|
||||
|
||||
@ -150,13 +144,6 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
if self.marked_for_paint {
|
||||
self.marked_for_paint = false;
|
||||
self.component.paint();
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.component.render(target);
|
||||
}
|
||||
@ -172,22 +159,6 @@ impl<T: Paginate> Paginate for Child<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PaintOverlapping for Child<T>
|
||||
where
|
||||
T: PaintOverlapping,
|
||||
{
|
||||
fn cleared_area(&self) -> Option<(Rect, Color)> {
|
||||
self.component.cleared_area()
|
||||
}
|
||||
|
||||
fn paint_overlapping(&mut self) {
|
||||
if self.marked_for_paint {
|
||||
self.marked_for_paint = false;
|
||||
self.component.paint_overlapping()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<T> crate::trace::Trace for Child<T>
|
||||
where
|
||||
@ -215,11 +186,6 @@ where
|
||||
.or_else(|| self.1.event(ctx, event))
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.0.paint();
|
||||
self.1.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.0.render(target);
|
||||
self.1.render(target);
|
||||
@ -262,12 +228,6 @@ where
|
||||
.or_else(|| self.2.event(ctx, event))
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.0.paint();
|
||||
self.1.paint();
|
||||
self.2.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.0.render(target);
|
||||
self.1.render(target);
|
||||
@ -288,12 +248,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
if let Some(ref mut c) = self {
|
||||
c.paint()
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
if let Some(ref c) = self {
|
||||
c.render(target)
|
||||
|
@ -38,10 +38,6 @@ where
|
||||
self.inner.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.inner.render(target);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::ui::{
|
||||
geometry::Rect,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))]
|
||||
#[cfg(all(feature = "micropython", feature = "touch"))]
|
||||
use crate::ui::component::swipe_detect::SwipeConfig;
|
||||
|
||||
/// Component that sends a ButtonRequest after receiving Event::Attach. The
|
||||
@ -62,16 +62,12 @@ impl<T: Component> Component for SendButtonRequest<T> {
|
||||
self.inner.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl crate::ui::shape::Renderer<'s>) {
|
||||
self.inner.render(target)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))]
|
||||
#[cfg(all(feature = "micropython", feature = "touch"))]
|
||||
impl<T: crate::ui::flow::Swipable> crate::ui::flow::Swipable for SendButtonRequest<T> {
|
||||
fn get_swipe_config(&self) -> SwipeConfig {
|
||||
self.inner.get_swipe_config()
|
||||
|
@ -58,8 +58,6 @@ impl Component for CachedJpeg {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let off = Offset::new(
|
||||
self.image_size.x / (2 << self.scale),
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
strutil::TString,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
display::{self, Color, Font},
|
||||
display::{Color, Font},
|
||||
geometry::{Alignment, Offset, Rect},
|
||||
shape::{self, Renderer},
|
||||
},
|
||||
@ -42,21 +42,6 @@ impl Component for Connect {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let font = Font::NORMAL;
|
||||
|
||||
self.bg.paint();
|
||||
self.message.map(|t| {
|
||||
display::text_center(
|
||||
self.bg.area.center() + Offset::y(font.text_height() / 2),
|
||||
t,
|
||||
font,
|
||||
self.fg,
|
||||
self.bg.color,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let font = Font::NORMAL;
|
||||
|
||||
|
@ -15,8 +15,6 @@ impl Component for Empty {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {}
|
||||
|
||||
fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
display::{
|
||||
toif::{image, Toif, ToifFormat},
|
||||
toif::{Toif, ToifFormat},
|
||||
Color, Icon,
|
||||
},
|
||||
geometry::{Alignment2D, Offset, Point, Rect},
|
||||
@ -25,13 +24,6 @@ impl Image {
|
||||
area: Rect::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Display the icon with baseline Point, aligned according to the
|
||||
/// `alignment` argument.
|
||||
pub fn draw(&self, baseline: Point, alignment: Alignment2D) {
|
||||
let r = Rect::snap(baseline, self.toif.size(), alignment);
|
||||
image(self, r.center());
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Image {
|
||||
@ -46,10 +38,6 @@ impl Component for Image {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.draw(self.area.center(), Alignment2D::CENTER);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::ToifImage::new(self.area.center(), self.toif)
|
||||
.with_align(Alignment2D::CENTER)
|
||||
@ -92,15 +80,6 @@ impl BlendedImage {
|
||||
pub fn single(icon: Icon, color: Color, area_color: Color) -> Self {
|
||||
Self::new(icon, icon, color, color, area_color)
|
||||
}
|
||||
|
||||
fn paint_image(&self) {
|
||||
display::icon_over_icon(
|
||||
None,
|
||||
(self.bg, self.bg_top_left.into(), self.bg_color),
|
||||
(self.fg, self.fg_offset, self.fg_color),
|
||||
self.area_color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for BlendedImage {
|
||||
@ -126,10 +105,6 @@ impl Component for BlendedImage {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.paint_image();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::ToifImage::new(self.bg_top_left, self.bg.toif)
|
||||
.with_fg(self.bg_color)
|
||||
|
@ -2,8 +2,7 @@ use crate::{
|
||||
io::BinaryData,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
geometry::{Alignment2D, Offset, Rect},
|
||||
geometry::{Alignment2D, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
},
|
||||
@ -37,17 +36,6 @@ impl Component for Jpeg {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// SAFETY: We expect no existing mutable reference. Resulting reference is
|
||||
// discarded before returning to micropython.
|
||||
let jpeg_data = unsafe { self.image.data() };
|
||||
|
||||
if let Some((size, _)) = display::tjpgd::jpeg_info(jpeg_data) {
|
||||
let off = Offset::new(size.x / (2 << self.scale), size.y / (2 << self.scale));
|
||||
display::tjpgd::jpeg(jpeg_data, self.area.center() - off, self.scale);
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::JpegImage::new_image(self.area.center(), self.image)
|
||||
.with_align(Alignment2D::CENTER)
|
||||
|
@ -136,12 +136,8 @@ impl Component for Label<'_> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.text.map(|c| self.layout.render_text(c));
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.text.map(|c| self.layout.render_text2(c, target));
|
||||
self.text.map(|c| self.layout.render_text(c, target));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::{Component, Event, EventCtx};
|
||||
use crate::ui::{geometry::Rect, shape::Renderer};
|
||||
|
||||
#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))]
|
||||
#[cfg(all(feature = "micropython", feature = "touch"))]
|
||||
use crate::ui::component::swipe_detect::SwipeConfig;
|
||||
|
||||
pub struct MsgMap<T, F> {
|
||||
@ -30,16 +30,12 @@ where
|
||||
self.inner.event(ctx, event).and_then(&self.func)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.inner.render(target);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))]
|
||||
#[cfg(all(feature = "micropython", feature = "touch"))]
|
||||
impl<T, F> crate::ui::flow::Swipable for MsgMap<T, F>
|
||||
where
|
||||
T: Component + crate::ui::flow::Swipable,
|
||||
@ -90,10 +86,6 @@ where
|
||||
res
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.inner.render(target);
|
||||
}
|
||||
@ -109,7 +101,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))]
|
||||
#[cfg(all(feature = "micropython", feature = "touch"))]
|
||||
impl<T, F> crate::ui::flow::Swipable for PageMap<T, F>
|
||||
where
|
||||
T: Component + crate::ui::flow::Swipable,
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
ui::{
|
||||
animation::Animation,
|
||||
component::{Component, Event, EventCtx, Never, Timer},
|
||||
display::{self, Color, Font},
|
||||
display::{Color, Font},
|
||||
geometry::{Offset, Rect},
|
||||
shape::{self, Renderer},
|
||||
util::animation_disabled,
|
||||
@ -119,11 +119,6 @@ impl Marquee {
|
||||
self.animation().is_some()
|
||||
}
|
||||
|
||||
pub fn paint_anim(&mut self, offset: i16) {
|
||||
self.text
|
||||
.map(|t| display::marquee(self.area, t, offset, self.font, self.fg, self.bg));
|
||||
}
|
||||
|
||||
pub fn render_anim<'s>(&'s self, target: &mut impl Renderer<'s>, offset: i16) {
|
||||
target.in_window(self.area, &|target| {
|
||||
let text_height = self.font.text_height();
|
||||
@ -201,30 +196,6 @@ impl Component for Marquee {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let now = Instant::now();
|
||||
|
||||
match self.state {
|
||||
State::Initial => {
|
||||
self.paint_anim(0);
|
||||
}
|
||||
State::PauseRight => {
|
||||
self.paint_anim(self.min_offset);
|
||||
}
|
||||
State::PauseLeft => {
|
||||
self.paint_anim(self.max_offset);
|
||||
}
|
||||
_ => {
|
||||
let progress = self.progress(now);
|
||||
if let Some(done) = progress {
|
||||
self.paint_anim(done);
|
||||
} else {
|
||||
self.paint_anim(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let now = Instant::now();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::ui::{
|
||||
component::{Component, ComponentExt, Event, EventCtx, Pad},
|
||||
display::{self, Color},
|
||||
display::Color,
|
||||
geometry::Rect,
|
||||
shape::Renderer,
|
||||
};
|
||||
@ -88,13 +88,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.pad.paint();
|
||||
if self.visible {
|
||||
self.inner.paint();
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.pad.render(target);
|
||||
if self.visible {
|
||||
@ -103,51 +96,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PaintOverlapping {
|
||||
/// Return area that would be cleared during regular paint, along with
|
||||
/// background color, or None if clearing isn't requested.
|
||||
fn cleared_area(&self) -> Option<(Rect, Color)>;
|
||||
|
||||
/// Paint the component but do not clear background beforehand.
|
||||
fn paint_overlapping(&mut self);
|
||||
}
|
||||
|
||||
impl<T> PaintOverlapping for Maybe<T>
|
||||
where
|
||||
T: Component,
|
||||
{
|
||||
fn cleared_area(&self) -> Option<(Rect, Color)> {
|
||||
self.pad.will_paint()
|
||||
}
|
||||
|
||||
fn paint_overlapping(&mut self) {
|
||||
self.pad.cancel_clear();
|
||||
self.paint()
|
||||
}
|
||||
}
|
||||
|
||||
/// Paint multiple Maybe<T> components, correctly handling clearing of
|
||||
/// background in the case the areas overlap, i.e. clear the combined area first
|
||||
/// and then paint over it.
|
||||
pub fn paint_overlapping(components: &mut [&mut dyn PaintOverlapping]) {
|
||||
let mut area = Rect::zero();
|
||||
let mut color = Color::rgb(0, 0, 0);
|
||||
for component in components.iter() {
|
||||
if let Some((clear_area, clear_color)) = component.cleared_area() {
|
||||
area = area.union(clear_area);
|
||||
color = clear_color;
|
||||
}
|
||||
}
|
||||
|
||||
if area != Rect::zero() {
|
||||
display::rect_fill(area, color)
|
||||
}
|
||||
|
||||
for component in components.iter_mut() {
|
||||
component.paint_overlapping()
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
|
@ -1,9 +1,4 @@
|
||||
use crate::ui::{
|
||||
display::{self, Color},
|
||||
geometry::Rect,
|
||||
shape,
|
||||
shape::Renderer,
|
||||
};
|
||||
use crate::ui::{display::Color, geometry::Rect, shape, shape::Renderer};
|
||||
|
||||
pub struct Pad {
|
||||
pub area: Rect,
|
||||
@ -47,14 +42,6 @@ impl Pad {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint(&mut self) {
|
||||
if self.clear {
|
||||
self.clear = false;
|
||||
|
||||
display::rect_fill(self.area, self.color);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::Bar::new(self.area)
|
||||
.with_bg(self.color)
|
||||
|
@ -61,10 +61,6 @@ where
|
||||
self.inner.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.inner.render(target);
|
||||
}
|
||||
@ -108,10 +104,6 @@ where
|
||||
self.inner.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.inner.render(target);
|
||||
}
|
||||
@ -184,10 +176,6 @@ where
|
||||
self.inner.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.inner.render(target);
|
||||
}
|
||||
@ -278,11 +266,6 @@ where
|
||||
.or_else(|| self.second.event(ctx, event))
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.first.paint();
|
||||
self.second.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.first.render(target);
|
||||
self.second.render(target);
|
||||
|
@ -5,9 +5,8 @@ use crate::{
|
||||
error::Error,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
constant,
|
||||
display::{pixeldata, pixeldata_dirty, rect_fill_rounded, set_window, Color},
|
||||
geometry::{Insets, Offset, Rect},
|
||||
display::Color,
|
||||
geometry::{Offset, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
},
|
||||
@ -76,33 +75,6 @@ impl Qr {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn draw(qr: &QrCode, area: Rect, border: i16, scale: i16) {
|
||||
if border > 0 {
|
||||
rect_fill_rounded(
|
||||
area.inset(Insets::uniform(-border)),
|
||||
LIGHT,
|
||||
DARK,
|
||||
CORNER_RADIUS,
|
||||
);
|
||||
}
|
||||
|
||||
let window = area.clamp(constant::screen());
|
||||
set_window(window);
|
||||
|
||||
for y in window.y0..window.y1 {
|
||||
for x in window.x0..window.x1 {
|
||||
let rx = (x - window.x0) / scale;
|
||||
let ry = (y - window.y0) / scale;
|
||||
if qr.get_module(rx.into(), ry.into()) {
|
||||
pixeldata(DARK);
|
||||
} else {
|
||||
pixeldata(LIGHT);
|
||||
};
|
||||
}
|
||||
}
|
||||
pixeldata_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Qr {
|
||||
@ -117,32 +89,6 @@ impl Component for Qr {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let mut outbuffer = [0u8; QR_MAX_VERSION.buffer_len()];
|
||||
let mut tempbuffer = [0u8; QR_MAX_VERSION.buffer_len()];
|
||||
|
||||
let qr = QrCode::encode_text(
|
||||
self.text.as_ref(),
|
||||
&mut tempbuffer,
|
||||
&mut outbuffer,
|
||||
QrCodeEcc::Medium,
|
||||
Version::MIN,
|
||||
QR_MAX_VERSION,
|
||||
None,
|
||||
true,
|
||||
);
|
||||
let qr = unwrap!(qr);
|
||||
let size = qr.size() as i16;
|
||||
|
||||
let avail_space = self.area.width().min(self.area.height());
|
||||
let avail_space = avail_space - 2 * self.border;
|
||||
let scale = avail_space / size;
|
||||
assert!((1..=10).contains(&scale));
|
||||
|
||||
let area = Rect::from_center_and_size(self.area.center(), Offset::uniform(size * scale));
|
||||
Self::draw(&qr, area, self.border, scale);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let mut outbuffer = [0u8; QR_MAX_VERSION.buffer_len()];
|
||||
let mut tempbuffer = [0u8; QR_MAX_VERSION.buffer_len()];
|
||||
|
@ -134,7 +134,5 @@ impl Component for Swipe {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {}
|
||||
|
||||
fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use crate::ui::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
layout::{LayoutFit, LayoutSink, TextNoOp, TextRenderer, TextRenderer2},
|
||||
layout::{LayoutFit, LayoutSink, TextNoOp, TextRenderer},
|
||||
op::OpTextLayout,
|
||||
};
|
||||
|
||||
@ -130,12 +130,8 @@ impl Component for FormattedText {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.layout_content(&mut TextRenderer);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.layout_content(&mut TextRenderer2::new(target));
|
||||
self.layout_content(&mut TextRenderer::new(target));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::ui::{
|
||||
display,
|
||||
display::{toif::Icon, Color, Font, GlyphMetrics},
|
||||
geometry::{Alignment, Alignment2D, Dimensions, Offset, Point, Rect},
|
||||
shape,
|
||||
@ -233,12 +232,7 @@ impl TextLayout {
|
||||
}
|
||||
|
||||
/// Draw as much text as possible on the current screen.
|
||||
pub fn render_text(&self, text: &str) -> LayoutFit {
|
||||
self.layout_text(text, &mut self.initial_cursor(), &mut TextRenderer)
|
||||
}
|
||||
|
||||
/// Draw as much text as possible on the current screen.
|
||||
pub fn render_text2<'s>(&self, text: &str, target: &mut impl Renderer<'s>) -> LayoutFit {
|
||||
pub fn render_text<'s>(&self, text: &str, target: &mut impl Renderer<'s>) -> LayoutFit {
|
||||
self.render_text_with_alpha(text, target, 255)
|
||||
}
|
||||
/// Draw as much text as possible on the current screen.
|
||||
@ -251,7 +245,7 @@ impl TextLayout {
|
||||
self.layout_text(
|
||||
text,
|
||||
&mut self.initial_cursor(),
|
||||
&mut TextRenderer2::new(target).with_alpha(alpha),
|
||||
&mut TextRenderer::new(target).with_alpha(alpha),
|
||||
)
|
||||
}
|
||||
|
||||
@ -486,71 +480,7 @@ pub struct TextNoOp;
|
||||
|
||||
impl LayoutSink for TextNoOp {}
|
||||
|
||||
/// `LayoutSink` for rendering the content.
|
||||
pub struct TextRenderer;
|
||||
|
||||
impl LayoutSink for TextRenderer {
|
||||
fn text(&mut self, cursor: Point, layout: &TextLayout, text: &str) {
|
||||
display::text_left(
|
||||
cursor,
|
||||
text,
|
||||
layout.style.text_font,
|
||||
layout.style.text_color,
|
||||
layout.style.background_color,
|
||||
);
|
||||
}
|
||||
|
||||
fn hyphen(&mut self, cursor: Point, layout: &TextLayout) {
|
||||
display::text_left(
|
||||
cursor,
|
||||
"-",
|
||||
layout.style.text_font,
|
||||
layout.style.hyphen_color,
|
||||
layout.style.background_color,
|
||||
);
|
||||
}
|
||||
|
||||
fn ellipsis(&mut self, cursor: Point, layout: &TextLayout) {
|
||||
if let Some((icon, margin)) = layout.style.ellipsis_icon {
|
||||
let bottom_left = cursor + Offset::x(margin);
|
||||
icon.draw(
|
||||
bottom_left,
|
||||
Alignment2D::BOTTOM_LEFT,
|
||||
layout.style.ellipsis_color,
|
||||
layout.style.background_color,
|
||||
);
|
||||
} else {
|
||||
display::text_left(
|
||||
cursor,
|
||||
ELLIPSIS,
|
||||
layout.style.text_font,
|
||||
layout.style.ellipsis_color,
|
||||
layout.style.background_color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn prev_page_ellipsis(&mut self, cursor: Point, layout: &TextLayout) {
|
||||
if let Some((icon, _margin)) = layout.style.prev_page_ellipsis_icon {
|
||||
icon.draw(
|
||||
cursor,
|
||||
Alignment2D::BOTTOM_LEFT,
|
||||
layout.style.ellipsis_color,
|
||||
layout.style.background_color,
|
||||
);
|
||||
} else {
|
||||
display::text_left(
|
||||
cursor,
|
||||
ELLIPSIS,
|
||||
layout.style.text_font,
|
||||
layout.style.ellipsis_color,
|
||||
layout.style.background_color,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextRenderer2<'a, 's, R>
|
||||
pub struct TextRenderer<'a, 's, R>
|
||||
where
|
||||
R: Renderer<'s>,
|
||||
{
|
||||
@ -559,7 +489,7 @@ where
|
||||
alpha: u8,
|
||||
}
|
||||
|
||||
impl<'a, 's, R> TextRenderer2<'a, 's, R>
|
||||
impl<'a, 's, R> TextRenderer<'a, 's, R>
|
||||
where
|
||||
R: Renderer<'s>,
|
||||
{
|
||||
@ -576,7 +506,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's, R> LayoutSink for TextRenderer2<'a, 's, R>
|
||||
impl<'a, 's, R> LayoutSink for TextRenderer<'a, 's, R>
|
||||
where
|
||||
R: Renderer<'s>,
|
||||
{
|
||||
|
@ -5,9 +5,7 @@ use crate::{
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never, Paginate},
|
||||
display::{toif::Icon, Color, Font},
|
||||
geometry::{
|
||||
Alignment, Alignment2D, Dimensions, Insets, LinearPlacement, Offset, Point, Rect,
|
||||
},
|
||||
geometry::{Alignment, Dimensions, Insets, LinearPlacement, Offset, Point, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
},
|
||||
@ -196,24 +194,13 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
Self::foreach_visible(
|
||||
&self.source,
|
||||
&self.visible,
|
||||
self.offset,
|
||||
&mut |layout, content| {
|
||||
layout.render_text(content);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
Self::foreach_visible(
|
||||
&self.source,
|
||||
&self.visible,
|
||||
self.offset,
|
||||
&mut |layout, content| {
|
||||
layout.render_text2(content, target);
|
||||
layout.render_text(content, target);
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -649,16 +636,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_icon(&self, layout: &TextLayout, icon: Icon, offset: Offset) {
|
||||
let top_left = Point::new(self.area.x0, layout.bounds.y0);
|
||||
icon.draw(
|
||||
top_left + offset,
|
||||
Alignment2D::TOP_LEFT,
|
||||
layout.style.text_color,
|
||||
layout.style.background_color,
|
||||
);
|
||||
}
|
||||
|
||||
fn render_numeral<'s>(
|
||||
&self,
|
||||
base_point: Point,
|
||||
@ -703,26 +680,6 @@ where
|
||||
self.paragraphs.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.paragraphs.paint();
|
||||
|
||||
let current_visible = self.current.saturating_sub(self.paragraphs.offset.par);
|
||||
for layout in self.paragraphs.visible.iter().take(current_visible) {
|
||||
self.paint_icon(
|
||||
&layout.layout(&self.paragraphs.source),
|
||||
self.icon_done,
|
||||
self.done_offset,
|
||||
);
|
||||
}
|
||||
if let Some(layout) = self.paragraphs.visible.iter().nth(current_visible) {
|
||||
self.paint_icon(
|
||||
&layout.layout(&self.paragraphs.source),
|
||||
self.icon_current,
|
||||
self.current_offset,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.paragraphs.render(target);
|
||||
self.render_left_column(target);
|
||||
|
@ -19,33 +19,7 @@ use super::{
|
||||
///
|
||||
/// 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>(
|
||||
pub fn text_multiline<'s>(
|
||||
target: &mut impl Renderer<'s>,
|
||||
area: Rect,
|
||||
text: TString<'_>,
|
||||
@ -58,7 +32,7 @@ pub fn text_multiline2<'s>(
|
||||
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));
|
||||
let layout_fit = text.map(|t| text_layout.render_text(t, target));
|
||||
match layout_fit {
|
||||
LayoutFit::Fitting { height, .. } => Some(area.split_top(height).1),
|
||||
LayoutFit::OutOfBounds { .. } => None,
|
||||
@ -67,37 +41,7 @@ pub fn text_multiline2<'s>(
|
||||
|
||||
/// 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>(
|
||||
pub fn text_multiline_bottom<'s>(
|
||||
target: &mut impl Renderer<'s>,
|
||||
area: Rect,
|
||||
text: TString<'_>,
|
||||
@ -116,11 +60,11 @@ pub fn text_multiline_bottom2<'s>(
|
||||
LayoutFit::Fitting { height, .. } => {
|
||||
let (top, bottom) = area.split_bottom(height);
|
||||
text_layout = text_layout.with_bounds(bottom);
|
||||
text_layout.render_text2(t, target);
|
||||
text_layout.render_text(t, target);
|
||||
Some(top)
|
||||
}
|
||||
LayoutFit::OutOfBounds { .. } => {
|
||||
text_layout.render_text2(t, target);
|
||||
text_layout.render_text(t, target);
|
||||
None
|
||||
}
|
||||
})
|
||||
|
@ -35,8 +35,6 @@ impl Component for Timeout {
|
||||
self.timer.expire(event).then_some(())
|
||||
}
|
||||
|
||||
fn paint(&mut self) {}
|
||||
|
||||
fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {}
|
||||
}
|
||||
|
||||
|
@ -2,14 +2,12 @@ use crate::{
|
||||
trezorhal::display,
|
||||
ui::{
|
||||
constant,
|
||||
geometry::{Offset, Point, Rect},
|
||||
geometry::Offset,
|
||||
shape::{Bitmap, BitmapFormat},
|
||||
},
|
||||
};
|
||||
use core::slice;
|
||||
|
||||
use super::{get_color_table, get_offset, pixeldata, set_window, Color};
|
||||
|
||||
/// Representation of a single glyph.
|
||||
/// We use standard typographic terms. For a nice explanation, see, e.g.,
|
||||
/// the FreeType docs at https://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html
|
||||
@ -67,28 +65,6 @@ impl Glyph {
|
||||
self.adv - self.width - self.bearing_x
|
||||
}
|
||||
|
||||
pub fn print(&self, pos: Point, colortable: [Color; 16]) -> i16 {
|
||||
let bearing = Offset::new(self.bearing_x, -self.bearing_y);
|
||||
let size = Offset::new(self.width, self.height);
|
||||
let pos_adj = pos + bearing;
|
||||
let r = Rect::from_top_left_and_size(pos_adj, size);
|
||||
|
||||
let area = r.translate(get_offset());
|
||||
let window = area.clamp(constant::screen());
|
||||
|
||||
set_window(window);
|
||||
|
||||
for y in window.y0..window.y1 {
|
||||
for x in window.x0..window.x1 {
|
||||
let p = Point::new(x, y);
|
||||
let r = p - pos_adj;
|
||||
let c = self.get_pixel_data(r);
|
||||
pixeldata(colortable[c as usize]);
|
||||
}
|
||||
}
|
||||
self.adv
|
||||
}
|
||||
|
||||
pub fn unpack_bpp1(&self, a: i16) -> u8 {
|
||||
let c_data = self.data[(a / 8) as usize];
|
||||
((c_data >> (7 - (a % 8))) & 0x01) * 15
|
||||
@ -109,18 +85,6 @@ impl Glyph {
|
||||
c_data >> 4
|
||||
}
|
||||
|
||||
pub fn get_pixel_data(&self, p: Offset) -> u8 {
|
||||
let a = p.x + p.y * self.width;
|
||||
|
||||
match constant::FONT_BPP {
|
||||
1 => self.unpack_bpp1(a),
|
||||
2 => self.unpack_bpp2(a),
|
||||
4 => self.unpack_bpp4(a),
|
||||
8 => self.unpack_bpp8(a),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bitmap(&self) -> Bitmap<'static> {
|
||||
match constant::FONT_BPP {
|
||||
1 => unwrap!(Bitmap::new(
|
||||
@ -298,16 +262,6 @@ impl Font {
|
||||
unsafe { Glyph::load(gl_data) }
|
||||
}
|
||||
|
||||
pub fn display_text(self, text: &str, baseline: Point, fg_color: Color, bg_color: Color) {
|
||||
let colortable = get_color_table(fg_color, bg_color);
|
||||
let mut adv_total = 0;
|
||||
for c in text.chars() {
|
||||
let gly = self.get_glyph(c);
|
||||
let adv = gly.print(baseline + Offset::new(adv_total, 0), colortable);
|
||||
adv_total += adv;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the longest prefix of a given `text` (breaking at word boundaries)
|
||||
/// that will fit into the area `width` pixels wide.
|
||||
pub fn longest_prefix(self, width: i16, text: &str) -> &str {
|
||||
|
@ -1,429 +0,0 @@
|
||||
use crate::ui::{
|
||||
constant,
|
||||
constant::{screen, LOADER_INNER, LOADER_OUTER},
|
||||
display,
|
||||
display::{toif::Icon, Color},
|
||||
geometry::{Offset, Point, Rect},
|
||||
};
|
||||
|
||||
#[cfg(feature = "dma2d")]
|
||||
use crate::trezorhal::{
|
||||
buffers,
|
||||
dma2d::{dma2d_setup_4bpp_over_4bpp, dma2d_start_blend, dma2d_wait_for_transfer},
|
||||
};
|
||||
|
||||
const ICON_MAX_SIZE: i16 = constant::LOADER_ICON_MAX_SIZE;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LoaderDimensions {
|
||||
in_inner_anti: i32,
|
||||
inner_min: i32,
|
||||
inner_max: i32,
|
||||
inner_outer_anti: i32,
|
||||
outer_out_anti: i32,
|
||||
outer_max: i32,
|
||||
}
|
||||
|
||||
impl LoaderDimensions {
|
||||
pub fn new(outer: i16, inner: i16) -> Self {
|
||||
let outer: f32 = outer.into();
|
||||
let inner: f32 = inner.into();
|
||||
Self {
|
||||
in_inner_anti: ((inner - 0.5) * (inner - 0.5)) as i32,
|
||||
inner_min: ((inner + 0.5) * (inner + 0.5)) as i32,
|
||||
inner_max: ((inner + 1.5) * (inner + 1.5)) as i32,
|
||||
inner_outer_anti: ((inner + 2.5) * (inner + 2.5)) as i32,
|
||||
outer_out_anti: ((outer - 1.5) * (outer - 1.5)) as i32,
|
||||
outer_max: ((outer - 0.5) * (outer - 0.5)) as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loader_circular_uncompress(
|
||||
dim: LoaderDimensions,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
progress: u16,
|
||||
indeterminate: bool,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
if let Some((icon, color)) = icon {
|
||||
let toif_size = icon.toif.size();
|
||||
if toif_size.x <= ICON_MAX_SIZE && toif_size.y <= ICON_MAX_SIZE {
|
||||
let mut icon_data = [0_u8; ((ICON_MAX_SIZE * ICON_MAX_SIZE) / 2) as usize];
|
||||
icon.toif.uncompress(&mut icon_data);
|
||||
let i = Some((icon_data.as_ref(), color, toif_size));
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
i,
|
||||
);
|
||||
} else {
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
None,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loader_circular(
|
||||
progress: u16,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
loader_circular_uncompress(
|
||||
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
false,
|
||||
icon,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn loader_circular_indeterminate(
|
||||
progress: u16,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
loader_circular_uncompress(
|
||||
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
true,
|
||||
icon,
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_loader_vectors(indeterminate: bool, progress: u16) -> (Point, Point) {
|
||||
let (start_progress, end_progress) = if indeterminate {
|
||||
const LOADER_INDETERMINATE_WIDTH: u16 = 100;
|
||||
(
|
||||
(progress + 1000 - LOADER_INDETERMINATE_WIDTH) % 1000,
|
||||
(progress + LOADER_INDETERMINATE_WIDTH) % 1000,
|
||||
)
|
||||
} else {
|
||||
(0, progress)
|
||||
};
|
||||
|
||||
let start = ((360 * start_progress as i32) / 1000) % 360;
|
||||
let end = ((360 * end_progress as i32) / 1000) % 360;
|
||||
|
||||
let start_vector;
|
||||
let end_vector;
|
||||
|
||||
if indeterminate {
|
||||
start_vector = display::get_vector(start as _);
|
||||
end_vector = display::get_vector(end as _);
|
||||
} else if progress >= 1000 {
|
||||
start_vector = Point::zero();
|
||||
end_vector = Point::zero();
|
||||
} else if progress > 500 {
|
||||
start_vector = display::get_vector(end as _);
|
||||
end_vector = display::get_vector(start as _);
|
||||
} else {
|
||||
start_vector = display::get_vector(start as _);
|
||||
end_vector = display::get_vector(end as _);
|
||||
}
|
||||
|
||||
(start_vector, end_vector)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn loader_get_pixel_color_idx(
|
||||
show_all: bool,
|
||||
inverted: bool,
|
||||
end_vector: Point,
|
||||
n_start: Point,
|
||||
c: Point,
|
||||
center: Point,
|
||||
dim: LoaderDimensions,
|
||||
) -> u8 {
|
||||
let y_p = -(c.y - center.y);
|
||||
let x_p = c.x - center.x;
|
||||
|
||||
let vx = Point::new(x_p, y_p);
|
||||
let n_vx = Point::new(-y_p, x_p);
|
||||
|
||||
let d = y_p as i32 * y_p as i32 + x_p as i32 * x_p as i32;
|
||||
|
||||
let included = if inverted {
|
||||
!display::is_clockwise_or_equal(n_start, vx)
|
||||
|| !display::is_clockwise_or_equal_inc(n_vx, end_vector)
|
||||
} else {
|
||||
display::is_clockwise_or_equal(n_start, vx)
|
||||
&& display::is_clockwise_or_equal_inc(n_vx, end_vector)
|
||||
};
|
||||
|
||||
// The antialiasing calculation below uses simplified distance difference
|
||||
// calculation. Optimally, SQRT should be used, but assuming
|
||||
// diameter large enough and antialiasing over distance
|
||||
// r_outer-r_inner = 1, the difference between simplified:
|
||||
// (d^2-r_inner^2)/(r_outer^2-r_inner^2) and precise: (sqrt(d^2)
|
||||
// - r_inner)/(r_outer-r_inner) is negligible
|
||||
if show_all || included {
|
||||
//active part
|
||||
if d <= dim.in_inner_anti {
|
||||
0
|
||||
} else if d <= dim.inner_min {
|
||||
((15 * (d - dim.in_inner_anti)) / (dim.inner_min - dim.in_inner_anti)) as u8
|
||||
} else if d <= dim.outer_out_anti {
|
||||
15
|
||||
} else if d <= dim.outer_max {
|
||||
(15 - ((15 * (d - dim.outer_out_anti)) / (dim.outer_max - dim.outer_out_anti))) as u8
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
//inactive part
|
||||
if d <= dim.in_inner_anti {
|
||||
0
|
||||
} else if d <= dim.inner_min {
|
||||
((15 * (d - dim.in_inner_anti)) / (dim.inner_min - dim.in_inner_anti)) as u8
|
||||
} else if d <= dim.inner_max {
|
||||
15
|
||||
} else if d <= dim.inner_outer_anti {
|
||||
(15 - ((10 * (d - dim.inner_max)) / (dim.inner_outer_anti - dim.inner_max))) as u8
|
||||
} else if d <= dim.outer_out_anti {
|
||||
5
|
||||
} else if d <= dim.outer_max {
|
||||
5 - ((5 * (d - dim.outer_out_anti)) / (dim.outer_max - dim.outer_out_anti)) as u8
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dma2d"))]
|
||||
pub fn loader_rust(
|
||||
dim: LoaderDimensions,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
progress: u16,
|
||||
indeterminate: bool,
|
||||
icon: Option<(&[u8], Color, Offset)>,
|
||||
) {
|
||||
let center = screen().center() + Offset::new(0, y_offset);
|
||||
let r = Rect::from_center_and_size(center, Offset::uniform(LOADER_OUTER as i16 * 2));
|
||||
let clamped = r.clamp(constant::screen());
|
||||
display::set_window(clamped);
|
||||
|
||||
let center = r.center();
|
||||
|
||||
let colortable = display::get_color_table(fg_color, bg_color);
|
||||
let mut icon_colortable = colortable;
|
||||
|
||||
let mut use_icon = false;
|
||||
let mut icon_area = Rect::zero();
|
||||
let mut icon_area_clamped = Rect::zero();
|
||||
let mut icon_width = 0;
|
||||
let mut icon_data = [].as_ref();
|
||||
|
||||
if let Some((data, color, size)) = icon {
|
||||
if size.x <= ICON_MAX_SIZE && size.y <= ICON_MAX_SIZE {
|
||||
icon_width = size.x;
|
||||
icon_area = Rect::from_center_and_size(center, size);
|
||||
icon_area_clamped = icon_area.clamp(constant::screen());
|
||||
icon_data = data;
|
||||
use_icon = true;
|
||||
icon_colortable = display::get_color_table(color, bg_color);
|
||||
}
|
||||
}
|
||||
|
||||
let show_all = !indeterminate && progress >= 1000;
|
||||
let inverted = !indeterminate && progress > 500;
|
||||
let (start_vector, end_vector) = get_loader_vectors(indeterminate, progress);
|
||||
|
||||
let n_start = Point::new(-start_vector.y, start_vector.x);
|
||||
|
||||
for y_c in r.y0..r.y1 {
|
||||
for x_c in r.x0..r.x1 {
|
||||
let p = Point::new(x_c, y_c);
|
||||
let mut icon_pixel = false;
|
||||
|
||||
let mut underlying_color = bg_color;
|
||||
|
||||
if use_icon && icon_area_clamped.contains(p) {
|
||||
let x = x_c - center.x;
|
||||
let y = y_c - center.y;
|
||||
if (x as i32 * x as i32 + y as i32 * y as i32) <= dim.in_inner_anti {
|
||||
let x_i = x_c - icon_area.x0;
|
||||
let y_i = y_c - icon_area.y0;
|
||||
|
||||
let data = icon_data[(((x_i & 0xFE) + (y_i * icon_width)) / 2) as usize];
|
||||
if (x_i & 0x01) == 0 {
|
||||
underlying_color = icon_colortable[(data & 0xF) as usize];
|
||||
} else {
|
||||
underlying_color = icon_colortable[(data >> 4) as usize];
|
||||
}
|
||||
icon_pixel = true;
|
||||
}
|
||||
}
|
||||
|
||||
if clamped.contains(p) && !icon_pixel {
|
||||
let pix_c_idx = loader_get_pixel_color_idx(
|
||||
show_all,
|
||||
inverted,
|
||||
end_vector,
|
||||
n_start,
|
||||
Point::new(x_c, y_c),
|
||||
center,
|
||||
dim,
|
||||
);
|
||||
underlying_color = colortable[pix_c_idx as usize];
|
||||
}
|
||||
|
||||
display::pixeldata(underlying_color);
|
||||
}
|
||||
}
|
||||
|
||||
display::pixeldata_dirty();
|
||||
}
|
||||
|
||||
#[cfg(feature = "dma2d")]
|
||||
pub fn loader_rust(
|
||||
dim: LoaderDimensions,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
progress: u16,
|
||||
indeterminate: bool,
|
||||
icon: Option<(&[u8], Color, Offset)>,
|
||||
) {
|
||||
let center = screen().center() + Offset::new(0, y_offset);
|
||||
let r = Rect::from_center_and_size(center, Offset::uniform(LOADER_OUTER * 2));
|
||||
let clamped = r.clamp(constant::screen());
|
||||
display::set_window(clamped);
|
||||
|
||||
let center = r.center();
|
||||
|
||||
let mut use_icon = false;
|
||||
let mut icon_area = Rect::zero();
|
||||
let mut icon_area_clamped = Rect::zero();
|
||||
let mut icon_width = 0;
|
||||
let mut icon_offset = 0;
|
||||
let mut icon_color = Color::from_u16(0);
|
||||
let mut icon_data = [].as_ref();
|
||||
|
||||
if let Some((data, color, size)) = icon {
|
||||
if size.x <= ICON_MAX_SIZE && size.y <= ICON_MAX_SIZE {
|
||||
icon_width = size.x;
|
||||
icon_area = Rect::from_center_and_size(center, size);
|
||||
icon_area_clamped = icon_area.clamp(constant::screen());
|
||||
icon_offset = (icon_area_clamped.x0 - r.x0) / 2;
|
||||
icon_color = color;
|
||||
icon_data = data;
|
||||
use_icon = true;
|
||||
}
|
||||
}
|
||||
|
||||
let show_all = !indeterminate && progress >= 1000;
|
||||
let inverted = !indeterminate && progress > 500;
|
||||
let (start_vector, end_vector) = get_loader_vectors(indeterminate, progress);
|
||||
|
||||
let n_start = Point::new(-start_vector.y, start_vector.x);
|
||||
|
||||
let mut b1 = buffers::BufferLine16bpp::get();
|
||||
let mut b2 = buffers::BufferLine16bpp::get();
|
||||
let mut ib1 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut ib2 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut empty_line = buffers::BufferLine4bpp::get_cleared();
|
||||
|
||||
dma2d_setup_4bpp_over_4bpp(fg_color.into(), bg_color.into(), icon_color.into());
|
||||
|
||||
for y_c in r.y0..r.y1 {
|
||||
let mut icon_buffer = &mut *empty_line;
|
||||
let icon_buffer_used;
|
||||
let loader_buffer;
|
||||
|
||||
if y_c % 2 == 0 {
|
||||
icon_buffer_used = &mut *ib1;
|
||||
loader_buffer = &mut *b1;
|
||||
} else {
|
||||
icon_buffer_used = &mut *ib2;
|
||||
loader_buffer = &mut *b2;
|
||||
}
|
||||
|
||||
if use_icon && y_c >= icon_area_clamped.y0 && y_c < icon_area_clamped.y1 {
|
||||
let y_i = y_c - icon_area.y0;
|
||||
|
||||
// Optimally, we should cut corners of the icon if it happens to be large enough
|
||||
// to invade loader area. but this would require calculation of circle chord
|
||||
// length (since we need to limit data copied to the buffer),
|
||||
// which requires expensive SQRT. Therefore, when using this method of loader
|
||||
// drawing, special care needs to be taken to ensure that the icons
|
||||
// have transparent corners.
|
||||
|
||||
icon_buffer_used.buffer[icon_offset as usize..(icon_offset + icon_width / 2) as usize]
|
||||
.copy_from_slice(
|
||||
&icon_data[(y_i * (icon_width / 2)) as usize
|
||||
..((y_i + 1) * (icon_width / 2)) as usize],
|
||||
);
|
||||
icon_buffer = icon_buffer_used;
|
||||
}
|
||||
|
||||
let mut pix_c_idx_prev: u8 = 0;
|
||||
|
||||
for x_c in r.x0..r.x1 {
|
||||
let p = Point::new(x_c, y_c);
|
||||
|
||||
let pix_c_idx = if clamped.contains(p) {
|
||||
loader_get_pixel_color_idx(
|
||||
show_all,
|
||||
inverted,
|
||||
end_vector,
|
||||
n_start,
|
||||
Point::new(x_c, y_c),
|
||||
center,
|
||||
dim,
|
||||
)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let x = x_c - r.x0;
|
||||
if x % 2 == 0 {
|
||||
pix_c_idx_prev = pix_c_idx;
|
||||
} else {
|
||||
loader_buffer.buffer[(x >> 1) as usize] = pix_c_idx_prev | pix_c_idx << 4;
|
||||
}
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
unsafe {
|
||||
dma2d_start_blend(&icon_buffer.buffer, &loader_buffer.buffer, clamped.width());
|
||||
}
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
}
|
@ -1,333 +0,0 @@
|
||||
use crate::ui::{
|
||||
constant,
|
||||
constant::{screen, LOADER_INNER, LOADER_OUTER},
|
||||
display,
|
||||
display::{toif::Icon, Color},
|
||||
geometry::{Offset, Point, Rect},
|
||||
};
|
||||
|
||||
use crate::trezorhal::{
|
||||
buffers,
|
||||
dma2d::{dma2d_setup_4bpp_over_4bpp, dma2d_start_blend, dma2d_wait_for_transfer},
|
||||
};
|
||||
|
||||
const ICON_MAX_SIZE: i16 = constant::LOADER_ICON_MAX_SIZE;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LoaderDimensions {
|
||||
in_inner_anti: i32,
|
||||
inner_min: i32,
|
||||
outer_out_anti: i32,
|
||||
outer_max: i32,
|
||||
}
|
||||
|
||||
impl LoaderDimensions {
|
||||
pub fn new(outer: i16, inner: i16) -> Self {
|
||||
let outer: f32 = outer.into();
|
||||
let inner: f32 = inner.into();
|
||||
Self {
|
||||
in_inner_anti: ((inner + 0.5) * (inner + 0.5)) as i32,
|
||||
inner_min: ((inner + 1.5) * (inner + 1.5)) as i32,
|
||||
outer_out_anti: ((outer - 1.5) * (outer - 1.5)) as i32,
|
||||
outer_max: ((outer - 0.5) * (outer - 0.5)) as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loader_circular_uncompress(
|
||||
dim: LoaderDimensions,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
progress: u16,
|
||||
indeterminate: bool,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
if let Some((icon, color)) = icon {
|
||||
let toif_size = icon.toif.size();
|
||||
if toif_size.x <= ICON_MAX_SIZE && toif_size.y <= ICON_MAX_SIZE {
|
||||
let mut icon_data = [0_u8; ((ICON_MAX_SIZE * ICON_MAX_SIZE) / 2) as usize];
|
||||
icon.toif.uncompress(&mut icon_data);
|
||||
let i = Some((icon_data.as_ref(), color, toif_size));
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
i,
|
||||
);
|
||||
} else {
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
None,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
loader_rust(
|
||||
dim,
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
indeterminate,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loader_circular(
|
||||
progress: u16,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
loader_circular_uncompress(
|
||||
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
false,
|
||||
icon,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn loader_circular_indeterminate(
|
||||
progress: u16,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
loader_circular_uncompress(
|
||||
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
|
||||
y_offset,
|
||||
fg_color,
|
||||
bg_color,
|
||||
progress,
|
||||
true,
|
||||
icon,
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_loader_vectors(indeterminate: bool, progress: u16) -> (Point, Point) {
|
||||
let (start_progress, end_progress) = if indeterminate {
|
||||
const LOADER_INDETERMINATE_WIDTH: u16 = 100;
|
||||
(
|
||||
(progress + 1000 - LOADER_INDETERMINATE_WIDTH) % 1000,
|
||||
(progress + LOADER_INDETERMINATE_WIDTH) % 1000,
|
||||
)
|
||||
} else {
|
||||
(0, progress)
|
||||
};
|
||||
|
||||
let start = ((360 * start_progress as i32) / 1000) % 360;
|
||||
let end = ((360 * end_progress as i32) / 1000) % 360;
|
||||
|
||||
let start_vector;
|
||||
let end_vector;
|
||||
|
||||
if indeterminate {
|
||||
start_vector = display::get_vector(start as _);
|
||||
end_vector = display::get_vector(end as _);
|
||||
} else if progress >= 1000 {
|
||||
start_vector = Point::zero();
|
||||
end_vector = Point::zero();
|
||||
} else if progress > 500 {
|
||||
start_vector = display::get_vector(end as _);
|
||||
end_vector = display::get_vector(start as _);
|
||||
} else {
|
||||
start_vector = display::get_vector(start as _);
|
||||
end_vector = display::get_vector(end as _);
|
||||
}
|
||||
|
||||
(start_vector, end_vector)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn loader_get_pixel_color_idx(
|
||||
show_all: bool,
|
||||
inverted: bool,
|
||||
end_vector: Point,
|
||||
n_start: Point,
|
||||
c: Point,
|
||||
center: Point,
|
||||
dim: LoaderDimensions,
|
||||
) -> u8 {
|
||||
let y_p = -(c.y - center.y);
|
||||
let x_p = c.x - center.x;
|
||||
|
||||
let vx = Point::new(x_p, y_p);
|
||||
let n_vx = Point::new(-y_p, x_p);
|
||||
|
||||
let d = y_p as i32 * y_p as i32 + x_p as i32 * x_p as i32;
|
||||
|
||||
let included = if inverted {
|
||||
!display::is_clockwise_or_equal(n_start, vx)
|
||||
|| !display::is_clockwise_or_equal_inc(n_vx, end_vector)
|
||||
} else {
|
||||
display::is_clockwise_or_equal(n_start, vx)
|
||||
&& display::is_clockwise_or_equal_inc(n_vx, end_vector)
|
||||
};
|
||||
|
||||
// The antialiasing calculation below uses simplified distance difference
|
||||
// calculation. Optimally, SQRT should be used, but assuming
|
||||
// diameter large enough and antialiasing over distance
|
||||
// r_outer-r_inner = 1, the difference between simplified:
|
||||
// (d^2-r_inner^2)/(r_outer^2-r_inner^2) and precise: (sqrt(d^2)
|
||||
// - r_inner)/(r_outer-r_inner) is negligible
|
||||
if show_all || included {
|
||||
//active part
|
||||
if d <= dim.in_inner_anti {
|
||||
0
|
||||
} else if d <= dim.inner_min {
|
||||
((15 * (d - dim.in_inner_anti)) / (dim.inner_min - dim.in_inner_anti)) as u8
|
||||
} else if d <= dim.outer_out_anti {
|
||||
15
|
||||
} else if d <= dim.outer_max {
|
||||
(15 - ((15 * (d - dim.outer_out_anti)) / (dim.outer_max - dim.outer_out_anti))) as u8
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
//inactive part
|
||||
if d <= dim.in_inner_anti {
|
||||
0
|
||||
} else if d <= dim.inner_min {
|
||||
((4 * (d - dim.in_inner_anti)) / (dim.inner_min - dim.in_inner_anti)) as u8
|
||||
} else if d <= dim.outer_out_anti {
|
||||
4
|
||||
} else if d <= dim.outer_max {
|
||||
4 - ((4 * (d - dim.outer_out_anti)) / (dim.outer_max - dim.outer_out_anti)) as u8
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loader_rust(
|
||||
dim: LoaderDimensions,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
progress: u16,
|
||||
indeterminate: bool,
|
||||
icon: Option<(&[u8], Color, Offset)>,
|
||||
) {
|
||||
let center = screen().center() + Offset::new(0, y_offset);
|
||||
let r = Rect::from_center_and_size(center, Offset::uniform(LOADER_OUTER * 2));
|
||||
let clamped = r.clamp(constant::screen());
|
||||
display::set_window(clamped);
|
||||
|
||||
let center = r.center();
|
||||
|
||||
let mut use_icon = false;
|
||||
let mut icon_area = Rect::zero();
|
||||
|
||||
let mut icon_area_clamped = Rect::zero();
|
||||
let mut icon_width = 0;
|
||||
let mut icon_offset = 0;
|
||||
let mut icon_color = Color::from_u16(0);
|
||||
let mut icon_data = [].as_ref();
|
||||
|
||||
if let Some((data, color, size)) = icon {
|
||||
if size.x <= ICON_MAX_SIZE && size.y <= ICON_MAX_SIZE {
|
||||
icon_width = size.x;
|
||||
icon_area = Rect::from_center_and_size(center, size);
|
||||
icon_area_clamped = icon_area.clamp(constant::screen());
|
||||
icon_offset = (icon_area_clamped.x0 - r.x0) / 2;
|
||||
icon_color = color;
|
||||
icon_data = data;
|
||||
use_icon = true;
|
||||
}
|
||||
}
|
||||
|
||||
let show_all = !indeterminate && progress >= 1000;
|
||||
let inverted = !indeterminate && progress > 500;
|
||||
let (start_vector, end_vector) = get_loader_vectors(indeterminate, progress);
|
||||
|
||||
let n_start = Point::new(-start_vector.y, start_vector.x);
|
||||
|
||||
let mut b1 = buffers::BufferLine16bpp::get();
|
||||
let mut b2 = buffers::BufferLine16bpp::get();
|
||||
let mut ib1 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut ib2 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut empty_line = buffers::BufferLine4bpp::get_cleared();
|
||||
|
||||
dma2d_setup_4bpp_over_4bpp(fg_color.into(), bg_color.into(), icon_color.into());
|
||||
|
||||
for y_c in r.y0..r.y1 {
|
||||
let mut icon_buffer = &mut *empty_line;
|
||||
let icon_buffer_used;
|
||||
let loader_buffer;
|
||||
|
||||
if y_c % 2 == 0 {
|
||||
icon_buffer_used = &mut *ib1;
|
||||
loader_buffer = &mut *b1;
|
||||
} else {
|
||||
icon_buffer_used = &mut *ib2;
|
||||
loader_buffer = &mut *b2;
|
||||
}
|
||||
|
||||
if use_icon && y_c >= icon_area_clamped.y0 && y_c < icon_area_clamped.y1 {
|
||||
let y_i = y_c - icon_area.y0;
|
||||
|
||||
// Optimally, we should cut corners of the icon if it happens to be large enough
|
||||
// to invade loader area. but this would require calculation of circle chord
|
||||
// length (since we need to limit data copied to the buffer),
|
||||
// which requires expensive SQRT. Therefore, when using this method of loader
|
||||
// drawing, special care needs to be taken to ensure that the icons
|
||||
// have transparent corners.
|
||||
|
||||
icon_buffer_used.buffer[icon_offset as usize..(icon_offset + icon_width / 2) as usize]
|
||||
.copy_from_slice(
|
||||
&icon_data[(y_i * (icon_width / 2)) as usize
|
||||
..((y_i + 1) * (icon_width / 2)) as usize],
|
||||
);
|
||||
icon_buffer = icon_buffer_used;
|
||||
}
|
||||
|
||||
let mut pix_c_idx_prev: u8 = 0;
|
||||
|
||||
for x_c in r.x0..r.x1 {
|
||||
let p = Point::new(x_c, y_c);
|
||||
|
||||
let pix_c_idx = if clamped.contains(p) {
|
||||
loader_get_pixel_color_idx(
|
||||
show_all,
|
||||
inverted,
|
||||
end_vector,
|
||||
n_start,
|
||||
Point::new(x_c, y_c),
|
||||
center,
|
||||
dim,
|
||||
)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let x = x_c - r.x0;
|
||||
if x % 2 == 0 {
|
||||
pix_c_idx_prev = pix_c_idx;
|
||||
} else {
|
||||
loader_buffer.buffer[(x >> 1) as usize] = pix_c_idx_prev | pix_c_idx << 4;
|
||||
}
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
unsafe {
|
||||
dma2d_start_blend(&icon_buffer.buffer, &loader_buffer.buffer, clamped.width());
|
||||
}
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
mod circular;
|
||||
#[cfg(feature = "dma2d")]
|
||||
mod circular_thin;
|
||||
mod rectangular;
|
||||
mod small;
|
||||
mod starry;
|
||||
|
||||
use crate::ui::display::{Color, Icon};
|
||||
|
||||
#[cfg(feature = "model_tt")]
|
||||
use crate::ui::display::loader::circular::{
|
||||
loader_circular as determinate, loader_circular_indeterminate as indeterminate,
|
||||
};
|
||||
#[cfg(any(feature = "model_tt", feature = "model_mercury"))]
|
||||
pub use crate::ui::display::loader::circular::{loader_circular_uncompress, LoaderDimensions};
|
||||
|
||||
#[cfg(all(feature = "model_mercury", not(feature = "model_tt")))]
|
||||
use crate::ui::display::loader::circular_thin::{
|
||||
loader_circular as determinate, loader_circular_indeterminate as indeterminate,
|
||||
};
|
||||
|
||||
#[cfg(all(not(feature = "model_tt"), not(feature = "model_mercury")))]
|
||||
use crate::ui::display::loader::rectangular::loader_rectangular as determinate;
|
||||
#[cfg(all(not(feature = "model_tt"), not(feature = "model_mercury")))]
|
||||
use crate::ui::display::loader::starry::loader_starry_indeterminate as indeterminate;
|
||||
|
||||
pub use small::loader_small_indeterminate;
|
||||
|
||||
pub const LOADER_MIN: u16 = 0;
|
||||
pub const LOADER_MAX: u16 = 1000;
|
||||
|
||||
pub fn loader(
|
||||
progress: u16,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
determinate(progress, y_offset, fg_color, bg_color, icon);
|
||||
}
|
||||
|
||||
pub fn loader_indeterminate(
|
||||
progress: u16,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
indeterminate(progress, y_offset, fg_color, bg_color, icon);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
use crate::ui::{
|
||||
constant::{screen, LOADER_INNER},
|
||||
display,
|
||||
display::{Color, Icon},
|
||||
geometry::{Offset, Rect},
|
||||
};
|
||||
|
||||
pub fn loader_rectangular(
|
||||
progress: u16,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
let area = Rect::from_center_and_size(screen().center(), Offset::uniform(LOADER_INNER as _))
|
||||
.translate(Offset::y(y_offset));
|
||||
|
||||
display::rect_rounded2_partial(
|
||||
area,
|
||||
fg_color,
|
||||
bg_color,
|
||||
(100 * progress as u32 / 1000) as i16,
|
||||
icon,
|
||||
);
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
use crate::ui::{
|
||||
constant::screen,
|
||||
display::{rect_fill, Color},
|
||||
geometry::{Offset, Point, Rect},
|
||||
};
|
||||
use core::f32::consts::SQRT_2;
|
||||
|
||||
const STAR_COUNT: usize = 8;
|
||||
const RADIUS: i16 = 3;
|
||||
const DIAGONAL: i16 = ((RADIUS as f32 * SQRT_2) / 2_f32) as i16;
|
||||
const LOADER_SIZE: Offset = Offset::uniform(2 * RADIUS + 3);
|
||||
|
||||
fn fill_point(point: Point, color: Color) {
|
||||
let area = Rect::from_center_and_size(point, Offset::uniform(1));
|
||||
rect_fill(area, color);
|
||||
}
|
||||
|
||||
pub fn loader_small_indeterminate(progress: u16, y_offset: i16, fg_color: Color, bg_color: Color) {
|
||||
let area =
|
||||
Rect::from_center_and_size(screen().center(), LOADER_SIZE).translate(Offset::y(y_offset));
|
||||
|
||||
rect_fill(area, bg_color);
|
||||
|
||||
// Offset of the normal point and then the extra offset for the main point
|
||||
let offsets: [(Offset, Offset); STAR_COUNT] = [
|
||||
(Offset::y(-RADIUS), Offset::y(-1)),
|
||||
(Offset::new(DIAGONAL, -DIAGONAL), Offset::new(1, -1)),
|
||||
(Offset::x(RADIUS), Offset::x(1)),
|
||||
(Offset::new(DIAGONAL, DIAGONAL), Offset::new(1, 1)),
|
||||
(Offset::y(RADIUS), Offset::y(1)),
|
||||
(Offset::new(-DIAGONAL, DIAGONAL), Offset::new(-1, 1)),
|
||||
(Offset::x(-RADIUS), Offset::x(-1)),
|
||||
(Offset::new(-DIAGONAL, -DIAGONAL), Offset::new(-1, -1)),
|
||||
];
|
||||
|
||||
let main_idx = (STAR_COUNT * progress as usize / 1000) % STAR_COUNT;
|
||||
|
||||
for (i, (point_offset, main_offset)) in offsets.iter().enumerate() {
|
||||
// Skip it when it is behind the main one (clockwise)
|
||||
if (main_idx + 1) % STAR_COUNT == i {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Draw the normal point
|
||||
let point = area.center() + *point_offset;
|
||||
fill_point(point, fg_color);
|
||||
|
||||
// Draw the main point
|
||||
if main_idx == i {
|
||||
fill_point(point + *main_offset, fg_color);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
use crate::ui::{
|
||||
constant::{screen, LOADER_OUTER},
|
||||
display::{rect_fill, rect_fill_rounded, Color, Icon},
|
||||
geometry::{Alignment2D, Offset, Point, Rect},
|
||||
};
|
||||
use core::f32::consts::SQRT_2;
|
||||
|
||||
const SIZE_SMALL: i16 = 2;
|
||||
const SIZE_MEDIUM: i16 = 4;
|
||||
const SIZE_LARGE: i16 = 6;
|
||||
const RADIUS: i16 = 13;
|
||||
const DIAGONAL: i16 = ((RADIUS as f32 * SQRT_2) / 2_f32) as i16;
|
||||
|
||||
fn star_small(center: Point, fg: Color, _bg: Color) {
|
||||
let r = Rect::from_center_and_size(center, Offset::uniform(SIZE_SMALL));
|
||||
rect_fill(r, fg);
|
||||
}
|
||||
|
||||
fn star_medium(center: Point, fg: Color, bg: Color) {
|
||||
let r = Rect::from_center_and_size(center, Offset::uniform(SIZE_MEDIUM));
|
||||
rect_fill_rounded(r, fg, bg, 1);
|
||||
}
|
||||
|
||||
fn star_large(center: Point, fg: Color, bg: Color) {
|
||||
let r = Rect::from_center_and_size(center, Offset::uniform(SIZE_LARGE));
|
||||
rect_fill_rounded(r, fg, bg, 2);
|
||||
}
|
||||
|
||||
pub fn loader_starry_indeterminate(
|
||||
progress: u16,
|
||||
y_offset: i16,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
let area = Rect::from_center_and_size(screen().center(), Offset::uniform(LOADER_OUTER as _))
|
||||
.translate(Offset::y(y_offset));
|
||||
|
||||
rect_fill(area, bg_color);
|
||||
|
||||
let coords = [
|
||||
Point::new(area.center().x, area.center().y - RADIUS),
|
||||
Point::new(area.center().x + DIAGONAL, area.center().y - DIAGONAL),
|
||||
Point::new(area.center().x + RADIUS, area.center().y),
|
||||
Point::new(area.center().x + DIAGONAL, area.center().y + DIAGONAL),
|
||||
Point::new(area.center().x, area.center().y + RADIUS),
|
||||
Point::new(area.center().x - DIAGONAL, area.center().y + DIAGONAL),
|
||||
Point::new(area.center().x - RADIUS, area.center().y),
|
||||
Point::new(area.center().x - DIAGONAL, area.center().y - DIAGONAL),
|
||||
];
|
||||
|
||||
let big_idx = (progress / 125) as usize % 8;
|
||||
|
||||
for (i, c) in coords.iter().enumerate() {
|
||||
if i == big_idx {
|
||||
star_large(*c, fg_color, bg_color);
|
||||
} else if (big_idx + 1) % 8 == i || (big_idx - 1) % 8 == i {
|
||||
star_medium(*c, fg_color, bg_color);
|
||||
} else {
|
||||
star_small(*c, fg_color, bg_color);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((icon, color)) = icon {
|
||||
icon.draw(area.center(), Alignment2D::CENTER, color, bg_color);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,159 +0,0 @@
|
||||
use trezor_tjpgdec::{BlackHoleOutput, JpegOutput};
|
||||
pub use trezor_tjpgdec::{BufferInput, Error, JDEC};
|
||||
|
||||
use crate::{
|
||||
trezorhal::{
|
||||
buffers::{BufferJpeg, BufferJpegWork},
|
||||
display::pixeldata,
|
||||
},
|
||||
ui::{
|
||||
constant,
|
||||
display::set_window,
|
||||
geometry::{Offset, Point, Rect},
|
||||
},
|
||||
};
|
||||
|
||||
pub fn jpeg(data: &[u8], pos: Point, scale: u8) {
|
||||
let mut buffer = BufferJpegWork::get_cleared();
|
||||
let pool = buffer.buffer.as_mut_slice();
|
||||
let mut out = PixelDataOutput(pos);
|
||||
let mut inp = BufferInput(data);
|
||||
if let Ok(mut jd) = JDEC::new(&mut inp, pool) {
|
||||
let _ = jd.set_scale(scale);
|
||||
let _ = jd.decomp(&mut inp, &mut out);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jpeg_info(data: &[u8]) -> Option<(Offset, i16)> {
|
||||
let mut buffer = BufferJpegWork::get_cleared();
|
||||
let pool = buffer.buffer.as_mut_slice();
|
||||
let mut inp = BufferInput(data);
|
||||
let result = if let Ok(jd) = JDEC::new(&mut inp, pool) {
|
||||
let mcu_height = jd.mcu_height();
|
||||
if mcu_height > 16 {
|
||||
return None;
|
||||
}
|
||||
Some((Offset::new(jd.width(), jd.height()), mcu_height))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
pub fn jpeg_test(data: &[u8]) -> bool {
|
||||
let mut buffer = BufferJpegWork::get_cleared();
|
||||
let pool = buffer.buffer.as_mut_slice();
|
||||
let mut inp = BufferInput(data);
|
||||
let result = if let Ok(mut jd) = JDEC::new(&mut inp, pool) {
|
||||
if jd.mcu_height() > 16 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut out = BlackHoleOutput;
|
||||
let mut res = jd.decomp(&mut inp, &mut out);
|
||||
while res == Err(Error::Interrupted) {
|
||||
res = jd.decomp(&mut inp, &mut out);
|
||||
}
|
||||
res.is_ok()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
pub struct BufferOutput {
|
||||
buffer: BufferJpeg,
|
||||
buffer_width: i16,
|
||||
buffer_height: i16,
|
||||
current_line: i16,
|
||||
current_line_pix: i16,
|
||||
}
|
||||
|
||||
impl BufferOutput {
|
||||
pub fn new(buffer_width: i16, buffer_height: i16) -> Self {
|
||||
Self {
|
||||
buffer: BufferJpeg::get_cleared(),
|
||||
buffer_width,
|
||||
buffer_height,
|
||||
current_line: 0,
|
||||
current_line_pix: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer(&mut self) -> &mut BufferJpeg {
|
||||
&mut self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl JpegOutput for BufferOutput {
|
||||
fn write(
|
||||
&mut self,
|
||||
jd: &JDEC,
|
||||
rect_origin: (u32, u32),
|
||||
rect_size: (u32, u32),
|
||||
bitmap: &[u16],
|
||||
) -> bool {
|
||||
let w = rect_size.0 as i16;
|
||||
let h = rect_size.1 as i16;
|
||||
let x = rect_origin.0 as i16;
|
||||
|
||||
if h > self.buffer_height {
|
||||
// unsupported height, call and let know
|
||||
return true;
|
||||
}
|
||||
|
||||
let buffer_len = (self.buffer_width * self.buffer_height) as usize;
|
||||
|
||||
for i in 0..h {
|
||||
for j in 0..w {
|
||||
let buffer_pos = ((x + j) + (i * self.buffer_width)) as usize;
|
||||
if buffer_pos < buffer_len {
|
||||
self.buffer.buffer[buffer_pos] = bitmap[(i * w + j) as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.current_line_pix += w;
|
||||
|
||||
if self.current_line_pix >= jd.width() {
|
||||
self.current_line_pix = 0;
|
||||
self.current_line += jd.mcu_height();
|
||||
// finished line, abort and continue later
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PixelDataOutput(Point);
|
||||
|
||||
impl JpegOutput for PixelDataOutput {
|
||||
fn write(
|
||||
&mut self,
|
||||
_jd: &JDEC,
|
||||
rect_origin: (u32, u32),
|
||||
rect_size: (u32, u32),
|
||||
bitmap: &[u16],
|
||||
) -> bool {
|
||||
let pos = self.0;
|
||||
let rect = Rect::from_top_left_and_size(
|
||||
Point::new(rect_origin.0 as i16, rect_origin.1 as i16),
|
||||
Offset::new(rect_size.0 as i16, rect_size.1 as i16),
|
||||
);
|
||||
let r = rect.translate(pos.into());
|
||||
let clamped = r.clamp(constant::screen());
|
||||
set_window(clamped);
|
||||
for py in r.y0..r.y1 {
|
||||
for px in r.x0..r.x1 {
|
||||
let p = Point::new(px, py);
|
||||
if clamped.contains(p) {
|
||||
let off = p - r.top_left();
|
||||
let c = bitmap[(off.y * rect.width() + off.x) as usize];
|
||||
pixeldata(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
@ -1,33 +1,8 @@
|
||||
use crate::{
|
||||
error::{value_error, Error},
|
||||
trezorhal::uzlib::{UzlibContext, UZLIB_WINDOW_SIZE},
|
||||
ui::{
|
||||
component::image::Image,
|
||||
constant,
|
||||
display::{get_offset, pixeldata_dirty, set_window},
|
||||
geometry::{Alignment2D, Offset, Point, Rect},
|
||||
},
|
||||
ui::geometry::Offset,
|
||||
};
|
||||
|
||||
#[cfg(feature = "dma2d")]
|
||||
use crate::{
|
||||
trezorhal::{
|
||||
buffers::BufferLine16bpp,
|
||||
dma2d::{dma2d_setup_16bpp, dma2d_start, dma2d_wait_for_transfer},
|
||||
},
|
||||
ui::display::process_buffer,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "framebuffer"))]
|
||||
use crate::ui::display::{get_color_table, pixeldata};
|
||||
|
||||
#[cfg(feature = "framebuffer")]
|
||||
use crate::trezorhal::{buffers::BufferLine4bpp, dma2d::dma2d_setup_4bpp};
|
||||
#[cfg(feature = "framebuffer")]
|
||||
use core::cmp::max;
|
||||
|
||||
use super::Color;
|
||||
|
||||
const TOIF_HEADER_LENGTH: usize = 12;
|
||||
|
||||
#[derive(PartialEq, Debug, Eq, FromPrimitive, Clone, Copy)]
|
||||
@ -38,160 +13,6 @@ pub enum ToifFormat {
|
||||
GrayScaleEH = 3, // even hi
|
||||
}
|
||||
|
||||
pub fn render_icon(icon: &Icon, center: Point, fg_color: Color, bg_color: Color) {
|
||||
render_toif(&icon.toif, center, fg_color, bg_color);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "framebuffer"))]
|
||||
pub fn render_toif(toif: &Toif, center: Point, fg_color: Color, bg_color: Color) {
|
||||
let r = Rect::from_center_and_size(center, toif.size());
|
||||
let area = r.translate(get_offset());
|
||||
let clamped = area.clamp(constant::screen());
|
||||
let colortable = get_color_table(fg_color, bg_color);
|
||||
|
||||
set_window(clamped);
|
||||
|
||||
let mut dest = [0_u8; 1];
|
||||
|
||||
let mut window = [0; UZLIB_WINDOW_SIZE];
|
||||
let mut ctx = toif.decompression_context(Some(&mut window));
|
||||
|
||||
for py in area.y0..area.y1 {
|
||||
for px in area.x0..area.x1 {
|
||||
let p = Point::new(px, py);
|
||||
let x = p.x - area.x0;
|
||||
|
||||
if clamped.contains(p) {
|
||||
if x % 2 == 0 {
|
||||
unwrap!(ctx.uncompress(&mut dest), "Decompression failed");
|
||||
pixeldata(colortable[(dest[0] & 0xF) as usize]);
|
||||
} else {
|
||||
pixeldata(colortable[(dest[0] >> 4) as usize]);
|
||||
}
|
||||
} else if x % 2 == 0 {
|
||||
//continue unzipping but dont write to display
|
||||
unwrap!(ctx.uncompress(&mut dest), "Decompression failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pixeldata_dirty();
|
||||
}
|
||||
|
||||
#[cfg(feature = "framebuffer")]
|
||||
pub fn render_toif(toif: &Toif, center: Point, fg_color: Color, bg_color: Color) {
|
||||
let r = Rect::from_center_and_size(center, toif.size());
|
||||
let area = r.translate(get_offset());
|
||||
let clamped = area.clamp(constant::screen()).ensure_even_width();
|
||||
|
||||
set_window(clamped);
|
||||
|
||||
let mut b1 = BufferLine4bpp::get_cleared();
|
||||
let mut b2 = BufferLine4bpp::get_cleared();
|
||||
|
||||
let mut window = [0; UZLIB_WINDOW_SIZE];
|
||||
let mut ctx = toif.decompression_context(Some(&mut window));
|
||||
|
||||
dma2d_setup_4bpp(fg_color.into(), bg_color.into());
|
||||
|
||||
let x_shift = max(0, clamped.x0 - area.x0);
|
||||
|
||||
for y in area.y0..clamped.y1 {
|
||||
let img_buffer_used = if y % 2 == 0 { &mut b1 } else { &mut b2 };
|
||||
|
||||
unwrap!(ctx.uncompress(&mut (&mut img_buffer_used.buffer)[..(area.width() / 2) as usize]));
|
||||
|
||||
if y >= clamped.y0 {
|
||||
dma2d_wait_for_transfer();
|
||||
unsafe {
|
||||
dma2d_start(
|
||||
&img_buffer_used.buffer
|
||||
[(x_shift / 2) as usize..((clamped.width() + x_shift) / 2) as usize],
|
||||
clamped.width(),
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
pixeldata_dirty();
|
||||
}
|
||||
|
||||
#[cfg(feature = "dma2d")]
|
||||
pub fn image(image: &Image, center: Point) {
|
||||
let r = Rect::from_center_and_size(center, image.toif.size());
|
||||
let area = r.translate(get_offset());
|
||||
let clamped = area.clamp(constant::screen());
|
||||
|
||||
set_window(clamped);
|
||||
|
||||
let mut window = [0; UZLIB_WINDOW_SIZE];
|
||||
let mut ctx = image.toif.decompression_context(Some(&mut window));
|
||||
|
||||
let mut b1 = BufferLine16bpp::get_cleared();
|
||||
let mut b2 = BufferLine16bpp::get_cleared();
|
||||
|
||||
let mut decompressed_lines = 0;
|
||||
let clamp_x = if clamped.x0 > area.x0 {
|
||||
area.x0 - clamped.x0
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
dma2d_setup_16bpp();
|
||||
|
||||
for y in clamped.y0..clamped.y1 {
|
||||
let img_buffer_used = if y % 2 == 0 { &mut b1 } else { &mut b2 };
|
||||
|
||||
process_buffer(
|
||||
y,
|
||||
area,
|
||||
Offset::x(clamp_x),
|
||||
&mut ctx,
|
||||
&mut img_buffer_used.buffer,
|
||||
&mut decompressed_lines,
|
||||
16,
|
||||
);
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
unsafe { dma2d_start(&img_buffer_used.buffer, clamped.width()) };
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
pixeldata_dirty();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dma2d"))]
|
||||
pub fn image(image: &Image, center: Point) {
|
||||
let r = Rect::from_center_and_size(center, image.toif.size());
|
||||
let area = r.translate(get_offset());
|
||||
let clamped = area.clamp(constant::screen());
|
||||
|
||||
set_window(clamped);
|
||||
|
||||
let mut dest = [0_u8; 2];
|
||||
|
||||
let mut window = [0; UZLIB_WINDOW_SIZE];
|
||||
let mut ctx = image.toif.decompression_context(Some(&mut window));
|
||||
|
||||
for py in area.y0..area.y1 {
|
||||
for px in area.x0..area.x1 {
|
||||
let p = Point::new(px, py);
|
||||
|
||||
if clamped.contains(p) {
|
||||
unwrap!(ctx.uncompress(&mut dest), "Decompression failed");
|
||||
let c = Color::from_u16(u16::from_le_bytes(dest));
|
||||
pixeldata(c);
|
||||
} else {
|
||||
//continue unzipping but dont write to display
|
||||
unwrap!(ctx.uncompress(&mut dest), "Decompression failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pixeldata_dirty();
|
||||
}
|
||||
|
||||
/// Holding toif data and allowing it to draw itself.
|
||||
/// See https://docs.trezor.io/trezor-firmware/misc/toif.html for data format.
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
@ -259,14 +80,6 @@ impl<'i> Toif<'i> {
|
||||
Offset::new(self.width(), self.height())
|
||||
}
|
||||
|
||||
pub fn stride(&self) -> usize {
|
||||
if self.is_grayscale() {
|
||||
(self.width() + 1) as usize / 2
|
||||
} else {
|
||||
self.width() as usize * 2
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zdata(&self) -> &'i [u8] {
|
||||
&self.data[TOIF_HEADER_LENGTH..]
|
||||
}
|
||||
@ -274,25 +87,6 @@ impl<'i> Toif<'i> {
|
||||
pub fn original_data(&self) -> &'i [u8] {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn uncompress(&self, dest: &mut [u8]) {
|
||||
let mut ctx = self.decompression_context(None);
|
||||
unwrap!(ctx.uncompress(dest));
|
||||
}
|
||||
|
||||
pub fn decompression_context<'a>(
|
||||
&'a self,
|
||||
window: Option<&'a mut [u8; UZLIB_WINDOW_SIZE]>,
|
||||
) -> UzlibContext {
|
||||
UzlibContext::new(self.zdata(), window)
|
||||
}
|
||||
|
||||
/// Display the data with baseline Point, aligned according to the
|
||||
/// `alignment` argument.
|
||||
pub fn draw(&self, baseline: Point, alignment: Alignment2D, fg_color: Color, bg_color: Color) {
|
||||
let r = Rect::snap(baseline, self.size(), alignment);
|
||||
render_toif(self, r.center(), fg_color, bg_color);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
@ -330,11 +124,4 @@ impl Icon {
|
||||
..Self::new(data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Display the icon with baseline Point, aligned according to the
|
||||
/// `alignment` argument.
|
||||
pub fn draw(&self, baseline: Point, alignment: Alignment2D, fg_color: Color, bg_color: Color) {
|
||||
let r = Rect::snap(baseline, self.toif.size(), alignment);
|
||||
render_icon(self, r.center(), fg_color, bg_color);
|
||||
}
|
||||
}
|
||||
|
@ -93,10 +93,6 @@ impl<T: Component + Paginate> Component for SwipePage<T> {
|
||||
self.inner.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.inner.render(target)
|
||||
}
|
||||
|
@ -9,8 +9,9 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
||||
|
||||
#[cfg(feature = "button")]
|
||||
use crate::ui::event::ButtonEvent;
|
||||
#[cfg(feature = "new_rendering")]
|
||||
|
||||
use crate::ui::{display::Color, shape::render_on_display};
|
||||
|
||||
#[cfg(feature = "touch")]
|
||||
use crate::ui::{event::TouchEvent, geometry::Direction};
|
||||
use crate::{
|
||||
@ -141,14 +142,9 @@ where
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
self.inner.paint();
|
||||
#[cfg(feature = "new_rendering")]
|
||||
{
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
self.inner.render(target);
|
||||
});
|
||||
}
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
self.inner.render(target);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,10 +301,6 @@ impl LayoutObjInner {
|
||||
/// Run a paint pass over the component tree. Returns true if any component
|
||||
/// actually requested painting since last invocation of the function.
|
||||
fn obj_paint_if_requested(&mut self) -> bool {
|
||||
if self.repaint == Repaint::Full {
|
||||
display::clear();
|
||||
}
|
||||
|
||||
display::sync();
|
||||
|
||||
if self.repaint != Repaint::None {
|
||||
|
@ -15,7 +15,6 @@ use crate::ui::{
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
use crate::ui::{display::color::Color, shape::render_on_display};
|
||||
|
||||
pub trait ReturnToC {
|
||||
@ -68,21 +67,11 @@ fn touch_eval() -> Option<TouchEvent> {
|
||||
}
|
||||
|
||||
fn render(frame: &mut impl Component) {
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
{
|
||||
display::sync();
|
||||
frame.paint();
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
{
|
||||
display::sync();
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
frame.render(target);
|
||||
});
|
||||
display::refresh();
|
||||
}
|
||||
display::sync();
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
frame.render(target);
|
||||
});
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
pub fn run(frame: &mut impl Component<Msg = impl ReturnToC>) -> u32 {
|
||||
|
@ -6,7 +6,7 @@ pub mod component;
|
||||
pub mod constant;
|
||||
pub mod display;
|
||||
pub mod event;
|
||||
#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))]
|
||||
#[cfg(all(feature = "micropython", feature = "touch"))]
|
||||
pub mod flow;
|
||||
pub mod geometry;
|
||||
pub mod lerp;
|
||||
|
@ -102,15 +102,6 @@ impl<'a> Component for Intro<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.title.paint();
|
||||
self.text.paint();
|
||||
self.warn.paint();
|
||||
self.host.paint();
|
||||
self.menu.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
self.title.render(target);
|
||||
|
@ -101,14 +101,6 @@ impl Component for Menu {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.title.paint();
|
||||
self.close.paint();
|
||||
self.reboot.paint();
|
||||
self.reset.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
self.title.render(target);
|
||||
|
@ -31,10 +31,6 @@ use super::{
|
||||
|
||||
use crate::ui::{ui_features::UIFeaturesBootloader, UIFeaturesCommon};
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
use super::theme::BLACK;
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
use crate::ui::{
|
||||
display::{toif::Toif, LOADER_MAX},
|
||||
geometry::Alignment2D,
|
||||
@ -43,10 +39,8 @@ use crate::ui::{
|
||||
shape::render_on_display,
|
||||
};
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
use ufmt::uwrite;
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
use super::theme::bootloader::BLD_WARN_COLOR;
|
||||
use intro::Intro;
|
||||
use menu::Menu;
|
||||
@ -63,42 +57,6 @@ const SCREEN: Rect = ModelMercuryFeatures::SCREEN;
|
||||
const PROGRESS_TEXT_ORIGIN: Point = Point::new(2, 28);
|
||||
|
||||
impl ModelMercuryFeatures {
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
fn screen_progress(
|
||||
text: &str,
|
||||
progress: u16,
|
||||
initialize: bool,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
center_text: Option<&str>,
|
||||
) {
|
||||
let loader_offset: i16 = 19;
|
||||
let center_text_offset: i16 = 10;
|
||||
|
||||
if initialize {
|
||||
Self::fadeout();
|
||||
display::rect_fill(SCREEN, bg_color);
|
||||
}
|
||||
|
||||
display::text_left(PROGRESS_TEXT_ORIGIN, text, Font::NORMAL, BLD_FG, bg_color);
|
||||
display::loader(progress, 19, fg_color, bg_color, icon);
|
||||
if let Some(center_text) = center_text {
|
||||
display::text_center(
|
||||
SCREEN.center() + Offset::y(loader_offset + center_text_offset),
|
||||
center_text,
|
||||
Font::NORMAL,
|
||||
GREY,
|
||||
bg_color,
|
||||
);
|
||||
}
|
||||
display::refresh();
|
||||
if initialize {
|
||||
Self::fadein();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
fn screen_progress(
|
||||
text: &str,
|
||||
progress: u16,
|
||||
@ -170,17 +128,6 @@ impl UIFeaturesBootloader for ModelMercuryFeatures {
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
fn bld_continue_label(bg_color: Color) {
|
||||
display::text_center(
|
||||
Point::new(SCREEN.width() / 2, SCREEN.height() - 5),
|
||||
"click to continue ...",
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
bg_color,
|
||||
);
|
||||
}
|
||||
|
||||
fn screen_install_success(restart_seconds: u8, initial_setup: bool, complete_draw: bool) {
|
||||
let mut reboot_msg = BootloaderString::new();
|
||||
|
||||
@ -372,9 +319,6 @@ impl UIFeaturesBootloader for ModelMercuryFeatures {
|
||||
Self::fadeout();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
display::rect_fill(SCREEN, BLACK);
|
||||
|
||||
let mut frame = WelcomeScreen::new();
|
||||
show(&mut frame, false);
|
||||
|
||||
@ -443,7 +387,6 @@ impl UIFeaturesBootloader for ModelMercuryFeatures {
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
fn screen_boot(
|
||||
warning: bool,
|
||||
vendor_str: Option<&str>,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
constant::screen,
|
||||
display::{self, Font},
|
||||
display::Font,
|
||||
geometry::{Offset, Point, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
@ -36,34 +36,6 @@ impl Component for Welcome {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let at_width = Font::NORMAL.text_width("at ");
|
||||
|
||||
self.bg.paint();
|
||||
display::text_left(TEXT_ORIGIN, "Get started", Font::NORMAL, GREY, BLACK);
|
||||
display::text_left(
|
||||
TEXT_ORIGIN + Offset::y(STRIDE),
|
||||
"with your Trezor",
|
||||
Font::NORMAL,
|
||||
GREY,
|
||||
BLACK,
|
||||
);
|
||||
display::text_left(
|
||||
TEXT_ORIGIN + Offset::y(2 * STRIDE),
|
||||
"at",
|
||||
Font::NORMAL,
|
||||
GREY,
|
||||
BLACK,
|
||||
);
|
||||
display::text_left(
|
||||
TEXT_ORIGIN + Offset::new(at_width, 2 * STRIDE),
|
||||
"trezor.io/start",
|
||||
Font::NORMAL,
|
||||
WHITE,
|
||||
BLACK,
|
||||
);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
|
||||
|
@ -174,13 +174,6 @@ impl Component for AddressDetails {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
match self.current_page {
|
||||
0 => self.details.paint(),
|
||||
_ => self.xpub_view.paint(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
match self.current_page {
|
||||
0 => self.details.render(target),
|
||||
|
@ -72,10 +72,6 @@ impl Component for BinarySelection {
|
||||
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);
|
||||
|
@ -205,42 +205,6 @@ impl Component for Confirm<'_> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.content_pad.paint();
|
||||
|
||||
if let Some(info) = self.info.as_mut() {
|
||||
if self.show_info {
|
||||
info.close_button.paint();
|
||||
info.title.paint();
|
||||
info.text.paint();
|
||||
self.left_button.paint();
|
||||
self.right_button.paint();
|
||||
// short-circuit before painting the main components
|
||||
return;
|
||||
} else {
|
||||
info.info_button.paint();
|
||||
// pass through to the rest of the paint
|
||||
}
|
||||
}
|
||||
|
||||
self.message.paint();
|
||||
self.alert.paint();
|
||||
self.left_button.paint();
|
||||
self.right_button.paint();
|
||||
match &mut self.title {
|
||||
ConfirmTitle::Text(label) => label.paint(),
|
||||
ConfirmTitle::Icon(icon) => {
|
||||
icon.draw(
|
||||
Point::new(screen().center().x, ICON_TOP),
|
||||
Alignment2D::TOP_CENTER,
|
||||
WHITE,
|
||||
self.bg_color,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
self.content_pad.render(target);
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
time::Duration,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Timer},
|
||||
display::{self, toif::Icon, Color, Font},
|
||||
display::{toif::Icon, Color, Font},
|
||||
event::TouchEvent,
|
||||
geometry::{Alignment, Alignment2D, Insets, Offset, Point, Rect},
|
||||
shape::{self, Renderer},
|
||||
@ -172,10 +172,6 @@ impl Button {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint_background(&self, style: &ButtonStyle) {
|
||||
display::rect_fill(self.area, style.button_color);
|
||||
}
|
||||
|
||||
pub fn render_background<'s>(
|
||||
&self,
|
||||
target: &mut impl Renderer<'s>,
|
||||
@ -199,35 +195,6 @@ impl Button {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint_content(&self, style: &ButtonStyle) {
|
||||
match &self.content {
|
||||
ButtonContent::Empty => {}
|
||||
ButtonContent::Text(text) => {
|
||||
let start_of_baseline = self.area.center() + Self::BASELINE_OFFSET;
|
||||
text.map(|text| {
|
||||
display::text_left(
|
||||
start_of_baseline,
|
||||
text,
|
||||
style.font,
|
||||
style.text_color,
|
||||
style.button_color,
|
||||
);
|
||||
});
|
||||
}
|
||||
ButtonContent::Icon(icon) => {
|
||||
icon.draw(
|
||||
self.area.center(),
|
||||
Alignment2D::CENTER,
|
||||
style.icon_color,
|
||||
style.button_color,
|
||||
);
|
||||
}
|
||||
ButtonContent::IconAndText(child) => {
|
||||
child.paint(self.area, self.style(), Self::BASELINE_OFFSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_content<'s>(
|
||||
&self,
|
||||
target: &mut impl Renderer<'s>,
|
||||
@ -387,12 +354,6 @@ impl Component for Button {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let style = self.style();
|
||||
self.paint_background(style);
|
||||
self.paint_content(style);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let style = self.style();
|
||||
self.render_background(target, style, 0xFF);
|
||||
@ -466,54 +427,6 @@ impl IconText {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: Offset) {
|
||||
let width = self.text.map(|t| style.font.text_width(t));
|
||||
let height = style.font.text_height();
|
||||
|
||||
let mut use_icon = false;
|
||||
let mut use_text = false;
|
||||
|
||||
let mut icon_pos = Point::new(
|
||||
area.top_left().x + ((Self::ICON_SPACE + Self::ICON_MARGIN) / 2),
|
||||
area.center().y,
|
||||
);
|
||||
let mut text_pos = area.center() + Offset::new(-width / 2, height / 2) + baseline_offset;
|
||||
|
||||
if area.width() > (Self::ICON_SPACE + Self::TEXT_MARGIN + width) {
|
||||
//display both icon and text
|
||||
text_pos = Point::new(area.top_left().x + Self::ICON_SPACE, text_pos.y);
|
||||
use_text = true;
|
||||
use_icon = true;
|
||||
} else if area.width() > (width + Self::TEXT_MARGIN) {
|
||||
use_text = true;
|
||||
} else {
|
||||
//if we can't fit the text, retreat to centering the icon
|
||||
icon_pos = area.center();
|
||||
use_icon = true;
|
||||
}
|
||||
|
||||
if use_text {
|
||||
self.text.map(|t| {
|
||||
display::text_left(
|
||||
text_pos,
|
||||
t,
|
||||
style.font,
|
||||
style.text_color,
|
||||
style.button_color,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
if use_icon {
|
||||
self.icon.draw(
|
||||
icon_pos,
|
||||
Alignment2D::CENTER,
|
||||
style.icon_color,
|
||||
style.button_color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render<'s>(
|
||||
&self,
|
||||
target: &mut impl Renderer<'s>,
|
||||
|
@ -7,7 +7,6 @@ use crate::{
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{base::Never, Bar, Component, Empty, Event, EventCtx, Label, Split},
|
||||
display::loader::{loader_circular_uncompress, LoaderDimensions},
|
||||
geometry::{Insets, Offset, Rect},
|
||||
model_mercury::constant,
|
||||
shape,
|
||||
@ -107,20 +106,6 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.content.paint();
|
||||
loader_circular_uncompress(
|
||||
LoaderDimensions::new(LOADER_OUTER, LOADER_INNER),
|
||||
LOADER_OFFSET,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
self.value,
|
||||
self.indeterminate,
|
||||
None,
|
||||
);
|
||||
self.label.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.content.render(target);
|
||||
|
||||
|
@ -77,21 +77,6 @@ impl<'a> Component for ErrorScreen<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
|
||||
let icon = ICON_WARNING40;
|
||||
icon.draw(
|
||||
Point::new(screen().center().x, ICON_TOP),
|
||||
Alignment2D::TOP_CENTER,
|
||||
WHITE,
|
||||
FATAL_ERROR_COLOR,
|
||||
);
|
||||
self.title.paint();
|
||||
self.message.paint();
|
||||
self.footer.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
|
||||
|
@ -70,10 +70,6 @@ impl<F: Fn() -> TString<'static>> Component for FidoCredential<F> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.app_icon.render(target);
|
||||
self.text.render(target);
|
||||
|
@ -186,10 +186,6 @@ impl<'a> Component for Footer<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done")
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let progress = self.progress as f32 / 1000.0;
|
||||
|
||||
|
@ -319,11 +319,6 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.header.paint();
|
||||
self.footer.paint();
|
||||
self.content.paint();
|
||||
}
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.header.render(target);
|
||||
self.footer.render(target);
|
||||
|
@ -212,10 +212,6 @@ impl Component for Header {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let offset = if let Some(anim) = &self.anim {
|
||||
Offset::x(anim.get_title_offset(anim.eval()))
|
||||
|
@ -271,10 +271,6 @@ impl Component for HoldToConfirm {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let elapsed = self.anim.eval();
|
||||
|
||||
|
@ -573,10 +573,6 @@ impl Component for Homescreen {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
if self.loader.is_animating() || self.loader.is_completely_grown(Instant::now()) {
|
||||
self.render_loader(target);
|
||||
@ -798,10 +794,6 @@ impl Component for Lockscreen {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
const OVERLAY_BORDER: i16 = (AREA.height() / 2) - DEFAULT_HS_RADIUS;
|
||||
|
||||
|
@ -102,10 +102,6 @@ impl Component for Bip39Input {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done");
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let area = self.button.area();
|
||||
let style = self.button.style();
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
time::Duration,
|
||||
ui::{
|
||||
component::{text::common::TextEdit, Event, EventCtx, Timer},
|
||||
display::{self, Color, Font},
|
||||
display::{Color, Font},
|
||||
geometry::{Alignment2D, Offset, Point, Rect},
|
||||
shape::{self, Renderer},
|
||||
},
|
||||
@ -110,21 +110,6 @@ impl MultiTapKeyboard {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a visible "underscoring" of the last letter of a text.
|
||||
pub fn paint_pending_marker(text_baseline: Point, text: &str, font: Font, color: Color) {
|
||||
// Measure the width of the last character of input.
|
||||
if let Some(last) = text.chars().last() {
|
||||
let width = font.text_width(text);
|
||||
let last_width = font.char_width(last);
|
||||
// Draw the marker 2px under the start of the baseline of the last character.
|
||||
let marker_origin = text_baseline + Offset::new(width - last_width, 2);
|
||||
// Draw the marker 1px longer than the last character, and 3px thick.
|
||||
let marker_rect =
|
||||
Rect::from_top_left_and_size(marker_origin, Offset::new(last_width + 1, 3));
|
||||
display::rect_fill(marker_rect, color);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a visible "underscoring" of the last letter of a text.
|
||||
pub fn render_pending_marker<'s>(
|
||||
target: &mut impl Renderer<'s>,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
strutil::TString,
|
||||
ui::{
|
||||
component::{maybe::paint_overlapping, Component, Event, EventCtx, Label, Maybe},
|
||||
component::{Component, Event, EventCtx, Label, Maybe},
|
||||
geometry::{Alignment, Grid, Insets, Rect},
|
||||
model_mercury::{
|
||||
component::{Button, ButtonMsg},
|
||||
@ -185,13 +185,6 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
paint_overlapping(&mut [&mut self.prompt, &mut self.input, &mut self.erase]);
|
||||
for btn in &mut self.keys {
|
||||
btn.paint();
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
if self.input.inner().is_empty() {
|
||||
self.prompt.render(target);
|
||||
|
@ -389,10 +389,6 @@ impl Component for PassphraseKeyboard {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done")
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.input.render(target);
|
||||
self.next_btn.render(target);
|
||||
@ -444,10 +440,6 @@ impl Component for Input {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done");
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let style = theme::label_keyboard();
|
||||
|
||||
|
@ -477,10 +477,6 @@ impl Component for PinKeyboard<'_> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done");
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let t_attach = self.attach_animation.eval();
|
||||
let t_close = self.close_animation.eval();
|
||||
@ -678,10 +674,6 @@ impl Component for PinDots {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// TODO: remove when ui-t3t1 done
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let dot_area = self.area.inset(HEADER_PADDING);
|
||||
self.pad.render(target);
|
||||
|
@ -121,10 +121,6 @@ impl Component for Slip39Input {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done")
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let area = self.button.area();
|
||||
let style = self.button.style();
|
||||
|
@ -63,10 +63,6 @@ impl Component for SelectWordCount {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
match self {
|
||||
SelectWordCount::All(full_selector) => full_selector.render(target),
|
||||
@ -127,12 +123,6 @@ impl Component for ValueKeypad {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
for btn in self.button.iter_mut() {
|
||||
btn.paint()
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
for btn in self.button.iter() {
|
||||
btn.render(target)
|
||||
|
@ -190,28 +190,6 @@ impl Component for Loader {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// TODO: Consider passing the current instant along with the event -- that way,
|
||||
// we could synchronize painting across the component tree. Also could be useful
|
||||
// in automated tests.
|
||||
// In practice, taking the current instant here is more precise in case some
|
||||
// other component in the tree takes a long time to draw.
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(progress) = self.progress(now) {
|
||||
let style = self.styles.active;
|
||||
|
||||
self.pad.paint();
|
||||
display::loader(
|
||||
progress,
|
||||
self.offset_y,
|
||||
style.active,
|
||||
style.background_color,
|
||||
style.icon,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
// TODO: Consider passing the current instant along with the event -- that way,
|
||||
// we could synchronize painting across the component tree. Also could be useful
|
||||
|
@ -73,10 +73,6 @@ impl Component for NumberInputDialog {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done");
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.input.render(target);
|
||||
self.paragraphs_pad.render(target);
|
||||
@ -152,10 +148,6 @@ impl Component for NumberInput {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done");
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let mut buf = [0u8; 10];
|
||||
|
||||
|
@ -5,7 +5,6 @@ use crate::{
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx},
|
||||
constant::screen,
|
||||
display,
|
||||
event::TouchEvent,
|
||||
geometry::{Alignment, Alignment2D, Insets, Offset, Point, Rect},
|
||||
shape::{self, Renderer},
|
||||
@ -96,10 +95,6 @@ impl Component for NumberInputSliderDialog {
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.input.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.input.render(target);
|
||||
self.footer.render(target);
|
||||
@ -190,13 +185,6 @@ impl Component for NumberInputSlider {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let val_pct = (100 * (self.value - self.min)) / (self.max - self.min);
|
||||
let fill_to = (val_pct as i16 * self.area.width()) / 100;
|
||||
|
||||
display::bar_with_text_and_fill(self.area, None, theme::FG, theme::BG, 0, fill_to as _);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let (top_left_shape, top_right_shape, bot_left_shape, bot_right_shape) =
|
||||
shape::CornerHighlight::from_rect(
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
text::paragraphs::{Paragraph, Paragraphs},
|
||||
Component, Event, EventCtx, Label, Never, Pad,
|
||||
},
|
||||
display::{self, Font, LOADER_MAX},
|
||||
display::{Font, LOADER_MAX},
|
||||
geometry::{Insets, Offset, Rect},
|
||||
model_mercury::{
|
||||
constant,
|
||||
@ -88,23 +88,6 @@ impl Component for Progress {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.title.paint();
|
||||
if self.indeterminate {
|
||||
display::loader_indeterminate(
|
||||
self.value,
|
||||
self.loader_y_offset,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
display::loader(self.value, self.loader_y_offset, theme::FG, theme::BG, None);
|
||||
}
|
||||
self.description_pad.paint();
|
||||
self.description.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.title.render(target);
|
||||
|
||||
|
@ -106,10 +106,6 @@ impl Component for PromptScreen {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
match self {
|
||||
PromptScreen::Tap(t) => t.render(target),
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
ui::{
|
||||
component::{text::TextStyle, Component, Event, EventCtx, Label, Never, Pad},
|
||||
constant::screen,
|
||||
display::{self, Color, Font, Icon},
|
||||
display::{Color, Font, Icon},
|
||||
geometry::{Alignment2D, Insets, Offset, Point, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
@ -85,18 +85,6 @@ impl Component for ResultFooter<'_> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// divider line
|
||||
let bar = Rect::from_center_and_size(
|
||||
Point::new(self.area.center().x, self.area.y0),
|
||||
Offset::new(self.area.width(), 1),
|
||||
);
|
||||
display::rect_fill(bar, self.style.divider_color);
|
||||
|
||||
// footer text
|
||||
self.text.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
// divider line
|
||||
let bar = Rect::from_center_and_size(
|
||||
@ -168,20 +156,6 @@ impl<'a> Component for ResultScreen<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.footer_pad.paint();
|
||||
|
||||
self.icon.draw(
|
||||
Point::new(screen().center().x, ICON_CENTER_Y),
|
||||
Alignment2D::CENTER,
|
||||
self.style.fg_color,
|
||||
self.style.bg_color,
|
||||
);
|
||||
self.message.paint();
|
||||
self.footer.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
self.footer_pad.render(target);
|
||||
|
@ -84,46 +84,6 @@ impl Component for ScrollBar {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
fn dotsize(distance: usize, nhidden: usize) -> Icon {
|
||||
match (nhidden.saturating_sub(distance)).min(2 - distance) {
|
||||
0 => theme::DOT_INACTIVE,
|
||||
1 => theme::DOT_INACTIVE_HALF,
|
||||
_ => theme::DOT_INACTIVE_QUARTER,
|
||||
}
|
||||
}
|
||||
|
||||
// Number of visible dots.
|
||||
let num_shown = self.page_count.min(Self::MAX_DOTS);
|
||||
// Page indices corresponding to the first (and last) dot.
|
||||
let first_shown = self
|
||||
.active_page
|
||||
.saturating_sub(Self::MAX_DOTS / 2)
|
||||
.min(self.page_count.saturating_sub(Self::MAX_DOTS));
|
||||
let last_shown = first_shown + num_shown - 1;
|
||||
|
||||
let mut cursor = self.area.center()
|
||||
- Offset::on_axis(
|
||||
self.layout.axis,
|
||||
Self::DOT_INTERVAL * (num_shown.saturating_sub(1) as i16) / 2,
|
||||
);
|
||||
for i in first_shown..(last_shown + 1) {
|
||||
let icon = if i == self.active_page {
|
||||
theme::DOT_ACTIVE
|
||||
} else if i <= first_shown + 1 {
|
||||
let before_first_shown = first_shown;
|
||||
dotsize(i - first_shown, before_first_shown)
|
||||
} else if i >= last_shown - 1 {
|
||||
let after_last_shown = self.page_count - 1 - last_shown;
|
||||
dotsize(last_shown - i, after_last_shown)
|
||||
} else {
|
||||
theme::DOT_INACTIVE
|
||||
};
|
||||
icon.draw(cursor, Alignment2D::CENTER, theme::FG, theme::BG);
|
||||
cursor = cursor + Offset::on_axis(self.layout.axis, Self::DOT_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
fn dotsize(distance: usize, nhidden: usize) -> Icon {
|
||||
match (nhidden.saturating_sub(distance)).min(2 - distance) {
|
||||
|
@ -186,10 +186,6 @@ impl<'a> Component for ShareWords<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// TODO: remove when ui-t3t1 done
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
// corner highlights
|
||||
let (_, top_right_shape, bot_left_shape, bot_right_shape) =
|
||||
|
@ -235,10 +235,6 @@ impl Component for StatusScreen {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let t = self.anim.eval();
|
||||
|
||||
|
@ -268,10 +268,6 @@ impl<T: Component> Component for SwipeContent<T> {
|
||||
self.process_event(ctx, event, true)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.inner.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let (offset, clip, mask) = self.swipe_context.get_params(self.bounds);
|
||||
|
||||
@ -394,10 +390,6 @@ where
|
||||
self.content.process_event(ctx, event, animate)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.content.paint()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.content.render(target)
|
||||
}
|
||||
|
@ -60,10 +60,6 @@ impl<T: Swipable + Component> Component for SwipeUpScreen<T> {
|
||||
self.content.event(ctx, e).map(SwipeUpScreenMsg::Content)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.content.render(target);
|
||||
}
|
||||
|
@ -186,10 +186,6 @@ impl Component for TapToConfirm {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
const PAD_RADIUS: i16 = 70;
|
||||
const PAD_THICKNESS: i16 = 20;
|
||||
|
@ -61,10 +61,6 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
todo!("remove when ui-t3t1 done");
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.paragraphs.render(target);
|
||||
}
|
||||
|
@ -250,10 +250,6 @@ impl Component for VerticalMenu {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// TODO remove when ui-t3t1 done
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let t = self.attach_animation.eval();
|
||||
|
||||
@ -377,10 +373,6 @@ impl<F: Fn(usize) -> TString<'static>> Component for PagedVerticalMenu<F> {
|
||||
msg
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// TODO remove when ui-t3t1 done
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.inner.render(target)
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
display::font::Font,
|
||||
geometry::{Alignment, Alignment2D, Offset, Rect},
|
||||
shape,
|
||||
@ -12,7 +11,7 @@ use super::theme;
|
||||
const TEXT_BOTTOM_MARGIN: i16 = 54;
|
||||
const ICON_TOP_MARGIN: i16 = 48;
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
const MODEL_NAME_FONT: display::Font = display::Font::DEMIBOLD;
|
||||
const MODEL_NAME_FONT: Font = Font::DEMIBOLD;
|
||||
|
||||
use crate::trezorhal::model;
|
||||
|
||||
@ -38,22 +37,6 @@ impl Component for WelcomeScreen {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
theme::ICON_LOGO.draw(
|
||||
self.area.top_center() + Offset::y(ICON_TOP_MARGIN),
|
||||
Alignment2D::TOP_CENTER,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
display::text_center(
|
||||
self.area.bottom_center() - Offset::y(TEXT_BOTTOM_MARGIN),
|
||||
model::FULL_NAME,
|
||||
display::Font::NORMAL,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::ToifImage::new(
|
||||
self.area.top_center() + Offset::y(ICON_TOP_MARGIN),
|
||||
|
@ -5,21 +5,16 @@ use super::{
|
||||
constant,
|
||||
};
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
use crate::ui::{display::Color, shape::render_on_display};
|
||||
|
||||
pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) {
|
||||
let mut frame = ErrorScreen::new(title.into(), msg.into(), footer.into());
|
||||
frame.place(constant::screen());
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
frame.render(target);
|
||||
});
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
frame.paint();
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
@ -29,13 +24,9 @@ pub fn screen_boot_stage_2() {
|
||||
|
||||
display::sync();
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
frame.render(target);
|
||||
});
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
frame.paint();
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
@ -95,17 +95,6 @@ impl<'a> Component for Intro<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.title.paint();
|
||||
let area = self.bg.area;
|
||||
ICON_WARN_TITLE.draw(area.top_left(), Alignment2D::TOP_LEFT, BLD_FG, BLD_BG);
|
||||
ICON_WARN_TITLE.draw(area.top_right(), Alignment2D::TOP_RIGHT, BLD_FG, BLD_BG);
|
||||
self.warn.paint();
|
||||
self.text.paint();
|
||||
self.buttons.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
self.title.render(target);
|
||||
|
@ -5,7 +5,6 @@ use crate::{
|
||||
ui::{
|
||||
component::{Child, Component, Event, EventCtx, Pad},
|
||||
constant::screen,
|
||||
display,
|
||||
display::{Font, Icon},
|
||||
geometry::{Alignment, Alignment2D, Offset, Point, Rect},
|
||||
layout::simplified::ReturnToC,
|
||||
@ -52,25 +51,6 @@ impl MenuChoice {
|
||||
}
|
||||
|
||||
impl Choice for MenuChoice {
|
||||
fn paint_center(&self, _area: Rect, _inverse: bool) {
|
||||
// Icon on top and two lines of text below
|
||||
self.icon.draw(
|
||||
SCREEN_CENTER + Offset::y(-20),
|
||||
Alignment2D::CENTER,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
|
||||
display::text_center(SCREEN_CENTER, self.first_line, Font::NORMAL, BLD_FG, BLD_BG);
|
||||
display::text_center(
|
||||
SCREEN_CENTER + Offset::y(10),
|
||||
self.second_line,
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
|
||||
fn render_center<'s>(&self, target: &mut impl Renderer<'s>, _area: Rect, _inverse: bool) {
|
||||
// Icon on top and two lines of text below
|
||||
shape::ToifImage::new(SCREEN_CENTER + Offset::y(-20), self.icon.toif)
|
||||
@ -179,11 +159,6 @@ impl Component for Menu {
|
||||
self.choice_page.event(ctx, event).map(|evt| evt.0)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.pad.paint();
|
||||
self.choice_page.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.pad.render(target);
|
||||
self.choice_page.render(target);
|
||||
|
@ -24,15 +24,10 @@ use super::{
|
||||
ModelTRFeatures,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
use crate::ui::geometry::Rect;
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
use crate::ui::{
|
||||
display::toif::Toif, geometry::Alignment, model_tr::cshape, shape, shape::render_on_display,
|
||||
};
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
use ufmt::uwrite;
|
||||
|
||||
mod intro;
|
||||
@ -53,51 +48,6 @@ impl ReturnToC for ConfirmMsg {
|
||||
}
|
||||
|
||||
impl ModelTRFeatures {
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
fn screen_progress(
|
||||
text: &str,
|
||||
text2: &str,
|
||||
progress: u16,
|
||||
initialize: bool,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
if initialize {
|
||||
display::rect_fill(SCREEN, bg_color);
|
||||
}
|
||||
|
||||
let progress = if progress < 20 { 20 } else { progress };
|
||||
|
||||
display::rect_rounded2_partial(
|
||||
Rect::new(
|
||||
SCREEN.top_center() + Offset::new(-9, 3),
|
||||
SCREEN.top_center() + Offset::new(9, 18 + 3),
|
||||
),
|
||||
fg_color,
|
||||
bg_color,
|
||||
((100_u32 * progress as u32) / 1000) as _,
|
||||
icon,
|
||||
);
|
||||
display::text_center(
|
||||
SCREEN.center() + Offset::y(8),
|
||||
text,
|
||||
Font::BOLD,
|
||||
fg_color,
|
||||
bg_color,
|
||||
);
|
||||
display::text_center(
|
||||
SCREEN.center() + Offset::y(20),
|
||||
text2,
|
||||
Font::BOLD,
|
||||
fg_color,
|
||||
bg_color,
|
||||
);
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
fn screen_progress(
|
||||
text: &str,
|
||||
text2: &str,
|
||||
@ -148,29 +98,6 @@ impl UIFeaturesBootloader for ModelTRFeatures {
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
fn bld_continue_label(bg_color: Color) {
|
||||
display::text_center(
|
||||
Point::new(constant::WIDTH / 2, HEIGHT - 2),
|
||||
"CONTINUE",
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
bg_color,
|
||||
);
|
||||
ICON_ARM_LEFT.draw(
|
||||
Point::new(constant::WIDTH / 2 - 36, HEIGHT - 6),
|
||||
Alignment2D::TOP_LEFT,
|
||||
BLD_FG,
|
||||
bg_color,
|
||||
);
|
||||
ICON_ARM_RIGHT.draw(
|
||||
Point::new(constant::WIDTH / 2 + 25, HEIGHT - 6),
|
||||
Alignment2D::TOP_LEFT,
|
||||
BLD_FG,
|
||||
bg_color,
|
||||
);
|
||||
}
|
||||
|
||||
fn screen_install_success(restart_seconds: u8, _initial_setup: bool, complete_draw: bool) {
|
||||
let mut reboot_msg = BootloaderString::new();
|
||||
|
||||
@ -321,9 +248,6 @@ impl UIFeaturesBootloader for ModelTRFeatures {
|
||||
}
|
||||
|
||||
fn screen_boot_stage_1(_fading: bool) {
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
display::rect_fill(SCREEN, BLD_BG);
|
||||
|
||||
let mut frame = WelcomeScreen::new(cfg!(ui_empty_lock));
|
||||
show(&mut frame, false);
|
||||
}
|
||||
@ -377,7 +301,6 @@ impl UIFeaturesBootloader for ModelTRFeatures {
|
||||
show(&mut frame, false);
|
||||
}
|
||||
|
||||
#[cfg(feature = "new_rendering")]
|
||||
fn screen_boot(
|
||||
_warning: bool,
|
||||
vendor_str: Option<&str>,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
display::{self, Font},
|
||||
display::Font,
|
||||
geometry::{Alignment, Offset, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
@ -32,34 +32,6 @@ impl Component for Welcome {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
|
||||
let top_center = self.bg.area.top_center();
|
||||
|
||||
display::text_center(
|
||||
top_center + Offset::y(24),
|
||||
"Get started with",
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
display::text_center(
|
||||
top_center + Offset::y(32),
|
||||
"your Trezor at",
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
display::text_center(
|
||||
top_center + Offset::y(48),
|
||||
"trezor.io/start",
|
||||
Font::BOLD,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
|
||||
|
@ -250,16 +250,6 @@ impl Component for AddressDetails {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.pad.paint();
|
||||
self.buttons.paint();
|
||||
match self.current_page {
|
||||
0 => self.qr_code.paint(),
|
||||
1 => self.details_view.paint(),
|
||||
_ => self.xpub_view.paint(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.pad.render(target);
|
||||
self.buttons.render(target);
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
strutil::TString,
|
||||
ui::{
|
||||
component::{Child, Component, ComponentExt, Event, EventCtx, Label, Pad},
|
||||
display::{self, Color, Font},
|
||||
display::{Color, Font},
|
||||
geometry::{Point, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
@ -195,29 +195,6 @@ impl Component for Confirm<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
|
||||
let display_top_left = |text: TString| {
|
||||
text.map(|t| {
|
||||
display::text_top_left(Point::zero(), t, Font::BOLD, WHITE, self.bg_color)
|
||||
});
|
||||
};
|
||||
|
||||
// We are either on the info screen or on the "main" screen
|
||||
if self.showing_info_screen {
|
||||
if let Some(title) = self.info_title {
|
||||
display_top_left(title);
|
||||
}
|
||||
self.info_text.paint();
|
||||
} else {
|
||||
display_top_left(self.title);
|
||||
self.message.paint();
|
||||
self.alert.paint();
|
||||
}
|
||||
self.buttons.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
constant,
|
||||
display::{self, Color, Font, Icon},
|
||||
display::{Color, Font, Icon},
|
||||
event::PhysicalButton,
|
||||
geometry::{Alignment2D, Offset, Point, Rect},
|
||||
shape,
|
||||
@ -190,80 +190,6 @@ impl Component for Button {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let style = self.style();
|
||||
let fg_color = style.text_color;
|
||||
let bg_color = fg_color.negate();
|
||||
let area = self.get_current_area();
|
||||
let inversed_colors = bg_color != theme::BG;
|
||||
|
||||
// Filling the background (with 2-pixel rounding when applicable)
|
||||
if inversed_colors {
|
||||
display::rect_outline_rounded(area, bg_color, fg_color, 2);
|
||||
display::rect_fill(area.shrink(1), bg_color);
|
||||
} else if style.with_outline {
|
||||
display::rect_outline_rounded(area, fg_color, bg_color, 2);
|
||||
} else {
|
||||
display::rect_fill(area, bg_color);
|
||||
}
|
||||
|
||||
// Optionally display "arms" at both sides of content - always in FG and BG
|
||||
// colors (they are not inverted).
|
||||
if style.with_arms {
|
||||
theme::ICON_ARM_LEFT.draw(
|
||||
area.left_center(),
|
||||
Alignment2D::TOP_RIGHT,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
theme::ICON_ARM_RIGHT.draw(
|
||||
area.right_center(),
|
||||
Alignment2D::TOP_LEFT,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
}
|
||||
|
||||
// Painting the content
|
||||
match &self.content {
|
||||
ButtonContent::Text(text) => text.map(|t| {
|
||||
display::text_left(
|
||||
self.get_text_baseline(style) - Offset::x(style.font.start_x_bearing(t)),
|
||||
t,
|
||||
style.font,
|
||||
fg_color,
|
||||
bg_color,
|
||||
);
|
||||
}),
|
||||
ButtonContent::Icon(icon) => {
|
||||
// Allowing for possible offset of the area from current style
|
||||
let icon_area = area.translate(style.offset);
|
||||
if style.with_outline {
|
||||
icon.draw(icon_area.center(), Alignment2D::CENTER, fg_color, bg_color);
|
||||
} else {
|
||||
// Positioning the icon in the corresponding corner/center
|
||||
match self.pos {
|
||||
ButtonPos::Left => icon.draw(
|
||||
icon_area.bottom_left(),
|
||||
Alignment2D::BOTTOM_LEFT,
|
||||
fg_color,
|
||||
bg_color,
|
||||
),
|
||||
ButtonPos::Right => icon.draw(
|
||||
icon_area.bottom_right(),
|
||||
Alignment2D::BOTTOM_RIGHT,
|
||||
fg_color,
|
||||
bg_color,
|
||||
),
|
||||
ButtonPos::Middle => {
|
||||
icon.draw(icon_area.center(), Alignment2D::CENTER, fg_color, bg_color)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let style = self.style();
|
||||
let fg_color = style.text_color;
|
||||
|
@ -83,18 +83,6 @@ impl ButtonType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint(&mut self) {
|
||||
match self {
|
||||
Self::Button(button) => {
|
||||
button.paint();
|
||||
}
|
||||
Self::HoldToConfirm(htc) => {
|
||||
htc.paint();
|
||||
}
|
||||
Self::Nothing => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
match self {
|
||||
Self::Button(button) => {
|
||||
@ -162,11 +150,6 @@ impl ButtonContainer {
|
||||
self.button_type.place(bounds);
|
||||
}
|
||||
|
||||
/// Painting the component that should be currently visible, if any.
|
||||
pub fn paint(&mut self) {
|
||||
self.button_type.paint();
|
||||
}
|
||||
|
||||
pub fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.button_type.render(target);
|
||||
}
|
||||
@ -588,13 +571,6 @@ impl Component for ButtonController {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.pad.paint();
|
||||
self.left_btn.paint();
|
||||
self.middle_btn.paint();
|
||||
self.right_btn.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.pad.render(target);
|
||||
self.left_btn.render(target);
|
||||
@ -777,8 +753,6 @@ impl Component for AutomaticMover {
|
||||
bounds
|
||||
}
|
||||
|
||||
fn paint(&mut self) {}
|
||||
|
||||
fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use super::{common, theme};
|
||||
use super::theme;
|
||||
|
||||
/// Component that allows for "allocating" a standalone line of text anywhere
|
||||
/// on the screen and updating it arbitrarily - without affecting the rest
|
||||
@ -108,11 +108,6 @@ impl ChangingTextLine {
|
||||
self.font.text_width(self.text.as_ref()) <= self.pad.area.width()
|
||||
}
|
||||
|
||||
fn paint_left(&self) {
|
||||
let baseline = Point::new(self.pad.area.x0, self.y_baseline());
|
||||
common::display_left(baseline, &self.text, self.font);
|
||||
}
|
||||
|
||||
fn render_left<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let baseline = Point::new(self.pad.area.x0, self.y_baseline());
|
||||
shape::Text::new(baseline, self.text.as_ref())
|
||||
@ -120,11 +115,6 @@ impl ChangingTextLine {
|
||||
.render(target);
|
||||
}
|
||||
|
||||
fn paint_center(&self) {
|
||||
let baseline = Point::new(self.pad.area.bottom_center().x, self.y_baseline());
|
||||
common::display_center(baseline, &self.text, self.font);
|
||||
}
|
||||
|
||||
fn render_center<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let baseline = Point::new(self.pad.area.bottom_center().x, self.y_baseline());
|
||||
shape::Text::new(baseline, self.text.as_ref())
|
||||
@ -133,11 +123,6 @@ impl ChangingTextLine {
|
||||
.render(target);
|
||||
}
|
||||
|
||||
fn paint_right(&self) {
|
||||
let baseline = Point::new(self.pad.area.x1, self.y_baseline());
|
||||
common::display_right(baseline, &self.text, self.font);
|
||||
}
|
||||
|
||||
fn render_right<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let baseline = Point::new(self.pad.area.x1, self.y_baseline());
|
||||
shape::Text::new(baseline, self.text.as_ref())
|
||||
@ -146,23 +131,6 @@ impl ChangingTextLine {
|
||||
.render(target);
|
||||
}
|
||||
|
||||
fn paint_long_content_with_ellipsis(&self) {
|
||||
let text_to_display = long_line_content_with_ellipsis(
|
||||
self.text.as_ref(),
|
||||
self.ellipsis,
|
||||
self.font,
|
||||
self.pad.area.width(),
|
||||
);
|
||||
|
||||
// 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.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);
|
||||
}
|
||||
|
||||
fn render_long_content_with_ellipsis<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let text_to_display = long_line_content_with_ellipsis(
|
||||
self.text.as_ref(),
|
||||
@ -195,26 +163,6 @@ impl Component for ChangingTextLine {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// Always re-painting from scratch.
|
||||
// Effectively clearing the line completely
|
||||
// when `self.show_content` is set to `false`.
|
||||
self.pad.clear();
|
||||
self.pad.paint();
|
||||
if self.show_content {
|
||||
// In the case text cannot fit, show ellipsis and its right part
|
||||
if !self.text_fits_completely() {
|
||||
self.paint_long_content_with_ellipsis();
|
||||
} else {
|
||||
match self.alignment {
|
||||
Alignment::Start => self.paint_left(),
|
||||
Alignment::Center => self.paint_center(),
|
||||
Alignment::End => self.paint_right(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.pad.render(target);
|
||||
if self.show_content {
|
||||
|
@ -6,12 +6,10 @@ use crate::{
|
||||
ui::{
|
||||
component::{
|
||||
base::Never,
|
||||
text::util::{
|
||||
text_multiline, text_multiline2, text_multiline_bottom, text_multiline_bottom2,
|
||||
},
|
||||
text::util::{text_multiline, text_multiline_bottom},
|
||||
Component, Event, EventCtx,
|
||||
},
|
||||
display::{self, Font},
|
||||
display::Font,
|
||||
geometry::{Alignment, Alignment2D, Insets, Offset, Rect},
|
||||
model_tr::cshape,
|
||||
shape,
|
||||
@ -82,60 +80,12 @@ impl Component for CoinJoinProgress {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// TOP
|
||||
if self.indeterminate {
|
||||
text_multiline(
|
||||
self.area,
|
||||
TR::coinjoin__title_progress.into(),
|
||||
Font::BOLD_UPPER,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
Alignment::Center,
|
||||
);
|
||||
display::loader::loader_small_indeterminate(
|
||||
self.value,
|
||||
self.loader_y_offset,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
} else {
|
||||
display::loader(
|
||||
self.value,
|
||||
self.loader_y_offset,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
Some((theme::ICON_TICK_FAT, theme::FG)),
|
||||
);
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
let top_rest = text_multiline_bottom(
|
||||
self.area,
|
||||
TR::coinjoin__do_not_disconnect.into(),
|
||||
Font::BOLD,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
Alignment::Center,
|
||||
);
|
||||
if let Some(rest) = top_rest {
|
||||
text_multiline_bottom(
|
||||
rest.inset(Insets::bottom(FOOTER_TEXT_MARGIN)),
|
||||
self.text,
|
||||
Font::NORMAL,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
Alignment::Center,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
// TOP
|
||||
let center = self.area.center() + Offset::y(self.loader_y_offset);
|
||||
|
||||
if self.indeterminate {
|
||||
text_multiline2(
|
||||
text_multiline(
|
||||
target,
|
||||
self.area,
|
||||
TR::coinjoin__title_progress.into(),
|
||||
@ -158,7 +108,7 @@ impl Component for CoinJoinProgress {
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
let top_rest = text_multiline_bottom2(
|
||||
let top_rest = text_multiline_bottom(
|
||||
target,
|
||||
self.area,
|
||||
TR::coinjoin__do_not_disconnect.into(),
|
||||
@ -168,7 +118,7 @@ impl Component for CoinJoinProgress {
|
||||
Alignment::Center,
|
||||
);
|
||||
if let Some(rest) = top_rest {
|
||||
text_multiline_bottom2(
|
||||
text_multiline_bottom(
|
||||
target,
|
||||
rest.inset(Insets::bottom(FOOTER_TEXT_MARGIN)),
|
||||
self.text,
|
||||
|
@ -1,28 +0,0 @@
|
||||
use crate::ui::{
|
||||
display::{self, Font},
|
||||
geometry::Point,
|
||||
};
|
||||
|
||||
use super::theme;
|
||||
|
||||
/// Display white text on black background
|
||||
pub fn display_left<T: AsRef<str>>(baseline: Point, text: T, font: Font) {
|
||||
display::text_left(baseline, text.as_ref(), font, theme::FG, theme::BG);
|
||||
}
|
||||
|
||||
/// Display black text on white background
|
||||
pub fn display_inverse<T: AsRef<str>>(baseline: Point, text: T, font: Font) {
|
||||
display::text_left(baseline, text.as_ref(), font, theme::BG, theme::FG);
|
||||
}
|
||||
|
||||
/// Display white text on black background,
|
||||
/// centered around a baseline Point
|
||||
pub fn display_center<T: AsRef<str>>(baseline: Point, text: T, font: Font) {
|
||||
display::text_center(baseline, text.as_ref(), font, theme::FG, theme::BG);
|
||||
}
|
||||
|
||||
/// Display white text on black background,
|
||||
/// with right boundary at a baseline Point
|
||||
pub fn display_right<T: AsRef<str>>(baseline: Point, text: T, font: Font) {
|
||||
display::text_right(baseline, text.as_ref(), font, theme::FG, theme::BG);
|
||||
}
|
@ -3,7 +3,6 @@ use crate::{
|
||||
ui::{
|
||||
component::{Child, Component, Event, EventCtx, Label, Never, Pad},
|
||||
constant::{screen, WIDTH},
|
||||
display,
|
||||
geometry::{Alignment2D, Offset, Point, Rect},
|
||||
model_tr::cshape,
|
||||
shape,
|
||||
@ -86,22 +85,6 @@ impl Component for ErrorScreen<'_> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
|
||||
if self.show_icons {
|
||||
theme::ICON_WARN_TITLE.draw(screen().top_left(), Alignment2D::TOP_LEFT, FG, BG);
|
||||
theme::ICON_WARN_TITLE.draw(screen().top_right(), Alignment2D::TOP_RIGHT, FG, BG);
|
||||
}
|
||||
self.title.paint();
|
||||
self.message.paint();
|
||||
|
||||
// // divider line
|
||||
display::dotted_line(Point::new(0, DIVIDER_POSITION), WIDTH, FG, 3);
|
||||
|
||||
self.footer.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.bg.render(target);
|
||||
|
||||
|
@ -298,23 +298,6 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.pad.paint();
|
||||
// Scrollbars are painted only with a title and when requested
|
||||
if self.title.is_some() {
|
||||
if self.show_scrollbar {
|
||||
self.scrollbar.paint();
|
||||
}
|
||||
self.title.paint();
|
||||
}
|
||||
self.buttons.paint();
|
||||
// On purpose painting current page at the end, after buttons,
|
||||
// because we sometimes (in the case of QR code) need to use the
|
||||
// whole height of the display for showing the content
|
||||
// (and painting buttons last would cover the lower part).
|
||||
self.current_page.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.pad.render(target);
|
||||
// Scrollbars are painted only with a title and when requested
|
||||
|
@ -118,10 +118,6 @@ impl Page {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn paint(&mut self) {
|
||||
self.formatted.paint();
|
||||
}
|
||||
|
||||
pub fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.formatted.render(target);
|
||||
}
|
||||
|
@ -77,11 +77,6 @@ where
|
||||
self.content.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.title.paint();
|
||||
self.content.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.title.render(target);
|
||||
self.content.render(target);
|
||||
@ -198,12 +193,6 @@ where
|
||||
msg
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.title.paint();
|
||||
self.scrollbar.paint();
|
||||
self.content.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.title.render(target);
|
||||
self.scrollbar.render(target);
|
||||
|
@ -120,10 +120,6 @@ impl Component for HoldToConfirm {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.loader.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.loader.render(target);
|
||||
}
|
||||
|
@ -7,10 +7,7 @@ use crate::{
|
||||
component::{Child, Component, Event, EventCtx, Label},
|
||||
constant::{HEIGHT, WIDTH},
|
||||
display::{
|
||||
self,
|
||||
image::{ImageInfo, ToifFormat},
|
||||
rect_fill,
|
||||
toif::Toif,
|
||||
Font, Icon,
|
||||
},
|
||||
event::USBEvent,
|
||||
@ -22,8 +19,8 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
super::constant, common::display_center, theme, ButtonController, ButtonControllerMsg,
|
||||
ButtonLayout, ButtonPos, CancelConfirmMsg, LoaderMsg, ProgressLoader,
|
||||
super::constant, theme, ButtonController, ButtonControllerMsg, ButtonLayout, ButtonPos,
|
||||
CancelConfirmMsg, LoaderMsg, ProgressLoader,
|
||||
};
|
||||
|
||||
const AREA: Rect = constant::screen();
|
||||
@ -42,15 +39,6 @@ const COINJOIN_CORNER: Point = AREA.top_right().ofs(Offset::new(-2, 2));
|
||||
|
||||
const HOLD_TO_LOCK_MS: u32 = 1000;
|
||||
|
||||
fn paint_default_image() {
|
||||
theme::ICON_LOGO.draw(
|
||||
TOP_CENTER + Offset::y(LOGO_ICON_TOP_MARGIN),
|
||||
Alignment2D::TOP_CENTER,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
}
|
||||
|
||||
fn render_default_image<'s>(target: &mut impl Renderer<'s>) {
|
||||
shape::ToifImage::new(
|
||||
TOP_CENTER + Offset::y(LOGO_ICON_TOP_MARGIN),
|
||||
@ -106,17 +94,6 @@ impl Homescreen {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_homescreen_image(&self) {
|
||||
if let Some(image) = self.custom_image {
|
||||
// SAFETY: We expect no existing mutable reference. Resulting reference is
|
||||
// discarded before returning to micropython.
|
||||
let toif = unwrap!(Toif::new(unsafe { image.data() }));
|
||||
toif.draw(TOP_CENTER, Alignment2D::TOP_CENTER, theme::FG, theme::BG);
|
||||
} else {
|
||||
paint_default_image();
|
||||
}
|
||||
}
|
||||
|
||||
fn render_homescreen_image<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
if let Some(image) = self.custom_image {
|
||||
shape::ToifImage::new_image(TOP_CENTER, image)
|
||||
@ -128,37 +105,6 @@ impl Homescreen {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_notification(&self) {
|
||||
let baseline = TOP_CENTER + Offset::y(NOTIFICATION_FONT.line_height());
|
||||
if !usb_configured() {
|
||||
self.fill_notification_background();
|
||||
// TODO: fill warning icons here as well?
|
||||
TR::homescreen__title_no_usb_connection
|
||||
.map_translated(|t| display_center(baseline, t, NOTIFICATION_FONT));
|
||||
} else if let Some((notification, _level)) = &self.notification {
|
||||
self.fill_notification_background();
|
||||
notification.map(|c| display_center(baseline, c, NOTIFICATION_FONT));
|
||||
// Painting warning icons in top corners when the text is short enough not to
|
||||
// collide with them
|
||||
let icon_width = NOTIFICATION_ICON.toif.width();
|
||||
let text_width = notification.map(|c| NOTIFICATION_FONT.text_width(c));
|
||||
if AREA.width() >= text_width + (icon_width + 1) * 2 {
|
||||
NOTIFICATION_ICON.draw(
|
||||
AREA.top_left(),
|
||||
Alignment2D::TOP_LEFT,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
NOTIFICATION_ICON.draw(
|
||||
AREA.top_right(),
|
||||
Alignment2D::TOP_RIGHT,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_notification<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
let baseline = TOP_CENTER + Offset::y(NOTIFICATION_FONT.line_height());
|
||||
if !usb_configured() {
|
||||
@ -204,16 +150,6 @@ impl Homescreen {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_label(&mut self) {
|
||||
// paint black background to place the label
|
||||
let mut outset = Insets::uniform(LABEL_OUTSET);
|
||||
// the margin at top is bigger (caused by text-height vs line-height?)
|
||||
// compensate by shrinking the outset
|
||||
outset.top -= 5;
|
||||
rect_fill(self.label.text_area().outset(outset), theme::BG);
|
||||
self.label.paint();
|
||||
}
|
||||
|
||||
fn render_label<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
// paint black background to place the label
|
||||
let mut outset = Insets::uniform(LABEL_OUTSET);
|
||||
@ -227,11 +163,6 @@ impl Homescreen {
|
||||
self.label.render(target);
|
||||
}
|
||||
|
||||
/// So that notification is well visible even on homescreen image
|
||||
fn fill_notification_background(&self) {
|
||||
rect_fill(AREA.split_top(NOTIFICATION_HEIGHT).0, theme::BG);
|
||||
}
|
||||
|
||||
fn event_usb(&mut self, ctx: &mut EventCtx, event: Event) {
|
||||
if let Event::USB(USBEvent::Connected(_)) = event {
|
||||
ctx.request_paint();
|
||||
@ -283,27 +214,6 @@ impl Component for Homescreen {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// Redraw the whole screen when the screen changes (loader vs homescreen)
|
||||
if self.show_loader {
|
||||
if !matches!(self.current_screen, CurrentScreen::Loader) {
|
||||
display::clear();
|
||||
self.current_screen = CurrentScreen::Loader;
|
||||
}
|
||||
self.loader.paint();
|
||||
} else {
|
||||
if !matches!(self.current_screen, CurrentScreen::Homescreen) {
|
||||
display::clear();
|
||||
self.current_screen = CurrentScreen::Homescreen;
|
||||
}
|
||||
// Painting the homescreen image first, as the notification and label
|
||||
// should be "on top of it"
|
||||
self.paint_homescreen_image();
|
||||
self.paint_notification();
|
||||
self.paint_label();
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
// Redraw the whole screen when the screen changes (loader vs homescreen)
|
||||
if self.show_loader {
|
||||
@ -366,29 +276,6 @@ impl Component for Lockscreen<'_> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
if self.screensaver {
|
||||
// keep screen blank
|
||||
return;
|
||||
}
|
||||
theme::ICON_LOCK.draw(
|
||||
TOP_CENTER + Offset::y(LOCK_ICON_TOP_MARGIN),
|
||||
Alignment2D::TOP_CENTER,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
self.instruction.paint();
|
||||
self.label.paint();
|
||||
if let Some(i) = &self.coinjoin_icon {
|
||||
i.draw(
|
||||
COINJOIN_CORNER,
|
||||
Alignment2D::TOP_RIGHT,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
if self.screensaver {
|
||||
// keep screen blank
|
||||
@ -455,24 +342,6 @@ impl Component for ConfirmHomescreen {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
if self.image.is_empty() {
|
||||
paint_default_image();
|
||||
} else {
|
||||
// Drawing the image full-screen first and then other things on top
|
||||
// SAFETY: We expect no existing mutable reference. Resulting reference is
|
||||
// discarded before returning to micropython.
|
||||
let toif_data = unwrap!(Toif::new(unsafe { self.image.data() }));
|
||||
toif_data.draw(TOP_CENTER, Alignment2D::TOP_CENTER, theme::FG, theme::BG);
|
||||
};
|
||||
// Need to make all the title background black, so the title text is well
|
||||
// visible
|
||||
let title_area = self.title.inner().area();
|
||||
rect_fill(title_area, theme::BG);
|
||||
self.title.paint();
|
||||
self.buttons.paint();
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
if self.image.is_empty() {
|
||||
render_default_image(target);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user