acid/firmware2/src/ui/backend.rs
2026-01-11 00:06:35 +01:00

95 lines
3.4 KiB
Rust

use core::{cell::RefCell, time::Duration};
use alloc::rc::Rc;
use esp_hal::time::Instant;
use log::{debug, info, warn};
use slint::{
PhysicalSize, SharedString, WindowSize,
platform::{
Key, WindowEvent,
software_renderer::{RenderingRotation, RepaintBufferType, Rgb565Pixel, SoftwareRenderer},
},
};
use xkbcommon::xkb;
use crate::keymap::{KEY_MESSAGE_CHANNEL, TryFromKeysym};
use super::window_adapter::SoftwareWindowAdapter;
pub struct FramebufferPtr(pub *mut [Rgb565Pixel]);
unsafe impl Send for FramebufferPtr {}
pub struct SlintBackend {
pub window_size: [u32; 2],
pub window: RefCell<Option<Rc<SoftwareWindowAdapter>>>,
pub framebuffer: FramebufferPtr,
// pub peripherals: RefCell<Option<Peripherals>>,
}
impl slint::platform::Platform for SlintBackend {
fn create_window_adapter(
&self,
) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
// TODO: Custom window adapter impl needs to be implemented, so we can change `rotation` on
// `SoftwareRenderer`.
let renderer = SoftwareRenderer::new_with_repaint_buffer_type(
RepaintBufferType::ReusedBuffer, /* TODO: Implement a swapchain */
);
renderer.set_rendering_rotation(RenderingRotation::Rotate270);
let window = SoftwareWindowAdapter::new(renderer);
// window.set_scale_factor(4.0);
window.set_size(WindowSize::Physical(PhysicalSize::new(
self.window_size[0],
self.window_size[1],
)));
self.window.replace(Some(window.clone()));
Ok(window)
}
fn duration_since_start(&self) -> Duration {
Duration::from_millis(Instant::now().duration_since_epoch().as_millis())
}
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
// Instead of `loop`ing here, we execute a single iteration and handle `loop`ing
// in `crate::run_renderer_task`, where we can make use of `await`.
/* loop */
{
if let Some(window) = self.window.borrow().clone() {
// Handle key presses
while let Ok(key_message) = KEY_MESSAGE_CHANNEL.try_receive() {
debug!("key_message = {key_message:?}");
let text = key_message.string.map(SharedString::from).or_else(|| {
Key::try_from_keysym(key_message.keysym).map(SharedString::from)
});
debug!("text = {text:?}");
if let Some(text) = text {
match key_message.direction {
xkb::KeyDirection::Down => window
.try_dispatch_event(WindowEvent::KeyPressed { text: text.clone() })
.unwrap(),
xkb::KeyDirection::Up => window
.try_dispatch_event(WindowEvent::KeyReleased { text })
.unwrap(),
}
}
}
window.draw_if_needed(|renderer| {
// TODO: Proper synchronization.
let framebuffer = unsafe { &mut *self.framebuffer.0 };
renderer.render(framebuffer, self.window_size[1] as usize);
info!("UI rendered.");
});
}
}
Ok(())
}
}