123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- 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<Self::Msg>;
- type RootWidget: Widget<Self>;
- fn root_widget(&self) -> &Self::RootWidget;
- fn root_widget_mut(&mut self) -> &mut Self::RootWidget;
- }
- pub(crate) struct WindowState<WC: WindowComponent> {
- wc: WC,
- root_node: LayoutNode,
- window: Rc<winit::window::Window>,
- events: Vec<WindowEvent>,
- istate: InputState,
- surface: softbuffer::Surface<Rc<winit::window::Window>, Rc<winit::window::Window>>,
- bitmap: RefCell<Option<kahlo::Bitmap<RenderFormat>>>,
- }
- impl<WC: WindowComponent> WindowState<WC> {
- 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::<kahlo::formats::Bgr32>::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<WC::ParentMsg> {
- 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<WC: WindowComponent> WindowStateAccess for RefCell<WindowState<WC>> {
- 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<WC: WindowComponent>(self, wc: impl FnOnce(&mut UIHandle) -> WC) -> Window<WC> {
- 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<dyn WindowStateAccess>)),
- );
- Window { state: wstate }
- }
- }
- pub struct Window<WC: WindowComponent> {
- state: Rc<RefCell<WindowState<WC>>>,
- }
- impl<WC: WindowComponent> Window<WC> {
- pub fn poll(&mut self, uih: &mut UIHandle) -> Vec<WC::ParentMsg> {
- self.state.borrow_mut().poll(uih)
- }
- }
|