feat(core/rust): introduce unlock-screen animated overlay

[no changelog]
pull/3412/merge
cepetr 1 month ago committed by cepetr
parent 321e4be819
commit c0b3a2c26b

@ -0,0 +1,3 @@
mod unlock_overlay;
pub use unlock_overlay::UnlockOverlay;

@ -0,0 +1,115 @@
use crate::ui::{
display::Color,
geometry::{Offset, Point, Rect},
shape::{Canvas, DrawingCache, Mono8Canvas, Renderer, Shape, ShapeClone},
};
use without_alloc::alloc::LocalAllocLeakExt;
/// A special shape for rendering 7 differently rotated circular
/// sectors on 5 concentric circles, used as an overlay on the background
/// image on the lock screen.
///
/// The overlay covers area of 170x170 pixels (centered at `pos`).
pub struct UnlockOverlay {
/// Center of the overlay
pos: Point,
// Angle of the rotation (in degrees)
angle: f32,
}
impl UnlockOverlay {
/// Outer radius
pub const RADIUS: i16 = 85;
/// Distance between the circles
pub const SPAN: i16 = 10;
/// Thickness of the circles
pub const THICKNESS: i16 = 4;
/// Create a new overlay with the given center and rotation angle.
pub fn new(pos: Point, angle: f32) -> Self {
Self { pos, angle }
}
pub fn render<'a>(self, renderer: &mut impl Renderer<'a>) {
renderer.render_shape(self);
}
fn prepare_overlay(&self, canvas: &mut dyn Canvas) {
let center = canvas.bounds().center();
let transp = Color::black();
let opaque = Color::white();
canvas.fill_background(opaque);
// The most outer circle (with two sectors)
let angle = self.angle;
let r = Self::RADIUS;
canvas.fill_sector(center, r, 0.0 + angle, 140.0 + angle, transp);
canvas.fill_sector(center, r, 235.0 + angle, 270.0 + angle, transp);
canvas.fill_circle(center, r - Self::THICKNESS, opaque, 255);
// The second circle (with one sector)
let angle = -self.angle - 20.0;
let r = Self::RADIUS - Self::SPAN;
canvas.fill_sector(center, r, 0.0 + angle, 135.0 + angle, transp);
canvas.fill_circle(center, r - Self::THICKNESS, opaque, 255);
// The third circle (with one sector)
let angle = self.angle / 2.0 + 90.0;
let r = Self::RADIUS - 2 * Self::SPAN;
canvas.fill_sector(center, r, 0.0 + angle, 270.0 + angle, transp);
canvas.fill_circle(center, r - Self::THICKNESS, opaque, 255);
// The fourth circle (with two sectors)
let angle = -self.angle / 2.0 + 60.0;
let r = Self::RADIUS - 3 * Self::SPAN;
canvas.fill_sector(center, r, 0.0 + angle, 110.0 + angle, transp);
canvas.fill_sector(center, r, 180.0 + angle, 280.0 + angle, transp);
canvas.fill_circle(center, r - Self::THICKNESS, opaque, 255);
// Innner fixed circle
let r = Self::RADIUS - (9 * Self::SPAN) / 2;
canvas.fill_circle(center, r, transp, 255);
canvas.fill_circle(center, r - Self::THICKNESS, opaque, 255);
}
}
impl<'a> Shape<'a> for UnlockOverlay {
fn bounds(&self) -> Rect {
Rect::new(
self.pos - Offset::uniform(Self::RADIUS),
self.pos + Offset::uniform(Self::RADIUS + 1),
)
}
fn cleanup(&mut self, _cache: &DrawingCache<'a>) {
// TODO: inform the cache that we won't use the zlib slot anymore
}
fn draw(&mut self, canvas: &mut dyn Canvas, cache: &DrawingCache<'a>) {
let bounds = self.bounds();
let overlay_buff = &mut unwrap!(cache.image_buff(), "No image buffer");
let mut overlay_canvas = unwrap!(
Mono8Canvas::new(bounds.size(), None, None, &mut overlay_buff[..]),
"Too small buffer"
);
self.prepare_overlay(&mut overlay_canvas);
canvas.blend_bitmap(bounds, overlay_canvas.view().with_fg(Color::black()));
}
}
impl<'a> ShapeClone<'a> for UnlockOverlay {
fn clone_at_bump<T>(self, bump: &'a T) -> Option<&'a mut dyn Shape<'a>>
where
T: LocalAllocLeakExt<'a>,
{
let clone = bump.alloc_t()?;
Some(clone.uninit.init(UnlockOverlay { ..self }))
}
}

@ -17,6 +17,10 @@ const ZLIB_CACHE_SLOTS: usize = 1;
const ZLIB_CACHE_SLOTS: usize = 3;
const RENDER_BUFF_SIZE: usize = (240 * 2 * 16) + ALIGN_PAD;
#[cfg(feature = "model_mercury")]
const IMAGE_BUFF_SIZE: usize = 32768 + ALIGN_PAD;
#[cfg(not(feature = "model_mercury"))]
const IMAGE_BUFF_SIZE: usize = 2048 + ALIGN_PAD;
pub type ImageBuff = [u8; IMAGE_BUFF_SIZE];

@ -34,4 +34,5 @@ pub use rawimage::RawImage;
pub use render::{DirectRenderer, ProgressiveRenderer, Renderer};
pub use text::Text;
pub use toif::ToifImage;
#[cfg(feature = "model_mercury")]
pub use utils::ImageBuffer;

@ -4,6 +4,7 @@ use crate::ui::{
};
/// Size of image buffer in bytes
/// (up to 180x180 pixel, 16-bit RGB565 image)
const IMAGE_BUFFER_SIZE: usize = 64 * 1024;
#[repr(align(16))]

@ -6,6 +6,9 @@ mod trigo;
pub use blur::{BlurAlgorithm, BlurBuff};
pub use circle::circle_points;
#[cfg(feature = "model_mercury")]
pub use imagebuf::ImageBuffer;
pub use line::line_points;
pub use trigo::sin_f32;

Loading…
Cancel
Save