use crate::prelude::*; use arboard::Clipboard; use std::{ marker::{PhantomData, Sized}, sync::Arc, time::Instant, }; use winit::{ event::{Ime, WindowEvent}, event_loop::{ActiveEventLoop, EventLoopProxy}, window::{Window, WindowAttributes}, }; mod app; mod attr; mod event; mod input; mod render; mod sense; mod state; mod task; pub use app::*; pub use attr::*; pub use event::*; pub use input::*; pub use render::*; pub use sense::*; pub use state::*; pub use task::*; pub type Proxy = EventLoopProxy; pub struct DefaultUiState { pub root: Option, pub renderer: UiRenderer, pub input: Input, pub focus: Option>, pub clipboard: Clipboard, pub window: Arc, pub ime: usize, pub last_click: Instant, } impl HasRoot for DefaultUiState { fn set_root(&mut self, root: StrongWidget) { self.root = Some(root); } } impl DefaultUiState { pub fn new(window: impl Into>) -> Self { let window = window.into(); Self { root: None, renderer: UiRenderer::new(window.clone()), window, input: Input::default(), clipboard: Clipboard::new().unwrap(), ime: 0, last_click: Instant::now(), focus: None, } } } pub trait HasDefaultUiState: Sized + 'static { fn default_state(&self) -> &DefaultUiState; fn default_state_mut(&mut self) -> &mut DefaultUiState; } pub trait DefaultAppState: HasDefaultUiState { type Event = (); fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc, proxy: Proxy) -> Self; #[allow(unused_variables)] fn event( &mut self, event: Self::Event, rsc: &mut DefaultRsc, render: &mut UiRenderState, ) { } #[allow(unused_variables)] fn exit(&mut self, rsc: &mut DefaultRsc, render: &mut UiRenderState) {} #[allow(unused_variables)] fn window_event( &mut self, event: WindowEvent, rsc: &mut DefaultRsc, render: &mut UiRenderState, ) { } fn window_attributes() -> WindowAttributes { Default::default() } } pub struct DefaultRsc { pub ui: UiData, pub events: EventManager, pub tasks: Tasks, pub state: WidgetState, _state: PhantomData, } impl DefaultRsc { fn init(window: Arc) -> (Self, TaskMsgReceiver) { let (tasks, recv) = Tasks::init(window); ( Self { ui: Default::default(), events: Default::default(), tasks, state: Default::default(), _state: Default::default(), }, recv, ) } pub fn create_state(&mut self, id: impl IdLike, data: T) -> WeakState { self.state.add(id.id(), data) } } impl UiRsc for DefaultRsc { fn ui(&self) -> &UiData { &self.ui } fn ui_mut(&mut self) -> &mut UiData { &mut self.ui } fn on_draw(&mut self, active: &ActiveData) { self.events.draw(active); } fn on_undraw(&mut self, active: &ActiveData) { self.events.undraw(active); } fn on_remove(&mut self, id: WidgetId) { self.events.remove(id); self.state.remove(id); } } impl HasState for DefaultRsc { type State = State; } impl HasEvents for DefaultRsc { fn events(&self) -> &EventManager { &self.events } fn events_mut(&mut self) -> &mut EventManager { &mut self.events } } impl HasTasks for DefaultRsc { fn tasks_mut(&mut self) -> &mut Tasks { &mut self.tasks } } impl HasWidgetState for DefaultRsc { fn widget_state(&self) -> &WidgetState { &self.state } fn widget_state_mut(&mut self) -> &mut WidgetState { &mut self.state } } pub struct DefaultApp { rsc: DefaultRsc, render: UiRenderState, state: State, task_recv: TaskMsgReceiver>, } impl AppState for DefaultApp { type Event = State::Event; 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 render = UiRenderState::new(); Self { rsc, state, render, task_recv, } } fn event(&mut self, event: Self::Event, _: &ActiveEventLoop) { self.state.event(event, &mut self.rsc, &mut self.render); } fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) { let Self { rsc, render, state, task_recv, } = self; for update in task_recv.try_iter() { update(state, rsc); } 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 { let window_size = ui_state.window_size(); render.run_sensors(rsc, state, cursor_state, window_size); } 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 => { render.update(&ui_state.root, rsc); ui_state.renderer.update(&mut rsc.ui, render); ui_state.renderer.draw(); } WindowEvent::Resized(size) => { render.resize((size.width, size.height)); ui_state.renderer.resize(size) } WindowEvent::KeyboardInput { event, .. } => { if let Some(sel) = ui_state.focus && event.state.is_pressed() { let mut text = sel.edit(rsc); match text.apply_event(event, &ui_state.input.modifiers) { TextInputResult::Unfocus => { ui_state.focus = None; ui_state.window.set_ime_allowed(false); } TextInputResult::Submit => { rsc.run_event::(sel, (), state); } TextInputResult::Paste => { if let Ok(t) = ui_state.clipboard.get_text() { text.insert(&t); } rsc.run_event::(sel, (), state); } TextInputResult::Copy(text) => { if let Err(err) = ui_state.clipboard.set_text(text) { eprintln!("failed to copy text to clipboard: {err}") } } TextInputResult::Used => { rsc.run_event::(sel, (), state); } TextInputResult::Unused => {} } } } WindowEvent::Ime(ime) => { if let Some(sel) = ui_state.focus { let mut text = sel.edit(rsc); match ime { Ime::Enabled | Ime::Disabled => (), Ime::Preedit(content, _pos) => { // TODO: highlight once that's real text.replace(ui_state.ime, content); ui_state.ime = content.chars().count(); } Ime::Commit(content) => { text.insert(content); } } } } _ => (), } state.window_event(event, rsc, render); let ui_state = self.state.default_state_mut(); 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); } } pub trait RscIdx { type Output; fn get(self, rsc: &Rsc) -> &Self::Output; fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output; } impl>> std::ops::Index for DefaultRsc { type Output = I::Output; fn index(&self, index: I) -> &Self::Output { index.get(self) } } impl>> std::ops::IndexMut for DefaultRsc { fn index_mut(&mut self, index: I) -> &mut Self::Output { index.get_mut(self) } } impl RscIdx for WeakWidget { type Output = W; fn get(self, rsc: &Rsc) -> &Self::Output { &rsc.ui().widgets[self] } fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output { &mut rsc.ui_mut().widgets[self] } } impl RscIdx for WeakState { type Output = T; fn get(self, rsc: &Rsc) -> &Self::Output { rsc.widget_state().get(self) } fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output { rsc.widget_state_mut().get_mut(self) } }