Add Zen variant to emulator::Mode 🧘
This commit is contained in:
parent
751714388c
commit
71ee026444
2 changed files with 130 additions and 85 deletions
|
|
@ -6,6 +6,7 @@ use crate::core::{Element, Point, Size};
|
||||||
use crate::instruction;
|
use crate::instruction;
|
||||||
use crate::program;
|
use crate::program;
|
||||||
use crate::program::Program;
|
use crate::program::Program;
|
||||||
|
use crate::runtime;
|
||||||
use crate::runtime::futures::futures::StreamExt;
|
use crate::runtime::futures::futures::StreamExt;
|
||||||
use crate::runtime::futures::futures::channel::mpsc;
|
use crate::runtime::futures::futures::channel::mpsc;
|
||||||
use crate::runtime::futures::futures::stream;
|
use crate::runtime::futures::futures::stream;
|
||||||
|
|
@ -14,7 +15,7 @@ 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::window;
|
||||||
use crate::runtime::{Action, Task, UserInterface};
|
use crate::runtime::{Task, UserInterface};
|
||||||
use crate::selector;
|
use crate::selector;
|
||||||
use crate::{Instruction, Selector};
|
use crate::{Instruction, Selector};
|
||||||
|
|
||||||
|
|
@ -31,15 +32,22 @@ pub struct Emulator<P: Program> {
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
clipboard: Clipboard,
|
clipboard: Clipboard,
|
||||||
cache: Option<user_interface::Cache>,
|
cache: Option<user_interface::Cache>,
|
||||||
|
pending_tasks: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub enum Event<P: Program> {
|
pub enum Event<P: Program> {
|
||||||
Action(Action<P::Message>),
|
Action(Action<P>),
|
||||||
Failed(Instruction),
|
Failed(Instruction),
|
||||||
Ready,
|
Ready,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub enum Action<P: Program> {
|
||||||
|
Runtime(runtime::Action<P::Message>),
|
||||||
|
CountDown,
|
||||||
|
}
|
||||||
|
|
||||||
impl<P: Program + 'static> Emulator<P> {
|
impl<P: Program + 'static> Emulator<P> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
sender: mpsc::Sender<Event<P>>,
|
sender: mpsc::Sender<Event<P>>,
|
||||||
|
|
@ -90,6 +98,7 @@ impl<P: Program + 'static> Emulator<P> {
|
||||||
cursor: mouse::Cursor::Unavailable,
|
cursor: mouse::Cursor::Unavailable,
|
||||||
window: core::window::Id::unique(),
|
window: core::window::Id::unique(),
|
||||||
cache: Some(user_interface::Cache::default()),
|
cache: Some(user_interface::Cache::default()),
|
||||||
|
pending_tasks: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
emulator.wait_for(task);
|
emulator.wait_for(task);
|
||||||
|
|
@ -101,103 +110,119 @@ impl<P: Program + 'static> Emulator<P> {
|
||||||
pub fn update(&mut self, program: &P, message: P::Message) {
|
pub fn update(&mut self, program: &P, message: P::Message) {
|
||||||
let task = program.update(&mut self.state, message);
|
let task = program.update(&mut self.state, message);
|
||||||
|
|
||||||
if let Some(stream) = task::into_stream(task) {
|
match self.mode {
|
||||||
self.runtime.run(stream.map(Event::Action).boxed());
|
Mode::Zen => self.wait_for(task),
|
||||||
|
_ => {
|
||||||
|
if let Some(stream) = task::into_stream(task) {
|
||||||
|
self.runtime.run(
|
||||||
|
stream.map(Action::Runtime).map(Event::Action).boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.resubscribe(program);
|
self.resubscribe(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform(&mut self, program: &P, action: Action<P::Message>) {
|
pub fn perform(&mut self, program: &P, action: Action<P>) {
|
||||||
match action {
|
match action {
|
||||||
Action::Output(message) => {
|
Action::CountDown => {
|
||||||
self.update(program, message);
|
self.pending_tasks -= 1;
|
||||||
|
|
||||||
|
if self.pending_tasks == 0 {
|
||||||
|
self.runtime.send(Event::Ready);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Action::LoadFont { .. } => {
|
Action::Runtime(action) => match action {
|
||||||
// TODO
|
runtime::Action::Output(message) => {
|
||||||
}
|
self.update(program, message);
|
||||||
Action::Widget(operation) => {
|
}
|
||||||
let mut user_interface = UserInterface::build(
|
runtime::Action::LoadFont { .. } => {
|
||||||
program.view(&self.state, self.window),
|
// TODO
|
||||||
self.size,
|
}
|
||||||
self.cache.take().unwrap(),
|
runtime::Action::Widget(operation) => {
|
||||||
&mut self.renderer,
|
let mut user_interface = UserInterface::build(
|
||||||
);
|
program.view(&self.state, self.window),
|
||||||
|
self.size,
|
||||||
|
self.cache.take().unwrap(),
|
||||||
|
&mut self.renderer,
|
||||||
|
);
|
||||||
|
|
||||||
let mut operation = Some(operation);
|
let mut operation = Some(operation);
|
||||||
|
|
||||||
while let Some(mut current) = operation.take() {
|
while let Some(mut current) = operation.take() {
|
||||||
user_interface.operate(&self.renderer, &mut current);
|
user_interface.operate(&self.renderer, &mut current);
|
||||||
|
|
||||||
match current.finish() {
|
match current.finish() {
|
||||||
widget::operation::Outcome::None => {}
|
widget::operation::Outcome::None => {}
|
||||||
widget::operation::Outcome::Some(()) => {}
|
widget::operation::Outcome::Some(()) => {}
|
||||||
widget::operation::Outcome::Chain(next) => {
|
widget::operation::Outcome::Chain(next) => {
|
||||||
operation = Some(next);
|
operation = Some(next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.cache = Some(user_interface.into_cache());
|
self.cache = Some(user_interface.into_cache());
|
||||||
}
|
}
|
||||||
Action::Clipboard(action) => {
|
runtime::Action::Clipboard(action) => {
|
||||||
// TODO
|
// TODO
|
||||||
dbg!(action);
|
dbg!(action);
|
||||||
}
|
}
|
||||||
Action::Window(action) => match action {
|
runtime::Action::Window(action) => match action {
|
||||||
window::Action::Open(id, _settings, sender) => {
|
window::Action::Open(id, _settings, sender) => {
|
||||||
self.window = id;
|
self.window = id;
|
||||||
|
|
||||||
let _ = sender.send(self.window);
|
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::GetOldest(sender)
|
||||||
window::Action::GetMaximized(id, sender) => {
|
| window::Action::GetLatest(sender) => {
|
||||||
if id == self.window {
|
let _ = sender.send(Some(self.window));
|
||||||
let _ = sender.send(false);
|
|
||||||
}
|
}
|
||||||
}
|
window::Action::GetSize(id, sender) => {
|
||||||
window::Action::GetMinimized(id, sender) => {
|
if id == self.window {
|
||||||
if id == self.window {
|
let _ = sender.send(self.size);
|
||||||
let _ = sender.send(None);
|
}
|
||||||
}
|
}
|
||||||
}
|
window::Action::GetMaximized(id, sender) => {
|
||||||
window::Action::GetPosition(id, sender) => {
|
if id == self.window {
|
||||||
if id == self.window {
|
let _ = sender.send(false);
|
||||||
let _ = sender.send(Some(Point::ORIGIN));
|
}
|
||||||
}
|
}
|
||||||
}
|
window::Action::GetMinimized(id, sender) => {
|
||||||
window::Action::GetScaleFactor(id, sender) => {
|
if id == self.window {
|
||||||
if id == self.window {
|
let _ = sender.send(None);
|
||||||
let _ = sender.send(1.0);
|
}
|
||||||
}
|
}
|
||||||
}
|
window::Action::GetPosition(id, sender) => {
|
||||||
window::Action::GetMode(id, sender) => {
|
if id == self.window {
|
||||||
if id == self.window {
|
let _ = sender.send(Some(Point::ORIGIN));
|
||||||
let _ = sender.send(core::window::Mode::Windowed);
|
}
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
runtime::Action::System(action) => {
|
||||||
|
// TODO
|
||||||
|
dbg!(action);
|
||||||
}
|
}
|
||||||
_ => {
|
runtime::Action::Exit => {
|
||||||
// Ignored
|
// TODO
|
||||||
|
}
|
||||||
|
runtime::Action::Reload => {
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Action::System(action) => {
|
|
||||||
// TODO
|
|
||||||
dbg!(action);
|
|
||||||
}
|
|
||||||
Action::Exit => {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
Action::Reload => {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -295,16 +320,32 @@ impl<P: Program + 'static> Emulator<P> {
|
||||||
pub fn wait_for(&mut self, task: Task<P::Message>) {
|
pub fn wait_for(&mut self, task: Task<P::Message>) {
|
||||||
if let Some(stream) = task::into_stream(task) {
|
if let Some(stream) = task::into_stream(task) {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
|
Mode::Zen => {
|
||||||
|
self.pending_tasks += 1;
|
||||||
|
|
||||||
|
self.runtime.run(
|
||||||
|
stream
|
||||||
|
.map(Action::Runtime)
|
||||||
|
.map(Event::Action)
|
||||||
|
.chain(stream::once(async {
|
||||||
|
Event::Action(Action::CountDown)
|
||||||
|
}))
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
Mode::Patient => {
|
Mode::Patient => {
|
||||||
self.runtime.run(
|
self.runtime.run(
|
||||||
stream
|
stream
|
||||||
|
.map(Action::Runtime)
|
||||||
.map(Event::Action)
|
.map(Event::Action)
|
||||||
.chain(stream::once(async { Event::Ready }))
|
.chain(stream::once(async { Event::Ready }))
|
||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Mode::Impatient => {
|
Mode::Impatient => {
|
||||||
self.runtime.run(stream.map(Event::Action).boxed());
|
self.runtime.run(
|
||||||
|
stream.map(Action::Runtime).map(Event::Action).boxed(),
|
||||||
|
);
|
||||||
self.runtime.send(Event::Ready);
|
self.runtime.send(Event::Ready);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -315,9 +356,9 @@ impl<P: Program + 'static> Emulator<P> {
|
||||||
|
|
||||||
pub fn resubscribe(&mut self, program: &P) {
|
pub fn resubscribe(&mut self, program: &P) {
|
||||||
self.runtime.track(subscription::into_recipes(
|
self.runtime.track(subscription::into_recipes(
|
||||||
program
|
program.subscription(&self.state).map(|message| {
|
||||||
.subscription(&self.state)
|
Event::Action(Action::Runtime(runtime::Action::Output(message)))
|
||||||
.map(|message| Event::Action(Action::Output(message))),
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,20 +381,22 @@ impl<P: Program + 'static> Emulator<P> {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
#[default]
|
#[default]
|
||||||
|
Zen,
|
||||||
Patient,
|
Patient,
|
||||||
Impatient,
|
Impatient,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mode {
|
impl Mode {
|
||||||
pub const ALL: &[Self] = &[Self::Patient, Self::Impatient];
|
pub const ALL: &[Self] = &[Self::Zen, Self::Patient, Self::Impatient];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Mode {
|
impl fmt::Display for Mode {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
f.write_str(match self {
|
||||||
Mode::Patient => f.write_str("Patient"),
|
Self::Zen => "Zen",
|
||||||
Mode::Impatient => f.write_str("Impatient"),
|
Self::Patient => "Patient",
|
||||||
}
|
Self::Impatient => "Impatient",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ impl Ice {
|
||||||
}
|
}
|
||||||
"mode" => {
|
"mode" => {
|
||||||
mode = Some(match value.trim().to_lowercase().as_str() {
|
mode = Some(match value.trim().to_lowercase().as_str() {
|
||||||
|
"zen" => emulator::Mode::Zen,
|
||||||
"patient" => emulator::Mode::Patient,
|
"patient" => emulator::Mode::Patient,
|
||||||
"impatient" => emulator::Mode::Impatient,
|
"impatient" => emulator::Mode::Impatient,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -118,6 +119,7 @@ impl std::fmt::Display for Ice {
|
||||||
f,
|
f,
|
||||||
"mode: {}",
|
"mode: {}",
|
||||||
match self.mode {
|
match self.mode {
|
||||||
|
emulator::Mode::Zen => "Zen",
|
||||||
emulator::Mode::Patient => "Patient",
|
emulator::Mode::Patient => "Patient",
|
||||||
emulator::Mode::Impatient => "Impatient",
|
emulator::Mode::Impatient => "Impatient",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue