1
0
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:
cepetr 2024-11-13 11:04:53 +01:00 committed by cepetr
parent a4da695430
commit 2481f768f8
169 changed files with 134 additions and 6946 deletions

View File

@ -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")

View File

@ -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);

View File

@ -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
);

View File

@ -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 {

View File

@ -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();
}
}

View File

@ -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"))]

View File

@ -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,

View File

@ -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);
}

View File

@ -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)

View File

@ -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)

View File

@ -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);
}

View File

@ -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()

View File

@ -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),

View File

@ -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;

View File

@ -15,8 +15,6 @@ impl Component for Empty {
None
}
fn paint(&mut self) {}
fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {}
}

View File

@ -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)

View File

@ -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)

View File

@ -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));
}
}

View File

@ -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,

View File

@ -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();

View File

@ -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")]

View File

@ -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)

View File

@ -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);

View File

@ -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()];

View File

@ -134,7 +134,5 @@ impl Component for Swipe {
None
}
fn paint(&mut self) {}
fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {}
}

View File

@ -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));
}
}

View File

@ -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>,
{

View File

@ -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);

View File

@ -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
}
})

View File

@ -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>) {}
}

View File

@ -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 {

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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,
);
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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>,

View File

@ -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);

View File

@ -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),

View File

@ -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);

View File

@ -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);

View File

@ -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>,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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()))

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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>,

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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

View File

@ -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];

View File

@ -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(

View File

@ -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);

View File

@ -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),

View File

@ -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);

View File

@ -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) {

View File

@ -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) =

View File

@ -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();

View File

@ -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)
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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)
}

View File

@ -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),

View File

@ -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();
}

View File

@ -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);

View File

@ -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);

View File

@ -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>,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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> {

View File

@ -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 {

View File

@ -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,

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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