use crate::Instruction; use crate::core; use crate::core::mouse; use crate::core::renderer; use crate::core::window; use crate::core::{Element, Size}; use crate::program::Program; use crate::runtime::futures::futures::StreamExt; use crate::runtime::futures::futures::channel::mpsc; use crate::runtime::futures::subscription; use crate::runtime::futures::{Executor, Runtime}; use crate::runtime::task; use crate::runtime::user_interface; use crate::runtime::{Action, UserInterface}; #[allow(missing_debug_implementations)] pub struct Emulator { state: P::State, runtime: Runtime>, Event

>, renderer: P::Renderer, size: Size, window: window::Id, cursor: mouse::Cursor, clipboard: Clipboard, cache: Option, } #[allow(missing_debug_implementations)] pub enum Event { Action(Action), Ready, } impl Emulator

{ pub fn new( program: &P, size: Size, sender: mpsc::Sender>, ) -> Emulator

{ use renderer::Headless; let settings = program.settings(); // TODO: Error handling let executor = P::Executor::new().expect("Create emulator executor"); let renderer = executor .block_on(P::Renderer::new( settings.default_font, settings.default_text_size, None, )) .expect("Create emulator renderer"); let mut runtime = Runtime::new(executor, sender); let (state, task) = program.boot(); if let Some(stream) = task::into_stream(task) { runtime.run(stream.map(Event::Action).boxed()); } // TODO: Async boot environments runtime.send(Event::Ready); Self { state, runtime, renderer, size, clipboard: Clipboard { content: None }, cursor: mouse::Cursor::Unavailable, window: window::Id::unique(), cache: Some(user_interface::Cache::default()), } } pub fn update(&mut self, program: &P, message: P::Message) { let task = program.update(&mut self.state, message); if let Some(stream) = task::into_stream(task) { self.runtime.run(stream.map(Event::Action).boxed()); } self.runtime.track(subscription::into_recipes( program .subscription(&self.state) .map(|message| Event::Action(Action::Output(message))), )); } pub fn perform(&mut self, program: &P, action: Action) { match action { Action::Output(message) => { self.update(program, message); } Action::LoadFont { .. } => { // TODO } Action::Widget(_operation) => { // TODO } Action::Clipboard(action) => { // TODO dbg!(action); } Action::Window(_action) => { // TODO } Action::System(action) => { // TODO dbg!(action); } Action::Exit => { // TODO } } } pub fn run(&mut self, program: &P, instruction: Instruction) { let mut user_interface = UserInterface::build( program.view(&self.state, self.window), self.size, self.cache.take().unwrap(), &mut self.renderer, ); let mut messages = Vec::new(); match instruction { Instruction::Interact(interaction) => { let events = interaction.events(); for event in &events { if let core::Event::Mouse(mouse::Event::CursorMoved { position, }) = event { self.cursor = mouse::Cursor::Available(*position); } } let (_state, _status) = user_interface.update( &events, self.cursor, &mut self.renderer, &mut self.clipboard, &mut messages, ); } } self.cache = Some(user_interface.into_cache()); for message in messages { self.update(program, message); } self.runtime.send(Event::Ready); } pub fn view( &self, program: &P, ) -> Element<'_, P::Message, P::Theme, P::Renderer> { program.view(&self.state, self.window) } pub fn theme(&self, program: &P) -> P::Theme { program.theme(&self.state, self.window) } } struct Clipboard { content: Option, } impl core::Clipboard for Clipboard { fn read(&self, _kind: core::clipboard::Kind) -> Option { self.content.clone() } fn write(&mut self, _kind: core::clipboard::Kind, contents: String) { self.content = Some(contents); } }