Add Failed and Success states to tester devtool
This commit is contained in:
parent
73f5569f28
commit
e548372fe0
7 changed files with 198 additions and 53 deletions
37
Cargo.lock
generated
37
Cargo.lock
generated
|
|
@ -117,9 +117,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
|
|
@ -2342,9 +2342,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8"
|
||||
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
|
|
@ -4613,9 +4613,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "read-fonts"
|
||||
version = "0.29.2"
|
||||
version = "0.29.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f96bfbb7df43d34a2b7b8582fcbcb676ba02a763265cb90bc8aabfd62b57d64"
|
||||
checksum = "04ca636dac446b5664bd16c069c00a9621806895b8bb02c2dc68542b23b8f25d"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"font-types",
|
||||
|
|
@ -5950,9 +5950,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.5"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2"
|
||||
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"bytes",
|
||||
|
|
@ -6938,13 +6938,13 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
|||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.4.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
||||
checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-result 0.3.4",
|
||||
"windows-strings 0.3.1",
|
||||
"windows-targets 0.53.0",
|
||||
"windows-strings 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6984,15 +6984,6 @@ dependencies = [
|
|||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.2"
|
||||
|
|
@ -7642,9 +7633,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.4.14"
|
||||
version = "0.4.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
|
||||
checksum = "3e4a518c0ea2576f4da876349d7f67a7be489297cd77c2cf9e04c2e05fcd3974"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ module = "icon"
|
|||
[glyphs]
|
||||
play = "entypo-play"
|
||||
stop = "entypo-stop"
|
||||
pause = "entypo-pause"
|
||||
record = "entypo-record"
|
||||
import = "entypo-folder"
|
||||
export = "entypo-floppy"
|
||||
lightbulb = "fontawesome-lightbulb"
|
||||
check = "entypo-check"
|
||||
cancel = "entypo-cancel"
|
||||
folder = "entypo-folder"
|
||||
floppy = "entypo-floppy"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -5,6 +5,54 @@ use crate::widget::{Text, text};
|
|||
|
||||
pub const FONT: &[u8] = include_bytes!("../fonts/iced_devtools-icons.ttf");
|
||||
|
||||
pub fn cancel<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: program::Renderer,
|
||||
{
|
||||
icon("\u{2715}")
|
||||
}
|
||||
|
||||
pub fn check<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: program::Renderer,
|
||||
{
|
||||
icon("\u{2713}")
|
||||
}
|
||||
|
||||
pub fn floppy<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: program::Renderer,
|
||||
{
|
||||
icon("\u{1F4BE}")
|
||||
}
|
||||
|
||||
pub fn folder<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: program::Renderer,
|
||||
{
|
||||
icon("\u{1F4C1}")
|
||||
}
|
||||
|
||||
pub fn lightbulb<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: program::Renderer,
|
||||
{
|
||||
icon("\u{F0EB}")
|
||||
}
|
||||
|
||||
pub fn pause<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: program::Renderer,
|
||||
{
|
||||
icon("\u{2389}")
|
||||
}
|
||||
|
||||
pub fn play<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
|
|
@ -29,6 +77,14 @@ where
|
|||
icon("\u{25A0}")
|
||||
}
|
||||
|
||||
pub fn tape<'a, Theme, Renderer>() -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: program::Renderer,
|
||||
{
|
||||
icon("\u{2707}")
|
||||
}
|
||||
|
||||
fn icon<'a, Theme, Renderer>(codepoint: &'a str) -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
|
|
|
|||
|
|
@ -36,12 +36,22 @@ enum State<P: Program> {
|
|||
Recording {
|
||||
state: P::State,
|
||||
},
|
||||
Ready {
|
||||
state: P::State,
|
||||
},
|
||||
Playing {
|
||||
emulator: Emulator<P>,
|
||||
current: usize,
|
||||
outcome: Outcome,
|
||||
},
|
||||
}
|
||||
|
||||
enum Outcome {
|
||||
Running,
|
||||
Failed,
|
||||
Success,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
ChangeViewport(Size),
|
||||
|
|
@ -83,7 +93,14 @@ impl<P: Program + 'static> Tester<P> {
|
|||
}
|
||||
|
||||
pub fn is_busy(&self) -> bool {
|
||||
matches!(self.state, State::Recording { .. } | State::Playing { .. })
|
||||
matches!(
|
||||
self.state,
|
||||
State::Recording { .. }
|
||||
| State::Playing {
|
||||
outcome: Outcome::Running,
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn update(&mut self, program: &P, message: Message) -> Task<Tick<P>> {
|
||||
|
|
@ -117,7 +134,13 @@ impl<P: Program + 'static> Tester<P> {
|
|||
task.map(Tick::Program)
|
||||
}
|
||||
Message::Stop => {
|
||||
self.state = State::Idle;
|
||||
let State::Recording { state } =
|
||||
std::mem::replace(&mut self.state, State::Idle)
|
||||
else {
|
||||
return Task::none();
|
||||
};
|
||||
|
||||
self.state = State::Ready { state };
|
||||
|
||||
Task::none()
|
||||
}
|
||||
|
|
@ -135,6 +158,7 @@ impl<P: Program + 'static> Tester<P> {
|
|||
self.state = State::Playing {
|
||||
emulator,
|
||||
current: 0,
|
||||
outcome: Outcome::Running,
|
||||
};
|
||||
|
||||
Task::run(receiver, Tick::Emulator)
|
||||
|
|
@ -190,7 +214,11 @@ impl<P: Program + 'static> Tester<P> {
|
|||
Task::none()
|
||||
}
|
||||
Tick::Emulator(event) => {
|
||||
let State::Playing { emulator, current } = &mut self.state
|
||||
let State::Playing {
|
||||
emulator,
|
||||
current,
|
||||
outcome,
|
||||
} = &mut self.state
|
||||
else {
|
||||
return Task::none();
|
||||
};
|
||||
|
|
@ -199,6 +227,9 @@ impl<P: Program + 'static> Tester<P> {
|
|||
emulator::Event::Action(action) => {
|
||||
emulator.perform(program, action);
|
||||
}
|
||||
emulator::Event::Failed => {
|
||||
*outcome = Outcome::Failed;
|
||||
}
|
||||
emulator::Event::Ready => {
|
||||
if let Some(instruction) =
|
||||
self.instructions.get(*current).cloned()
|
||||
|
|
@ -206,6 +237,10 @@ impl<P: Program + 'static> Tester<P> {
|
|||
emulator.run(program, instruction);
|
||||
*current += 1;
|
||||
}
|
||||
|
||||
if *current >= self.instructions.len() {
|
||||
*outcome = Outcome::Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,7 +251,9 @@ impl<P: Program + 'static> Tester<P> {
|
|||
|
||||
pub fn subscription(&self, program: &P) -> Subscription<Tick<P>> {
|
||||
match &self.state {
|
||||
State::Idle | State::Playing { .. } => Subscription::none(),
|
||||
State::Idle | State::Playing { .. } | State::Ready { .. } => {
|
||||
Subscription::none()
|
||||
}
|
||||
State::Recording { state } => {
|
||||
program.subscription(state).map(Tick::Program)
|
||||
}
|
||||
|
|
@ -230,22 +267,44 @@ impl<P: Program + 'static> Tester<P> {
|
|||
current: impl FnOnce() -> Element<'a, T, Theme, P::Renderer>,
|
||||
emulate: impl Fn(Tick<P>) -> T + 'a,
|
||||
) -> Element<'a, T, Theme, P::Renderer> {
|
||||
let status = match &self.state {
|
||||
State::Idle => monospace("Idle").style(|theme| text::Style {
|
||||
color: Some(
|
||||
theme.extended_palette().background.strongest.color,
|
||||
),
|
||||
}),
|
||||
State::Recording { .. } => {
|
||||
monospace("Recording").style(|theme| text::Style {
|
||||
color: Some(theme.palette().danger),
|
||||
let status = {
|
||||
let (icon, label) = match &self.state {
|
||||
State::Idle => (text(""), "Idle"),
|
||||
State::Recording { .. } => (icon::record(), "Recording"),
|
||||
State::Ready { .. } => (icon::lightbulb(), "Ready"),
|
||||
State::Playing { outcome, .. } => match outcome {
|
||||
Outcome::Running => (icon::play(), "Playing"),
|
||||
Outcome::Failed => (icon::cancel(), "Failed"),
|
||||
Outcome::Success => (icon::check(), "Success"),
|
||||
},
|
||||
};
|
||||
|
||||
container(row![icon.size(14), label].align_y(Center).spacing(8))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
|
||||
container::Style {
|
||||
text_color: Some(match &self.state {
|
||||
State::Idle => palette.background.strongest.color,
|
||||
State::Recording { .. } => {
|
||||
palette.danger.base.color
|
||||
}
|
||||
State::Ready { .. } => palette.warning.base.color,
|
||||
State::Playing { outcome, .. } => match outcome {
|
||||
Outcome::Running => theme.palette().primary,
|
||||
Outcome::Failed => theme.palette().danger,
|
||||
Outcome::Success => {
|
||||
theme
|
||||
.extended_palette()
|
||||
.success
|
||||
.strong
|
||||
.color
|
||||
}
|
||||
},
|
||||
}),
|
||||
..container::Style::default()
|
||||
}
|
||||
})
|
||||
}
|
||||
State::Playing { .. } => {
|
||||
monospace("Playing").style(|theme| text::Style {
|
||||
color: Some(theme.palette().primary),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let viewport = container(
|
||||
|
|
@ -263,6 +322,13 @@ impl<P: Program + 'static> Tester<P> {
|
|||
)
|
||||
.map(emulate)
|
||||
}
|
||||
State::Ready { state } => {
|
||||
let theme = program.theme(state, window);
|
||||
let view =
|
||||
program.view(state, window).map(Tick::Program);
|
||||
|
||||
Element::from(themer(theme, view)).map(emulate)
|
||||
}
|
||||
State::Playing { emulator, .. } => {
|
||||
let theme = emulator.theme(program);
|
||||
let view = emulator.view(program).map(Tick::Program);
|
||||
|
|
@ -285,7 +351,12 @@ impl<P: Program + 'static> Tester<P> {
|
|||
border: border::width(2.0).color(match &self.state {
|
||||
State::Idle => palette.background.strongest.color,
|
||||
State::Recording { .. } => palette.danger.base.color,
|
||||
State::Playing { .. } => palette.primary.base.color,
|
||||
State::Ready { .. } => palette.warning.weak.color,
|
||||
State::Playing { outcome, .. } => match outcome {
|
||||
Outcome::Running => palette.primary.base.color,
|
||||
Outcome::Failed => palette.danger.strong.color,
|
||||
Outcome::Success => palette.success.strong.color,
|
||||
},
|
||||
}),
|
||||
..container::Style::default()
|
||||
}
|
||||
|
|
@ -305,7 +376,7 @@ impl<P: Program + 'static> Tester<P> {
|
|||
width: width.parse().unwrap_or(self.viewport.width),
|
||||
..self.viewport
|
||||
})),
|
||||
monospace("x"),
|
||||
monospace("x").size(14),
|
||||
text_input("Height", &self.viewport.height.to_string())
|
||||
.size(14)
|
||||
.on_input(|height| Message::ChangeViewport(Size {
|
||||
|
|
@ -318,7 +389,7 @@ impl<P: Program + 'static> Tester<P> {
|
|||
|
||||
let preset = combo_box(
|
||||
&self.presets,
|
||||
"Default Preset",
|
||||
"Default",
|
||||
self.preset.as_ref(),
|
||||
Message::PresetSelected,
|
||||
)
|
||||
|
|
@ -349,9 +420,32 @@ impl<P: Program + 'static> Tester<P> {
|
|||
.size(10)
|
||||
.style(move |theme: &Theme| text::Style {
|
||||
color: match &self.state {
|
||||
State::Playing { current, .. } => {
|
||||
State::Playing {
|
||||
current,
|
||||
outcome,
|
||||
..
|
||||
} => {
|
||||
if *current == i {
|
||||
Some(theme.palette().primary)
|
||||
Some(match outcome {
|
||||
Outcome::Running => {
|
||||
theme.palette().primary
|
||||
}
|
||||
|
||||
Outcome::Failed => {
|
||||
theme
|
||||
.extended_palette()
|
||||
.danger
|
||||
.strong
|
||||
.color
|
||||
}
|
||||
Outcome::Success => {
|
||||
theme
|
||||
.extended_palette()
|
||||
.success
|
||||
.strong
|
||||
.color
|
||||
}
|
||||
})
|
||||
} else if *current > i {
|
||||
Some(
|
||||
theme
|
||||
|
|
@ -394,8 +488,7 @@ impl<P: Program + 'static> Tester<P> {
|
|||
} else {
|
||||
button(icon::record().size(14).width(Fill).center())
|
||||
.on_press_maybe(
|
||||
matches!(self.state, State::Idle)
|
||||
.then_some(Message::Record),
|
||||
(!self.is_busy()).then_some(Message::Record),
|
||||
)
|
||||
.style(button::danger)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -588,10 +588,10 @@ fn presets() -> impl Iterator<Item = iced::application::Preset<Todos, Message>>
|
|||
Command::done(Message::Loaded(Err(LoadError::File))),
|
||||
)
|
||||
}),
|
||||
Preset::new("Basic", || {
|
||||
Preset::new("Carl Sagan", || {
|
||||
(
|
||||
Todos::Loaded(State {
|
||||
input_value: "Bake an apple pie".to_owned(),
|
||||
input_value: "Make an apple pie".to_owned(),
|
||||
filter: Filter::All,
|
||||
tasks: vec![Task {
|
||||
id: Uuid::new_v4(),
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ pub struct Emulator<P: Program> {
|
|||
#[allow(missing_debug_implementations)]
|
||||
pub enum Event<P: Program> {
|
||||
Action(Action<P::Message>),
|
||||
Failed,
|
||||
Ready,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue