use std::cell::OnceCell; use std::rc::Rc; use std::sync::Arc; use std::sync::atomic::AtomicUsize; use evdev::KeyCode; use linfb::shape::Color; use slint::platform::software_renderer::{MinimalSoftwareWindow, RepaintBufferType, Rgb565Pixel}; use slint::platform::{EventLoopProxy, Platform, WindowEvent}; use slint::{EventLoopError, LogicalPosition, PhysicalSize, Rgb8Pixel, WindowSize}; use self::input::InputState; use self::screen::Screen; mod input; mod screen; static EVENTLOOP_PROXY: OnceCell> = OnceCell::new(); pub struct Context { pub screen: Screen, pub input: InputState, } pub struct Trekstor { window: Rc, } impl Trekstor { pub fn new() -> Self { let window = MinimalSoftwareWindow::new(RepaintBufferType::NewBuffer); Self { window } } } impl Platform for Trekstor { fn create_window_adapter( &self, ) -> Result, slint::PlatformError> { Ok(self.window.clone()) } fn run_event_loop(&self) -> Result<(), slint::PlatformError> { let screen = Screen::new(); let input = InputState::new(&screen); let mut ctx = Context { screen, input }; let mut buffer1 = [Rgb565Pixel(0); 614400]; let window_width = ctx.screen.width(); let window_height = ctx.screen.height(); self.window.set_size(WindowSize::Physical(PhysicalSize::new( window_width, window_height, ))); loop { ctx.input.handle_event(); slint::platform::update_timers_and_animations(); if ctx.input.is_just_pressed(KeyCode::BTN_TOUCH) { self.window .try_dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(ctx.input.x as f32, ctx.input.y as f32), button: slint::platform::PointerEventButton::Left, }) .unwrap(); } if ctx.input.is_just_released(KeyCode::BTN_TOUCH) { self.window .try_dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(ctx.input.x as f32, ctx.input.y as f32), button: slint::platform::PointerEventButton::Left, }) .unwrap(); } if ctx.input.is_down(KeyCode::BTN_TOUCH) { self.window .try_dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(ctx.input.x as f32, ctx.input.y as f32), }) .unwrap(); } self.window.draw_if_needed(|renderer| { renderer.render(&mut buffer1, window_width as usize); for (i, px) in buffer1.into_iter().enumerate() { let x = (i % window_width as usize) as u32; let y = (i / window_width as usize) as u32; let pixel = Rgb8Pixel::from(px); let c = Color::from((pixel.r, pixel.g, pixel.b, 255)); ctx.screen.framebuffer.set_pixel(x, y, c); } ctx.screen.flush(); }); ctx.input.finish(); } } fn new_event_loop_proxy(&self) -> Option> { // struct Proxy( // winit::event_loop::EventLoopProxy, // Arc, // ); // impl EventLoopProxy for Proxy { // fn quit_event_loop(&self) -> Result<(), EventLoopError> { // Err(EventLoopError::EventLoopTerminated) // } // fn invoke_from_event_loop( // &self, // event: Box, // ) -> Result<(), EventLoopError> { // self.0 // .send_event(SlintEvent(CustomEvent::UserEvent(event))) // .map_err(|_| EventLoopError::EventLoopTerminated) // } // } // Some(Box::new(Proxy( // self.shared_data.event_loop_proxy.clone(), // Arc::clone(&self.shared_data.event_loop_generation), // ))) None } fn click_interval(&self) -> core::time::Duration { // 500ms is the default delay according to https://en.wikipedia.org/wiki/Double-click#Speed_and_timing core::time::Duration::from_millis(500) } fn cursor_flash_cycle(&self) -> core::time::Duration { core::time::Duration::from_millis(1000) } fn set_clipboard_text(&self, _text: &str, _clipboard: slint::platform::Clipboard) {} fn clipboard_text(&self, _clipboard: slint::platform::Clipboard) -> Option { None } fn debug_log(&self, _arguments: core::fmt::Arguments) { crate::debug_log::default_log_message(_arguments); } fn open_url(&self, _url: &str) -> Result<(), slint::PlatformError> { Err(slint::PlatformError::Unsupported) } }