aw-lights/common/src/pattern.rs

248 lines
7.6 KiB
Rust
Raw Normal View History

2021-08-06 23:27:41 -04:00
use crate::color::Rgb;
2021-08-15 13:43:27 -04:00
use serde::{Deserialize, Serialize};
2021-07-31 14:29:21 -04:00
2021-08-01 19:38:17 -04:00
pub mod collide;
pub mod fade;
2021-08-15 14:18:18 -04:00
pub mod flashing;
2021-08-01 19:38:17 -04:00
pub mod moving_pixel;
pub mod moving_rainbow;
pub mod orb;
2022-11-17 15:58:11 -05:00
pub mod slide;
2021-08-01 19:38:17 -04:00
pub mod solid;
2022-11-17 16:23:26 -05:00
pub mod visualizer;
2021-08-21 14:02:08 -04:00
pub use collide::{Collide, CollideParams};
pub use fade::{Fade, FadeParams};
pub use flashing::{Flashing, FlashingParams};
pub use moving_pixel::{MovingPixel, MovingPixelParams};
pub use moving_rainbow::{MovingRainbow, MovingRainbowParams};
pub use orb::{Orb, OrbParams};
2022-11-17 15:58:11 -05:00
pub use slide::{Slide, SlideParams};
2021-08-21 14:02:08 -04:00
pub use solid::{Solid, SolidParams};
2022-11-17 16:23:26 -05:00
pub use visualizer::{Visualizer, VisualizerParams};
2021-08-21 14:02:08 -04:00
pub type ColorIterator<'a> = Box<dyn Iterator<Item = &'a Rgb> + 'a>;
2021-10-12 17:11:44 -04:00
pub type PatternResult<T> = Result<T, PatternError>;
#[derive(Debug)]
pub enum PatternError {
ArithmeticError,
Index,
LightCount,
2022-11-21 11:48:45 -05:00
CommandNotFound(String),
IoError(std::io::Error),
InternalError,
2021-10-12 17:11:44 -04:00
}
2022-11-21 11:48:45 -05:00
impl From<std::io::Error> for PatternError {
fn from(e: std::io::Error) -> Self {
Self::IoError(e)
}
}
2021-08-21 14:02:08 -04:00
pub trait FormRender {
fn render(&self) -> String;
}
2022-11-17 15:58:11 -05:00
2021-08-21 14:02:08 -04:00
pub trait InputRender {
2021-08-22 14:17:59 -04:00
fn render(&self, name: &str, multi_index: Option<usize>) -> String;
2021-08-21 14:02:08 -04:00
}
impl InputRender for bool {
2021-08-22 14:17:59 -04:00
fn render(&self, name: &str, multi_index: Option<usize>) -> String {
2021-08-21 14:02:08 -04:00
format!(
2021-08-22 14:17:59 -04:00
r#"<label for="{name}">{name}</label><input type="checkbox" name="{name}" {}{}/>"#,
2021-08-21 14:02:08 -04:00
if *self { " checked" } else { "" },
2021-08-22 14:17:59 -04:00
if let Some(i) = multi_index {
2022-12-29 13:38:12 -05:00
format!(r#" name="{name}-{i}" rust-form-multi="{name}""#)
2021-08-22 14:17:59 -04:00
} else {
2022-12-29 13:38:12 -05:00
format!(r#" name="{name}""#)
2021-08-22 14:17:59 -04:00
},
name = name
2021-08-21 14:02:08 -04:00
)
}
}
impl InputRender for Rgb {
2021-08-22 14:17:59 -04:00
fn render(&self, name: &str, multi_index: Option<usize>) -> String {
2021-08-21 14:02:08 -04:00
format!(
2021-08-22 14:17:59 -04:00
r#"<label for="{name}">{name}</label><input type="color" value="{}" name="{name}" {}/>"#,
2021-08-21 14:02:08 -04:00
self.to_hex_str(),
2021-08-22 14:17:59 -04:00
if let Some(i) = multi_index {
2022-12-29 13:38:12 -05:00
format!(r#" name="{name}-{i}" rust-form-multi="{name}""#)
2021-08-22 14:17:59 -04:00
} else {
2022-12-29 13:38:12 -05:00
format!(r#" name="{name}""#)
2021-08-22 14:17:59 -04:00
},
name = name
2021-08-21 14:02:08 -04:00
)
}
}
impl InputRender for Vec<Rgb> {
2021-08-22 14:17:59 -04:00
fn render(&self, name: &str, _multi_index: Option<usize>) -> String {
2021-08-21 14:02:08 -04:00
self.iter()
2021-10-10 11:43:30 -04:00
// .chain(iter::once(&Rgb::default()))
2021-08-21 14:02:08 -04:00
.enumerate()
.fold(String::new(), |acc, (i, c)| {
2021-08-22 14:17:59 -04:00
acc + &c.render(name, Some(i)) + "\n"
2021-08-21 14:02:08 -04:00
})
}
}
impl InputRender for u8 {
2021-08-22 14:17:59 -04:00
fn render(&self, name: &str, multi_index: Option<usize>) -> String {
2021-08-21 14:02:08 -04:00
format!(
2021-08-22 14:17:59 -04:00
r#"<label for="{name}">{name}</label><input type="number" max="255" min="0" step="1" value="{}" name="{name}" {}/>"#,
2021-08-21 15:24:21 -04:00
self,
2021-08-22 14:17:59 -04:00
if let Some(i) = multi_index {
2022-12-29 13:38:12 -05:00
format!(r#" name="{name}-{i}" rust-form-multi="{name}""#)
2021-08-22 14:17:59 -04:00
} else {
2022-12-29 13:38:12 -05:00
format!(r#" name="{name}""#)
2021-08-22 14:17:59 -04:00
},
name = name
2021-08-21 14:02:08 -04:00
)
}
}
2021-07-31 14:29:21 -04:00
2021-08-21 15:24:21 -04:00
impl InputRender for u16 {
2021-08-22 14:17:59 -04:00
fn render(&self, name: &str, multi_index: Option<usize>) -> String {
2021-08-21 15:24:21 -04:00
format!(
2021-08-22 14:17:59 -04:00
r#"<label for="{name}">{name}</label><input type="number" max="65535" min="0" step="1" value="{}" name="{name}" {}/>"#,
2021-08-21 15:24:21 -04:00
self,
2021-08-22 14:17:59 -04:00
if let Some(i) = multi_index {
2022-12-29 13:38:12 -05:00
format!(r#" name="{name}-{i}" rust-form-multi="{name}""#)
2021-08-22 14:17:59 -04:00
} else {
2022-12-29 13:38:12 -05:00
format!(r#" name="{name}""#)
2021-08-22 14:17:59 -04:00
},
name = name
2021-08-21 15:24:21 -04:00
)
}
}
2023-05-28 17:43:07 -04:00
#[derive(Serialize, Deserialize, Clone, Debug, strum::Display)]
pub enum Parameters {
2021-08-21 14:02:08 -04:00
Collide(CollideParams),
2022-11-17 15:58:11 -05:00
Slide(SlideParams),
2021-08-21 14:02:08 -04:00
Fade(FadeParams),
MovingPixel(MovingPixelParams),
MovingRainbow(MovingRainbowParams),
Orb(OrbParams),
Solid(SolidParams),
2022-11-17 16:23:26 -05:00
Visualizer(VisualizerParams),
2021-08-21 14:02:08 -04:00
Flashing(FlashingParams),
2021-08-10 17:44:03 -04:00
}
2021-08-21 15:24:21 -04:00
impl Default for Parameters {
fn default() -> Self {
2023-02-20 16:08:51 -05:00
Self::Visualizer(VisualizerParams::default())
2021-08-21 15:24:21 -04:00
}
}
impl FormRender for Parameters {
fn render(&self) -> String {
match self {
Self::Collide(ref p) => p.render(),
2022-11-17 15:58:11 -05:00
Self::Slide(ref p) => p.render(),
2021-08-21 15:24:21 -04:00
Self::Fade(ref p) => p.render(),
Self::MovingPixel(ref p) => p.render(),
Self::MovingRainbow(ref p) => p.render(),
Self::Orb(ref p) => p.render(),
Self::Solid(ref p) => p.render(),
2022-11-17 16:23:26 -05:00
Self::Visualizer(ref p) => p.render(),
2021-08-21 15:24:21 -04:00
Self::Flashing(ref p) => p.render(),
}
}
}
impl Parameters {
2021-08-21 15:24:21 -04:00
pub fn default_with_name(name: &str) -> Option<Self> {
match name {
"Collide" => Some(Self::Collide(CollideParams::default())),
2022-11-17 15:58:11 -05:00
"Slide" => Some(Self::Slide(SlideParams::default())),
2021-08-21 15:24:21 -04:00
"Fade" => Some(Self::Fade(FadeParams::default())),
"MovingPixel" => Some(Self::MovingPixel(MovingPixelParams::default())),
"MovingRainbow" => Some(Self::MovingRainbow(MovingRainbowParams::default())),
"Orb" => Some(Self::Orb(OrbParams::default())),
"Solid" => Some(Self::Solid(SolidParams::default())),
2022-11-17 16:23:26 -05:00
"Visualizer" => Some(Self::Visualizer(VisualizerParams::default())),
2021-08-21 15:24:21 -04:00
"Flashing" => Some(Self::Flashing(FlashingParams::default())),
_ => None,
}
}
2022-11-17 15:58:11 -05:00
2021-08-21 15:24:21 -04:00
pub const fn get_names() -> &'static [&'static str] {
&[
"Solid",
2022-11-17 16:23:26 -05:00
"Visualizer",
2021-08-21 15:24:21 -04:00
"Collide",
2022-11-17 15:58:11 -05:00
"Slide",
2021-08-21 15:24:21 -04:00
"Fade",
"MovingPixel",
"MovingRainbow",
"Orb",
"Flashing",
]
}
2022-11-17 15:58:11 -05:00
2021-10-10 19:10:30 -04:00
pub fn to_pattern(&self) -> Box<dyn Pattern + Send + Sync> {
2021-08-10 17:44:03 -04:00
match self {
2021-08-21 14:02:08 -04:00
Self::Collide(ref p) => Box::new(Collide::new(p)),
2022-11-17 15:58:11 -05:00
Self::Slide(ref p) => Box::new(Slide::new(p)),
2021-08-21 14:02:08 -04:00
Self::Fade(ref p) => Box::new(Fade::new(p)),
Self::MovingPixel(ref p) => Box::new(MovingPixel::new(p)),
Self::MovingRainbow(ref p) => Box::new(MovingRainbow::new(p)),
Self::Orb(ref p) => Box::new(Orb::new(p)),
Self::Solid(ref p) => Box::new(Solid::new(p)),
2022-11-17 16:23:26 -05:00
Self::Visualizer(ref p) => Box::new(Visualizer::new(p)),
2021-08-21 14:02:08 -04:00
Self::Flashing(ref p) => Box::new(Flashing::new(p)),
2021-08-10 17:44:03 -04:00
}
}
2021-08-09 23:13:38 -04:00
}
2021-08-10 17:44:03 -04:00
pub trait Pattern: std::fmt::Debug + Send + Sync {
2021-10-12 17:11:44 -04:00
fn init(&mut self, num_lights: u16) -> PatternResult<()>;
fn step(&mut self) -> PatternResult<bool>;
2022-11-22 21:08:59 -05:00
fn get_strip(&self) -> ColorIterator;
fn cleanup(&mut self) -> PatternResult<()> {
Ok(())
}
2021-07-31 14:29:21 -04:00
}
2021-08-01 19:38:17 -04:00
// #[cfg(test)]
// mod tests {
// use super::*;
// const NUM_LIGHTS: u16 = 10;
2021-08-06 23:27:41 -04:00
// fn test_strip() -> Vec<Rgb> {
2021-08-01 19:38:17 -04:00
// vec![color::BLACK; NUM_LIGHTS.into()]
// }
// #[test]
// fn moving_pixel() {
2021-08-06 23:27:41 -04:00
// let color = Rgb(123, 152, 89);
2021-08-01 19:38:17 -04:00
// let mut pat = MovingPixel::new(color.clone());
// let mut strip = test_strip();
// assert!(pat.init(&mut strip, NUM_LIGHTS).is_ok());
// // One is my color
// assert_eq!(strip.iter().filter(|c| **c == color).count(), 1);
// // The rest are off
// assert_eq!(
// strip.iter().filter(|c| **c == color::BLACK).count(),
// (NUM_LIGHTS - 1).into()
// );
// pat.step(&mut strip);
// // One is my color
// assert_eq!(strip.iter().filter(|c| **c == color).count(), 1);
// // The rest are off
// assert_eq!(
// strip.iter().filter(|c| **c == color::BLACK).count(),
// (NUM_LIGHTS - 1).into()
// );
// }
// #[test]
// fn solid() {}
// #[test]
// fn moving_rainbow() {}
// #[test]
// fn fade() {}
// #[test]
// fn collide() {}
// }