use std::cell::RefCell; use std::rc::Rc; use kahlo::{ math::{PixelBox, PixelPoint, PixelSize}, prelude::*, }; use crate::input::{InputState, MouseButton}; use crate::layout::{self, LayoutNode, LayoutNodeAccess, LinearAccess}; use crate::widget::Widget; use crate::{component::Component, ui::UIHandle}; pub type RenderFormat = kahlo::formats::Bgr32; #[derive(Debug)] pub enum WindowEvent { CloseRequested, Resized, } pub trait WindowComponent: 'static + Sized + Component { fn map_window_event(&self, we: WindowEvent) -> Option; type RootWidget: Widget; fn root_widget(&self) -> &Self::RootWidget; fn root_widget_mut(&mut self) -> &mut Self::RootWidget; } pub(crate) struct WindowState { wc: WC, root_node: LayoutNode, window: Rc, events: Vec, istate: InputState, surface: softbuffer::Surface, Rc>, bitmap: RefCell>>, } impl WindowState { fn redraw(&mut self, uih: &UIHandle) { let size = self.window.inner_size(); // if size.width != self.surface.buffer_mut().unwrap(). self.surface .resize( size.width.try_into().unwrap(), size.height.try_into().unwrap(), ) .unwrap(); let mut buf = self.surface.buffer_mut().unwrap(); self.root_node.set_behaviour(layout::NodeBehaviour::Fixed { area: PixelBox::from_size(PixelSize::new(size.width as i32, size.height as i32)), }); let layout = LinearAccess::new(&self.root_node, self.wc.root_widget().layout_node()); let mut bitmap = self.bitmap.borrow_mut(); if bitmap.as_ref().map(|v| v.size()) != Some(PixelSize::new(size.width as i32, size.height as i32)) { bitmap.take(); } let bitmap = bitmap.get_or_insert_with(|| { kahlo::Bitmap::new(size.width as usize, size.height as usize) }); let mut windowbuffer = kahlo::BitmapMut::::new( unsafe { std::slice::from_raw_parts_mut(buf[..].as_mut_ptr() as *mut u8, buf.len() * 4) }, size.width as usize, size.height as usize, ); layout::recalculate(LayoutNodeAccess::new(&layout)); let before = std::time::Instant::now(); self.wc.root_widget().render(uih.theme(), &mut bitmap.as_mut()); windowbuffer.copy_from( bitmap, PixelBox::from_size(bitmap.size()), PixelPoint::zero() ); let after = std::time::Instant::now(); print!("render time: {:?} \r", (after - before)); buf.present().unwrap(); } fn poll(&mut self, uih: &mut UIHandle) -> Vec { let mut ret = vec![]; for we in self.events.drain(..) { let mapped = self.wc.map_window_event(we); ret.extend(self.wc.process_all(mapped.into_iter()).into_iter()); } let evts = self.wc.root_widget_mut().poll(uih, Some(&self.istate)); ret.extend(self.wc.process_all(evts.into_iter())); self.istate.tick(); ret } } pub(crate) trait WindowStateAccess { fn notify_resize(&self, new_size: PixelSize); fn push_event(&self, we: WindowEvent); fn redraw(&self, uih: &UIHandle); fn request_redraw(&self); fn update_mouse_pos(&self, pos: PixelPoint); fn update_mouse_button(&self, which: MouseButton, to: bool); } impl WindowStateAccess for RefCell> { fn notify_resize(&self, new_size: PixelSize) { if Some(new_size) != self.borrow().bitmap.borrow().as_ref().map(|v| v.size()) { self.borrow_mut().bitmap.take(); self.borrow_mut().wc.root_widget().layout_node().relayout_tree(); self.borrow_mut().wc.root_widget().layout_node().render_needed(); } } fn push_event(&self, we: WindowEvent) { self.borrow_mut().events.push(we); } fn redraw(&self, uih: &UIHandle) { self.borrow_mut().redraw(uih); } fn request_redraw(&self) { self.borrow().window.request_redraw(); } fn update_mouse_pos(&self, pos: PixelPoint) { self.borrow_mut().istate.mouse.pos = pos; } fn update_mouse_button(&self, which: MouseButton, to: bool) { let is = &mut self.borrow_mut().istate; is.mouse.buttons.set_button(which, to); } } pub struct WindowBuilder<'r, 'l: 'r> { ui_handle: &'r mut UIHandle<'l>, } impl<'r, 'l: 'r> WindowBuilder<'r, 'l> { pub(crate) fn new(ui_handle: &'r mut UIHandle<'l>) -> Self { Self { ui_handle } } pub fn build(self, wc: impl FnOnce(&mut UIHandle) -> WC) -> Window { let window = Rc::new( self.ui_handle .eloop .create_window(winit::window::WindowAttributes::default()) .unwrap(), ); let wid = window.id(); let ctx = softbuffer::Context::new(window.clone()).unwrap(); let surface = softbuffer::Surface::new(&ctx, window.clone()).unwrap(); let wc = wc(self.ui_handle); let wstate = Rc::new(RefCell::new(WindowState { wc, root_node: LayoutNode::new(self.ui_handle.state.layout_cache.clone()), window, events: Default::default(), istate: InputState::default().into(), surface: surface.into(), bitmap: None.into(), })); self.ui_handle.state.window_states.insert( wid, Rc::downgrade(&(wstate.clone() as Rc)), ); Window { state: wstate } } } pub struct Window { state: Rc>>, } impl Window { pub fn poll(&mut self, uih: &mut UIHandle) -> Vec { self.state.borrow_mut().poll(uih) } }