From 1102dc7338f1b4ec5ad6362da33ab3c52fcdff98 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Thu, 26 Feb 2026 19:18:27 -0500 Subject: [PATCH] work --- examples/minimal.rs | 6 +- examples/tabs/main.rs | 6 +- examples/task.rs | 6 +- examples/view.rs | 6 +- src/default/event.rs | 4 ++ src/default/mod.rs | 151 +++++++++++++++++++++++++++++------------- src/default/task.rs | 11 ++- 7 files changed, 119 insertions(+), 71 deletions(-) diff --git a/examples/minimal.rs b/examples/minimal.rs index e98ae5b..8b2fb79 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -10,11 +10,7 @@ struct State { } impl DefaultAppState for State { - fn new( - mut ui_state: DefaultUiState, - rsc: &mut DefaultRsc, - _: Proxy, - ) -> Self { + fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc) -> Self { rect(Color::RED).set_root(rsc, &mut ui_state); Self { ui_state } } diff --git a/examples/tabs/main.rs b/examples/tabs/main.rs index d888e1a..8a1d753 100644 --- a/examples/tabs/main.rs +++ b/examples/tabs/main.rs @@ -16,11 +16,7 @@ pub struct Client { } impl DefaultAppState for Client { - fn new( - mut ui_state: DefaultUiState, - rsc: &mut DefaultRsc, - _: Proxy, - ) -> Self { + fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc) -> Self { let rrect = rect(Color::WHITE).radius(20); let pad_test = ( rrect.color(Color::BLUE), diff --git a/examples/task.rs b/examples/task.rs index 63e4d43..627141b 100644 --- a/examples/task.rs +++ b/examples/task.rs @@ -11,11 +11,7 @@ struct State { } impl DefaultAppState for State { - fn new( - mut ui_state: DefaultUiState, - rsc: &mut DefaultRsc, - _: Proxy, - ) -> Self { + fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc) -> Self { let rect = rect(Color::RED).add(rsc); rect.task_on(CursorSense::click(), async move |mut ctx| { tokio::time::sleep(Duration::from_secs(1)).await; diff --git a/examples/view.rs b/examples/view.rs index b8e06cf..4d8d652 100644 --- a/examples/view.rs +++ b/examples/view.rs @@ -36,11 +36,7 @@ impl Test { } impl DefaultAppState for State { - fn new( - mut ui_state: DefaultUiState, - rsc: &mut DefaultRsc, - _: Proxy, - ) -> Self { + fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc) -> Self { let test = Test::new(rsc); test.on(CursorSense::click(), move |_, rsc| { diff --git a/src/default/event.rs b/src/default/event.rs index 2ba4add..1d2611e 100644 --- a/src/default/event.rs +++ b/src/default/event.rs @@ -11,3 +11,7 @@ impl Event for Edited {} #[derive(Eq, PartialEq, Hash, Clone)] pub struct Draw; impl Event for Draw {} + +#[derive(Eq, PartialEq, Hash, Clone)] +pub struct Undraw; +impl Event for Undraw {} diff --git a/src/default/mod.rs b/src/default/mod.rs index 085ed5d..00628a0 100644 --- a/src/default/mod.rs +++ b/src/default/mod.rs @@ -29,7 +29,26 @@ pub use sense::*; pub use state::*; pub use task::*; -pub type Proxy = EventLoopProxy; +pub struct EventSender { + proxy: EventLoopProxy>, +} + +impl Clone for EventSender { + fn clone(&self) -> Self { + Self { + proxy: self.proxy.clone(), + } + } +} + +impl EventSender { + pub fn send(&self, event: State::Event) { + let _ = self.proxy.send_event(UiMainEvent::App(event)); + } + pub fn run(&self, f: impl MainCallback) { + let _ = self.proxy.send_event(UiMainEvent::Callback(Box::new(f))); + } +} pub struct DefaultUiState { pub root: Option, @@ -70,9 +89,8 @@ pub trait HasDefaultUiState: Sized + 'static { } pub trait DefaultAppState: HasDefaultUiState { - type Event = (); - fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc, proxy: Proxy) - -> Self; + type Event: Send = (); + fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc) -> Self; #[allow(unused_variables)] fn event( &mut self, @@ -96,12 +114,13 @@ pub trait DefaultAppState: HasDefaultUiState { } } -pub struct DefaultRsc { +pub struct DefaultRsc { pub ui: UiData, pub events: EventManager, pub tasks: Tasks, pub state: WidgetState, pub widget_events: Vec, + pub window_event: EventSender, _state: PhantomData, } @@ -116,9 +135,25 @@ pub enum WidgetEventType { Remove, } -impl DefaultRsc { - fn init(window: Arc) -> (Self, TaskMsgReceiver) { - let (tasks, recv) = Tasks::init(window); +pub trait MainCallback: FnOnce(&mut DefaultRsc) + Sync + Send + 'static {} +impl) + Sync + Send + 'static, State> MainCallback for F {} + +pub enum UiMainEvent { + RequestUpdate, + Callback(Box>), + App(State::Event), +} + +impl DefaultRsc { + fn init(proxy: EventLoopProxy>) -> (Self, TaskMsgReceiver) { + let window_event = EventSender { + proxy: proxy.clone(), + }; + let (tasks, recv) = Tasks::init(move || { + if proxy.send_event(UiMainEvent::RequestUpdate).is_err() { + panic!("main thread blew up or smth"); + } + }); ( Self { ui: Default::default(), @@ -126,6 +161,7 @@ impl DefaultRsc { tasks, widget_events: Default::default(), state: Default::default(), + window_event, _state: Default::default(), }, recv, @@ -137,7 +173,7 @@ impl DefaultRsc { } } -impl UiRsc for DefaultRsc { +impl UiRsc for DefaultRsc { fn ui(&self) -> &UiData { &self.ui } @@ -174,11 +210,11 @@ impl UiRsc for DefaultRsc { } } -impl HasState for DefaultRsc { +impl HasState for DefaultRsc { type State = State; } -impl HasEvents for DefaultRsc { +impl HasEvents for DefaultRsc { fn events(&self) -> &EventManager { &self.events } @@ -188,13 +224,13 @@ impl HasEvents for DefaultRsc { } } -impl HasTasks for DefaultRsc { +impl HasTasks for DefaultRsc { fn tasks_mut(&mut self) -> &mut Tasks { &mut self.tasks } } -impl HasWidgetState for DefaultRsc { +impl HasWidgetState for DefaultRsc { fn widget_state(&self) -> &WidgetState { &self.state } @@ -212,15 +248,15 @@ pub struct DefaultApp { } impl AppState for DefaultApp { - type Event = State::Event; + type Event = UiMainEvent; fn new(event_loop: &ActiveEventLoop, proxy: EventLoopProxy) -> Self { let window = event_loop .create_window(State::window_attributes()) .unwrap(); let default_state = DefaultUiState::new(window); - let (mut rsc, task_recv) = DefaultRsc::init(default_state.window.clone()); - let state = State::new(default_state, &mut rsc, proxy); + let (mut rsc, task_recv) = DefaultRsc::init(proxy); + let state = State::new(default_state, &mut rsc); let render = UiRenderState::new(); Self { rsc, @@ -231,38 +267,39 @@ impl AppState for DefaultApp { } fn event(&mut self, event: Self::Event, _: &ActiveEventLoop) { - self.state.event(event, &mut self.rsc, &mut self.render); + match event { + UiMainEvent::RequestUpdate => { + self.check_updates(); + } + UiMainEvent::App(event) => { + self.state.event(event, &mut self.rsc, &mut self.render); + } + UiMainEvent::Callback(f) => f(&mut self.rsc), + } } fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) { let Self { - rsc, - render, - state, - task_recv, + rsc, render, state, .. } = self; - for update in task_recv.try_iter() { - update(state, rsc); - } - + // input handling let ui_state = state.default_state_mut(); - let input_changed = ui_state.input.event(&event); - let cursor_state = ui_state.cursor_state().clone(); - let old = ui_state.focus; - if cursor_state.buttons.left.is_start() { - ui_state.focus = None; - } - if input_changed { + if ui_state.input.event(&event) { + let cursor_state = ui_state.cursor_state().clone(); + let old = ui_state.focus; + if cursor_state.buttons.left.is_start() { + ui_state.focus = None; + } let window_size = ui_state.window_size(); render.run_sensors(rsc, state, cursor_state, window_size); + if old != state.default_state().focus + && let Some(old) = old + { + old.edit(rsc).deselect(); + } } let ui_state = state.default_state_mut(); - if old != ui_state.focus - && let Some(old) = old - { - old.edit(rsc).deselect(); - } match &event { WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::RedrawRequested => { @@ -325,26 +362,46 @@ impl AppState for DefaultApp { } state.window_event(event, rsc, render); + self.check_updates(); + self.state.default_state_mut().input.end_frame(); + } + + fn exit(&mut self) { + self.state.exit(&mut self.rsc, &mut self.render); + } +} + +impl DefaultApp { + pub fn check_updates(&mut self) { + let Self { + rsc, + render, + state, + task_recv, + } = self; + + for update in task_recv.try_iter() { + update(state, rsc); + } + let mut events = std::mem::take(&mut rsc.widget_events); for event in events.drain(..) { match event.ty { WidgetEventType::Draw => { rsc.run_event::(event.id, (), state); } + WidgetEventType::Undraw => { + rsc.run_event::(event.id, (), state); + } _ => (), } } rsc.widget_events = events; - let ui_state = self.state.default_state_mut(); + let ui_state = state.default_state(); if render.needs_redraw(&ui_state.root, rsc.widgets()) { ui_state.renderer.window().request_redraw(); } - ui_state.input.end_frame(); - } - - fn exit(&mut self) { - self.state.exit(&mut self.rsc, &mut self.render); } } @@ -354,7 +411,9 @@ pub trait RscIdx { fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output; } -impl>> std::ops::Index for DefaultRsc { +impl>> std::ops::Index + for DefaultRsc +{ type Output = I::Output; fn index(&self, index: I) -> &Self::Output { @@ -362,7 +421,9 @@ impl>> std::ops::Index for Defaul } } -impl>> std::ops::IndexMut for DefaultRsc { +impl>> std::ops::IndexMut + for DefaultRsc +{ fn index_mut(&mut self, index: I) -> &mut Self::Output { index.get_mut(self) } diff --git a/src/default/task.rs b/src/default/task.rs index 36b55c1..4d6e39d 100644 --- a/src/default/task.rs +++ b/src/default/task.rs @@ -13,7 +13,6 @@ use tokio::{ unbounded_channel as async_channel, }, }; -use winit::window::Window; pub type TaskMsgSender = SyncSender>>; pub type TaskMsgReceiver = SyncReceiver>>; @@ -23,7 +22,7 @@ impl TaskUpdate pub struct Tasks { start: AsyncSender, - window: Arc, + request_update: Arc, msg_send: SyncSender>>, } @@ -45,7 +44,7 @@ impl TaskCtx { type BoxTask = Pin + Send>>; impl Tasks { - pub fn init(window: Arc) -> (Self, TaskMsgReceiver) { + pub fn init(request_update: impl Fn() + 'static + Send + Sync) -> (Self, TaskMsgReceiver) { let (start, start_recv) = async_channel(); let (msgs, msgs_recv) = sync_channel(); std::thread::spawn(|| { @@ -56,7 +55,7 @@ impl Tasks { Self { start, msg_send: msgs, - window, + request_update: Arc::new(request_update), }, msgs_recv, ) @@ -67,10 +66,10 @@ impl Tasks { F::CallOnceFuture: Send, { let send = self.msg_send.clone(); - let window = self.window.clone(); + let request_update = self.request_update.clone(); let _ = self.start.send(Box::pin(async move { task(TaskCtx::new(send)).await; - window.request_redraw(); + request_update(); })); } }