Make tester work with daemon (only 1 window for now!)
This commit is contained in:
parent
1deb87694d
commit
f3a4e44314
3 changed files with 113 additions and 84 deletions
|
|
@ -361,7 +361,7 @@ where
|
||||||
|
|
||||||
match &self.mode {
|
match &self.mode {
|
||||||
Mode::Open { tester } => {
|
Mode::Open { tester } => {
|
||||||
tester.view(program, window, view, Event::Tester)
|
tester.view(program, view, Event::Tester)
|
||||||
}
|
}
|
||||||
_ => view(),
|
_ => view(),
|
||||||
}
|
}
|
||||||
|
|
@ -444,19 +444,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscription(&self, program: &P) -> Subscription<Event<P>> {
|
pub fn subscription(&self, program: &P) -> Subscription<Event<P>> {
|
||||||
let subscription = match &self.mode {
|
let subscription =
|
||||||
Mode::Open { tester } if !tester.is_idle() => {
|
program.subscription(&self.state).map(Event::Program);
|
||||||
tester.subscription(program).map(Event::Tester)
|
debug::subscriptions_tracked(subscription.units());
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let subscription =
|
|
||||||
program.subscription(&self.state).map(Event::Program);
|
|
||||||
|
|
||||||
debug::subscriptions_tracked(subscription.units());
|
|
||||||
|
|
||||||
subscription
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let hotkeys =
|
let hotkeys =
|
||||||
futures::keyboard::on_key_press(|key, _modifiers| match key {
|
futures::keyboard::on_key_press(|key, _modifiers| match key {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ use crate::core::border;
|
||||||
use crate::core::window;
|
use crate::core::window;
|
||||||
use crate::core::{Element, Event, Font, Size, Theme};
|
use crate::core::{Element, Event, Font, Size, Theme};
|
||||||
use crate::executor;
|
use crate::executor;
|
||||||
use crate::futures::Subscription;
|
|
||||||
use crate::futures::futures::channel::mpsc;
|
use crate::futures::futures::channel::mpsc;
|
||||||
use crate::icon;
|
use crate::icon;
|
||||||
use crate::program;
|
use crate::program;
|
||||||
|
|
@ -36,10 +35,11 @@ pub struct Tester<P: Program> {
|
||||||
enum State<P: Program> {
|
enum State<P: Program> {
|
||||||
Idle,
|
Idle,
|
||||||
Recording {
|
Recording {
|
||||||
state: P::State,
|
emulator: Emulator<P>,
|
||||||
},
|
},
|
||||||
Ready {
|
Ready {
|
||||||
state: P::State,
|
state: P::State,
|
||||||
|
window: window::Id,
|
||||||
},
|
},
|
||||||
Playing {
|
Playing {
|
||||||
emulator: Emulator<P>,
|
emulator: Emulator<P>,
|
||||||
|
|
@ -98,10 +98,6 @@ impl<P: Program + 'static> Tester<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_idle(&self) -> bool {
|
|
||||||
matches!(self.state, State::Idle)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_busy(&self) -> bool {
|
pub fn is_busy(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self.state,
|
self.state,
|
||||||
|
|
@ -134,24 +130,30 @@ impl<P: Program + 'static> Tester<P> {
|
||||||
self.edit = None;
|
self.edit = None;
|
||||||
self.instructions.clear();
|
self.instructions.clear();
|
||||||
|
|
||||||
let (state, task) = if let Some(preset) = self.preset(program) {
|
let (sender, receiver) = mpsc::channel(1);
|
||||||
preset.boot()
|
|
||||||
} else {
|
|
||||||
program.boot()
|
|
||||||
};
|
|
||||||
|
|
||||||
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 => {
|
Message::Stop => {
|
||||||
let State::Recording { state } =
|
let State::Recording { emulator } =
|
||||||
std::mem::replace(&mut self.state, State::Idle)
|
std::mem::replace(&mut self.state, State::Idle)
|
||||||
else {
|
else {
|
||||||
return Task::none();
|
return Task::none();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.state = State::Ready { state };
|
let (state, window) = emulator.into_state();
|
||||||
|
|
||||||
|
self.state = State::Ready { state, window };
|
||||||
|
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -301,11 +303,13 @@ impl<P: Program + 'static> Tester<P> {
|
||||||
match tick {
|
match tick {
|
||||||
Tick::Tester(message) => self.update(program, message),
|
Tick::Tester(message) => self.update(program, message),
|
||||||
Tick::Program(message) => {
|
Tick::Program(message) => {
|
||||||
let State::Recording { state } = &mut self.state else {
|
let State::Recording { emulator } = &mut self.state else {
|
||||||
return Task::none();
|
return Task::none();
|
||||||
};
|
};
|
||||||
|
|
||||||
program.update(state, message).map(Tick::Program)
|
emulator.update(program, message);
|
||||||
|
|
||||||
|
Task::none()
|
||||||
}
|
}
|
||||||
Tick::Recorder(event) => {
|
Tick::Recorder(event) => {
|
||||||
let mut interaction =
|
let mut interaction =
|
||||||
|
|
@ -337,35 +341,38 @@ impl<P: Program + 'static> Tester<P> {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Tick::Emulator(event) => {
|
Tick::Emulator(event) => {
|
||||||
let State::Playing {
|
match &mut self.state {
|
||||||
emulator,
|
State::Recording { emulator } => {
|
||||||
current,
|
if let emulator::Event::Action(action) = event {
|
||||||
outcome,
|
emulator.perform(program, action);
|
||||||
} = &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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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()
|
Task::none()
|
||||||
|
|
@ -373,21 +380,9 @@ impl<P: Program + 'static> Tester<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscription(&self, program: &P) -> Subscription<Tick<P>> {
|
|
||||||
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>(
|
pub fn view<'a, T: 'static>(
|
||||||
&'a self,
|
&'a self,
|
||||||
program: &P,
|
program: &P,
|
||||||
window: window::Id,
|
|
||||||
current: impl FnOnce() -> Element<'a, T, Theme, P::Renderer>,
|
current: impl FnOnce() -> Element<'a, T, Theme, P::Renderer>,
|
||||||
emulate: impl Fn(Tick<P>) -> T + 'a,
|
emulate: impl Fn(Tick<P>) -> T + 'a,
|
||||||
) -> Element<'a, T, Theme, P::Renderer> {
|
) -> Element<'a, T, Theme, P::Renderer> {
|
||||||
|
|
@ -435,10 +430,9 @@ impl<P: Program + 'static> Tester<P> {
|
||||||
scrollable(
|
scrollable(
|
||||||
container(match &self.state {
|
container(match &self.state {
|
||||||
State::Idle => current(),
|
State::Idle => current(),
|
||||||
State::Recording { state } => {
|
State::Recording { emulator } => {
|
||||||
let theme = program.theme(state, window);
|
let theme = emulator.theme(program);
|
||||||
let view =
|
let view = emulator.view(program).map(Tick::Program);
|
||||||
program.view(state, window).map(Tick::Program);
|
|
||||||
|
|
||||||
Element::from(
|
Element::from(
|
||||||
recorder(themer(theme, view))
|
recorder(themer(theme, view))
|
||||||
|
|
@ -446,10 +440,10 @@ impl<P: Program + 'static> Tester<P> {
|
||||||
)
|
)
|
||||||
.map(emulate)
|
.map(emulate)
|
||||||
}
|
}
|
||||||
State::Ready { state } => {
|
State::Ready { state, window } => {
|
||||||
let theme = program.theme(state, window);
|
let theme = program.theme(state, *window);
|
||||||
let view =
|
let view =
|
||||||
program.view(state, window).map(Tick::Program);
|
program.view(state, *window).map(Tick::Program);
|
||||||
|
|
||||||
Element::from(themer(theme, view)).map(emulate)
|
Element::from(themer(theme, view)).map(emulate)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ use crate::core;
|
||||||
use crate::core::mouse;
|
use crate::core::mouse;
|
||||||
use crate::core::renderer;
|
use crate::core::renderer;
|
||||||
use crate::core::widget;
|
use crate::core::widget;
|
||||||
use crate::core::window;
|
use crate::core::{Element, Point, Size};
|
||||||
use crate::core::{Element, Size};
|
|
||||||
use crate::instruction;
|
use crate::instruction;
|
||||||
use crate::program;
|
use crate::program;
|
||||||
use crate::program::Program;
|
use crate::program::Program;
|
||||||
|
|
@ -15,6 +14,7 @@ use crate::runtime::futures::subscription;
|
||||||
use crate::runtime::futures::{Executor, Runtime};
|
use crate::runtime::futures::{Executor, Runtime};
|
||||||
use crate::runtime::task;
|
use crate::runtime::task;
|
||||||
use crate::runtime::user_interface;
|
use crate::runtime::user_interface;
|
||||||
|
use crate::runtime::window;
|
||||||
use crate::runtime::{Action, Task, UserInterface};
|
use crate::runtime::{Action, Task, UserInterface};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
@ -26,7 +26,7 @@ pub struct Emulator<P: Program> {
|
||||||
renderer: P::Renderer,
|
renderer: P::Renderer,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
size: Size,
|
size: Size,
|
||||||
window: window::Id,
|
window: core::window::Id,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
clipboard: Clipboard,
|
clipboard: Clipboard,
|
||||||
cache: Option<user_interface::Cache>,
|
cache: Option<user_interface::Cache>,
|
||||||
|
|
@ -87,7 +87,7 @@ impl<P: Program + 'static> Emulator<P> {
|
||||||
size,
|
size,
|
||||||
clipboard: Clipboard { content: None },
|
clipboard: Clipboard { content: None },
|
||||||
cursor: mouse::Cursor::Unavailable,
|
cursor: mouse::Cursor::Unavailable,
|
||||||
window: window::Id::unique(),
|
window: core::window::Id::unique(),
|
||||||
cache: Some(user_interface::Cache::default()),
|
cache: Some(user_interface::Cache::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -143,9 +143,50 @@ impl<P: Program + 'static> Emulator<P> {
|
||||||
// TODO
|
// TODO
|
||||||
dbg!(action);
|
dbg!(action);
|
||||||
}
|
}
|
||||||
Action::Window(_action) => {
|
Action::Window(action) => match action {
|
||||||
// TODO
|
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) => {
|
Action::System(action) => {
|
||||||
// TODO
|
// TODO
|
||||||
dbg!(action);
|
dbg!(action);
|
||||||
|
|
@ -265,6 +306,10 @@ impl<P: Program + 'static> Emulator<P> {
|
||||||
pub fn theme(&self, program: &P) -> P::Theme {
|
pub fn theme(&self, program: &P) -> P::Theme {
|
||||||
program.theme(&self.state, self.window)
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue