diff --git a/src/color.rs b/src/color.rs index 5cf32e7..f2bd2e5 100644 --- a/src/color.rs +++ b/src/color.rs @@ -104,6 +104,17 @@ pub fn build_ramp(from_color: Rgb, to_color: Rgb, length: usize) -> Vec { ret } +pub fn min_with_factor(at_least: u16, factor: u16) -> Result { + Ok(at_least + .checked_sub(1) + .ok_or(())? + .div_euclid(factor) + .checked_add(1) + .ok_or(())? + .checked_mul(factor) + .ok_or(())?) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/pattern.rs b/src/pattern.rs index 2ed6fca..3f64837 100644 --- a/src/pattern.rs +++ b/src/pattern.rs @@ -4,12 +4,14 @@ use std::collections::vec_deque; pub mod collide; pub mod fade; +pub mod flashing; pub mod moving_pixel; pub mod moving_rainbow; pub mod orb; pub mod solid; pub use collide::Collide; pub use fade::Fade; +pub use flashing::Flashing; pub use moving_pixel::MovingPixel; pub use moving_rainbow::MovingRainbow; pub use orb::Orb; @@ -23,17 +25,19 @@ pub enum Parameters { MovingRainbow(u8, bool), Orb(Rgb, u8, u8), Solid((Rgb,)), + Flashing(Vec, u8), } impl Parameters { - pub fn to_pattern(&self) -> Box { + pub fn into_pattern(self) -> Box { match self { - Self::Collide(l, r, c) => Box::new(Collide::new(*l, *r, *c)), - Self::Fade((c,)) => Box::new(Fade::new(*c)), - Self::MovingPixel((c,)) => Box::new(MovingPixel::new(*c)), - Self::MovingRainbow(w, f) => Box::new(MovingRainbow::new(*w, *f)), - Self::Orb(c, x, y) => Box::new(Orb::new(*c, *x, *y)), - Self::Solid((c,)) => Box::new(Solid::new(*c)), + Self::Collide(l, r, c) => Box::new(Collide::new(l, r, c)), + Self::Fade((c,)) => Box::new(Fade::new(c)), + Self::MovingPixel((c,)) => Box::new(MovingPixel::new(c)), + Self::MovingRainbow(w, f) => Box::new(MovingRainbow::new(w, f)), + Self::Orb(c, x, y) => Box::new(Orb::new(c, x, y)), + Self::Solid((c,)) => Box::new(Solid::new(c)), + Self::Flashing(cs, w) => Box::new(Flashing::new(cs, w)), } } } diff --git a/src/pattern/moving_rainbow.rs b/src/pattern/moving_rainbow.rs index b37e5e9..26af0fa 100644 --- a/src/pattern/moving_rainbow.rs +++ b/src/pattern/moving_rainbow.rs @@ -1,13 +1,13 @@ use super::Pattern; -use crate::color::{Rgb, RAINBOW}; -use std::collections::vec_deque; -use std::collections::VecDeque; +use crate::color::{self, Rgb, RAINBOW}; +use std::collections::{vec_deque, VecDeque}; use std::convert::TryFrom; use std::iter; #[derive(Clone, Debug)] pub struct MovingRainbow { lights_buf: VecDeque, + skip: u8, width: u8, forward: bool, } @@ -15,6 +15,7 @@ impl MovingRainbow { pub fn new(width: u8, forward: bool) -> Self { Self { lights_buf: VecDeque::new(), + skip: 5, width, forward, } @@ -37,22 +38,28 @@ impl Pattern for MovingRainbow { return Err(()); } - // The length of the buffer - // Always a factor of RAINBOW.len() * width + // RAINBOW.len() * width let length_factor = u16::try_from(RAINBOW.len()) .or(Err(()))? .saturating_mul(u16::from(self.width)); - let buf_length = num_lights - .checked_sub(1) - .ok_or(())? - .div_euclid(length_factor) - .checked_add(1) - .ok_or(())? - .saturating_mul(length_factor); + // The length of the buffer + // Always a factor of length_factor + let buf_length = color::min_with_factor(num_lights, length_factor)?; + // num_lights + // .checked_sub(1) + // .ok_or(())? + // .div_euclid(length_factor) + // .checked_add(1) + // .ok_or(())? + // .saturating_mul(length_factor); self.lights_buf = RAINBOW .iter() - .flat_map(|&x| iter::repeat(x).take(self.width.into())) + .flat_map(|&x| { + iter::repeat(x) + .take(self.width.into()) + .chain(iter::repeat(color::BLACK).take(self.skip.into())) + }) .cycle() .take(buf_length.into()) .collect(); diff --git a/src/webui.rs b/src/webui.rs index 740bddd..203a9ca 100644 --- a/src/webui.rs +++ b/src/webui.rs @@ -2,17 +2,18 @@ use crate::errors; use crate::pattern; use crate::strip; -use actix_web::error::{JsonPayloadError, UrlencodedError}; -use actix_web::web::JsonConfig; -use actix_web::{post, web, App, HttpServer, Responder, Result}; +use actix_web::{ + error::{JsonPayloadError, UrlencodedError}, + post, web, + web::JsonConfig, + App, HttpServer, Responder, Result, +}; use actix_web_static_files::ResourceFiles; use std::io; -use std::sync::{Arc, Mutex}; +use std::sync::{mpsc::Sender, Arc, Mutex}; include!(concat!(env!("OUT_DIR"), "/generated.rs")); -use std::sync::mpsc::Sender; - struct AppState { strip_tx: Arc>>, } @@ -26,9 +27,9 @@ async fn set_color_json( data.strip_tx .lock() .map_err(|_| io::Error::new(io::ErrorKind::Other, "Failed to get a lock"))? - .send(strip::Message::ChangePattern(params.0.to_pattern())) + .send(strip::Message::ChangePattern(params.0.into_pattern())) .map_err(|_| io::Error::new(io::ErrorKind::Other, "Failed to send to channel"))?; - Ok(format!("{:?}", params)) + Ok("Success") } #[actix_web::main] diff --git a/web/src/Form.svelte b/web/src/Form.svelte index 0775169..7580906 100644 --- a/web/src/Form.svelte +++ b/web/src/Form.svelte @@ -24,6 +24,14 @@ {name: "center_width", type: "number", label: "Center Width", value: "1"}, {name: "backoff_width", type: "number", label: "Backoff Width", value: "0"}, ]}, + {name: "Flashing", text: "Flashing", formElements: [ + {name: "color", type: "color", label: "Color1", value: "#000000"}, + {name: "color", type: "color", label: "Color2", value: "#000000"}, + {name: "color", type: "color", label: "Color3", value: "#000000"}, + {name: "color", type: "color", label: "Color4", value: "#000000"}, + {name: "color", type: "color", label: "Color5", value: "#000000"}, + {name: "width", type: "number", label: "Width", value: "1"}, + ]}, ]; let selectedPattern = possiblePatterns[0];