use crate::Framebuffer;
use crate::Lights;
use crate::color::RGB;
use crate::hal;
use crate::hal::SetAndFlushLights;
use std::sync::Arc;
use std::sync::Mutex;
#[derive(Clone)]
pub struct LightsSetter {
inner: Arc<Mutex<LightsSettingInner>>,
}
impl LightsSetter {
pub fn get() -> &'static LightsSetter {
crate::hal::LIGHTS.get().unwrap()
}
#[doc(hidden)]
pub fn new(hal: SetAndFlushLights) -> LightsSetter {
let inner = LightsSettingInner {
hal,
buffer: Framebuffer::new(),
auto_flush: true,
};
let inner = Arc::new(Mutex::new(inner));
LightsSetter { inner }
}
#[expect(
clippy::missing_panics_doc,
reason = "Mutex is internal and should not poisen"
)]
pub fn set_color(&self, selection: Lights, color: RGB) {
let mut inner = self.inner.lock().unwrap();
inner.buffer.set_color(selection, color);
if inner.auto_flush {
inner.flush();
}
}
#[expect(
clippy::missing_panics_doc,
reason = "Mutex is internal and should not poisen"
)]
pub fn set_all_colors(&self, colors: &[RGB; Lights::COUNT]) {
let mut inner = self.inner.lock().unwrap();
inner.buffer.set_all_colors(colors);
if inner.auto_flush {
inner.flush();
}
}
#[expect(
clippy::missing_panics_doc,
reason = "Mutex is internal and should not poisen"
)]
pub fn set_colors_on_selection(&self, selection: Lights, colors: &[RGB; Lights::COUNT]) {
let mut inner = self.inner.lock().unwrap();
for idx in selection.indices() {
inner.buffer.colors[idx] = colors[idx];
}
if inner.auto_flush {
inner.flush();
}
}
#[expect(
clippy::missing_panics_doc,
reason = "Mutex is internal and should not poisen"
)]
pub fn set_colors_on(&self, selection: Lights, colors: &[RGB]) {
let mut inner = self.inner.lock().unwrap();
for (light_idx, color) in selection.indices().zip(colors.iter()) {
inner.buffer.colors[light_idx] = *color;
}
if inner.auto_flush {
inner.flush();
}
}
#[expect(
clippy::missing_panics_doc,
reason = "Mutex is internal and should not poisen"
)]
pub fn flush(&self) {
let mut inner = self.inner.lock().unwrap();
inner.flush();
}
#[expect(
clippy::missing_panics_doc,
reason = "Mutex is internal and should not poisen"
)]
pub fn set_auto_flush(&self, v: bool) {
let mut inner = self.inner.lock().unwrap();
inner.auto_flush = v;
}
#[expect(
clippy::missing_panics_doc,
reason = "Mutex is internal and should not poisen"
)]
pub fn get_currently_set(&self) -> Framebuffer {
let inner = self.inner.lock().unwrap();
inner.buffer.clone()
}
#[expect(
clippy::missing_panics_doc,
reason = "Mutex is internal and should not poisen"
)]
#[must_use]
pub fn pause_auto_flush(&self) -> PauseAutoFlushGuard {
let mut inner = self.inner.lock().unwrap();
let should_reenable = inner.auto_flush;
inner.auto_flush = false;
PauseAutoFlushGuard {
should_reenable,
lights_setter: self.clone(),
}
}
}
impl std::fmt::Debug for LightsSetter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Lights").finish()
}
}
struct LightsSettingInner {
pub buffer: Framebuffer,
pub auto_flush: bool,
pub hal: hal::SetAndFlushLights,
}
impl LightsSettingInner {
pub fn flush(&mut self) {
(self.hal)(&self.buffer.colors);
}
}
pub struct PauseAutoFlushGuard {
lights_setter: LightsSetter,
should_reenable: bool,
}
impl Drop for PauseAutoFlushGuard {
fn drop(&mut self) {
if self.should_reenable {
self.lights_setter.set_auto_flush(true);
}
self.lights_setter.flush();
}
}