diff --git a/devtools/src/lib.rs b/devtools/src/lib.rs index 4a50580d..fa002c8e 100644 --- a/devtools/src/lib.rs +++ b/devtools/src/lib.rs @@ -361,7 +361,7 @@ where match &self.mode { Mode::Open { tester } => { - tester.view(program, window, view, Event::Tester) + tester.view(program, view, Event::Tester) } _ => view(), } @@ -444,19 +444,9 @@ where } pub fn subscription(&self, program: &P) -> Subscription> { - let subscription = match &self.mode { - Mode::Open { tester } if !tester.is_idle() => { - tester.subscription(program).map(Event::Tester) - } - _ => { - let subscription = - program.subscription(&self.state).map(Event::Program); - - debug::subscriptions_tracked(subscription.units()); - - subscription - } - }; + let subscription = + program.subscription(&self.state).map(Event::Program); + debug::subscriptions_tracked(subscription.units()); let hotkeys = futures::keyboard::on_key_press(|key, _modifiers| match key { diff --git a/devtools/src/tester.rs b/devtools/src/tester.rs index 0aa517c0..8c7ac9ce 100644 --- a/devtools/src/tester.rs +++ b/devtools/src/tester.rs @@ -10,7 +10,6 @@ use crate::core::border; use crate::core::window; use crate::core::{Element, Event, Font, Size, Theme}; use crate::executor; -use crate::futures::Subscription; use crate::futures::futures::channel::mpsc; use crate::icon; use crate::program; @@ -36,10 +35,11 @@ pub struct Tester { enum State { Idle, Recording { - state: P::State, + emulator: Emulator

, }, Ready { state: P::State, + window: window::Id, }, Playing { emulator: Emulator

, @@ -98,10 +98,6 @@ impl Tester

{ } } - pub fn is_idle(&self) -> bool { - matches!(self.state, State::Idle) - } - pub fn is_busy(&self) -> bool { matches!( self.state, @@ -134,24 +130,30 @@ impl Tester

{ self.edit = None; self.instructions.clear(); - let (state, task) = if let Some(preset) = self.preset(program) { - preset.boot() - } else { - program.boot() - }; + let (sender, receiver) = mpsc::channel(1); - self.state = State::Recording { state }; + let emulator = Emulator::with_preset( + sender, + program, + self.mode, + self.viewport, + self.preset(program), + ); - task.map(Tick::Program) + self.state = State::Recording { emulator }; + + Task::run(receiver, Tick::Emulator) } Message::Stop => { - let State::Recording { state } = + let State::Recording { emulator } = std::mem::replace(&mut self.state, State::Idle) else { return Task::none(); }; - self.state = State::Ready { state }; + let (state, window) = emulator.into_state(); + + self.state = State::Ready { state, window }; Task::none() } @@ -301,11 +303,13 @@ impl Tester

{ match tick { Tick::Tester(message) => self.update(program, message), Tick::Program(message) => { - let State::Recording { state } = &mut self.state else { + let State::Recording { emulator } = &mut self.state else { return Task::none(); }; - program.update(state, message).map(Tick::Program) + emulator.update(program, message); + + Task::none() } Tick::Recorder(event) => { let mut interaction = @@ -337,35 +341,38 @@ impl Tester

{ Task::none() } Tick::Emulator(event) => { - let State::Playing { - emulator, - current, - outcome, - } = &mut self.state - else { - return Task::none(); - }; - - match event { - emulator::Event::Action(action) => { - emulator.perform(program, action); - } - emulator::Event::Failed => { - *outcome = Outcome::Failed; - } - emulator::Event::Ready => { - *current += 1; - - if let Some(instruction) = - self.instructions.get(*current - 1).cloned() - { - emulator.run(program, instruction); - } - - if *current >= self.instructions.len() { - *outcome = Outcome::Success; + match &mut self.state { + State::Recording { emulator } => { + if let emulator::Event::Action(action) = event { + emulator.perform(program, action); } } + State::Playing { + emulator, + current, + outcome, + } => match event { + emulator::Event::Action(action) => { + emulator.perform(program, action); + } + emulator::Event::Failed => { + *outcome = Outcome::Failed; + } + emulator::Event::Ready => { + *current += 1; + + if let Some(instruction) = + self.instructions.get(*current - 1).cloned() + { + emulator.run(program, instruction); + } + + if *current >= self.instructions.len() { + *outcome = Outcome::Success; + } + } + }, + State::Idle | State::Ready { .. } => {} } Task::none() @@ -373,21 +380,9 @@ impl Tester

{ } } - pub fn subscription(&self, program: &P) -> Subscription> { - match &self.state { - State::Idle | State::Playing { .. } | State::Ready { .. } => { - Subscription::none() - } - State::Recording { state } => { - program.subscription(state).map(Tick::Program) - } - } - } - pub fn view<'a, T: 'static>( &'a self, program: &P, - window: window::Id, current: impl FnOnce() -> Element<'a, T, Theme, P::Renderer>, emulate: impl Fn(Tick

) -> T + 'a, ) -> Element<'a, T, Theme, P::Renderer> { @@ -435,10 +430,9 @@ impl Tester

{ scrollable( container(match &self.state { State::Idle => current(), - State::Recording { state } => { - let theme = program.theme(state, window); - let view = - program.view(state, window).map(Tick::Program); + State::Recording { emulator } => { + let theme = emulator.theme(program); + let view = emulator.view(program).map(Tick::Program); Element::from( recorder(themer(theme, view)) @@ -446,10 +440,10 @@ impl Tester

{ ) .map(emulate) } - State::Ready { state } => { - let theme = program.theme(state, window); + State::Ready { state, window } => { + let theme = program.theme(state, *window); let view = - program.view(state, window).map(Tick::Program); + program.view(state, *window).map(Tick::Program); Element::from(themer(theme, view)).map(emulate) } diff --git a/test/src/emulator.rs b/test/src/emulator.rs index a1465a4f..89e0bd87 100644 --- a/test/src/emulator.rs +++ b/test/src/emulator.rs @@ -3,8 +3,7 @@ use crate::core; use crate::core::mouse; use crate::core::renderer; use crate::core::widget; -use crate::core::window; -use crate::core::{Element, Size}; +use crate::core::{Element, Point, Size}; use crate::instruction; use crate::program; use crate::program::Program; @@ -15,6 +14,7 @@ use crate::runtime::futures::subscription; use crate::runtime::futures::{Executor, Runtime}; use crate::runtime::task; use crate::runtime::user_interface; +use crate::runtime::window; use crate::runtime::{Action, Task, UserInterface}; use std::fmt; @@ -26,7 +26,7 @@ pub struct Emulator { renderer: P::Renderer, mode: Mode, size: Size, - window: window::Id, + window: core::window::Id, cursor: mouse::Cursor, clipboard: Clipboard, cache: Option, @@ -87,7 +87,7 @@ impl Emulator

{ size, clipboard: Clipboard { content: None }, cursor: mouse::Cursor::Unavailable, - window: window::Id::unique(), + window: core::window::Id::unique(), cache: Some(user_interface::Cache::default()), }; @@ -143,9 +143,50 @@ impl Emulator

{ // TODO dbg!(action); } - Action::Window(_action) => { - // TODO - } + Action::Window(action) => match action { + window::Action::Open(_settings, sender) => { + self.window = core::window::Id::unique(); + + let _ = sender.send(self.window); + } + window::Action::GetOldest(sender) + | window::Action::GetLatest(sender) => { + let _ = sender.send(Some(self.window)); + } + window::Action::GetSize(id, sender) => { + if id == self.window { + let _ = sender.send(self.size); + } + } + window::Action::GetMaximized(id, sender) => { + if id == self.window { + let _ = sender.send(false); + } + } + window::Action::GetMinimized(id, sender) => { + if id == self.window { + let _ = sender.send(None); + } + } + window::Action::GetPosition(id, sender) => { + if id == self.window { + let _ = sender.send(Some(Point::ORIGIN)); + } + } + window::Action::GetScaleFactor(id, sender) => { + if id == self.window { + let _ = sender.send(1.0); + } + } + window::Action::GetMode(id, sender) => { + if id == self.window { + let _ = sender.send(core::window::Mode::Windowed); + } + } + _ => { + // Ignored + } + }, Action::System(action) => { // TODO dbg!(action); @@ -265,6 +306,10 @@ impl Emulator

{ pub fn theme(&self, program: &P) -> P::Theme { program.theme(&self.state, self.window) } + + pub fn into_state(self) -> (P::State, core::window::Id) { + (self.state, self.window) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]