1use palette::{
2 encoding::{Linear, Srgb},
3 FromColor, Hsl,
4};
5use serde::Serialize;
6
7use crate::{
8 component::ComponentName,
9 global::{InputMessageData, Message},
10 models::Color,
11};
12
13fn not_positive(x: &i64) -> bool {
14 *x <= 0
15}
16
17fn color_to_hsl(color: Color) -> Hsl<Linear<Srgb>> {
18 let (r, g, b) = color.into_components();
19 palette::Hsl::from_color(palette::LinSrgb::new(
20 r as f32 / 255.0,
21 g as f32 / 255.0,
22 b as f32 / 255.0,
23 ))
24}
25
26#[derive(Debug, Serialize)]
27pub struct PriorityInfo {
28 pub priority: i32,
29 #[serde(skip_serializing_if = "not_positive")]
30 pub duration_ms: i64,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub owner: Option<String>,
33 pub component_id: ComponentName,
34 pub origin: String,
35 pub active: bool,
36 pub visible: bool,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub value: Option<LedColor>,
39}
40
41impl PriorityInfo {
42 pub fn new(
43 msg: &crate::global::InputMessage,
44 origin: String,
45 expires: Option<std::time::Instant>,
46 visible: bool,
47 ) -> Self {
48 let duration_ms = expires
49 .and_then(|when| {
50 let now = std::time::Instant::now();
51
52 if when > now {
53 chrono::Duration::from_std(when - now).ok()
54 } else {
55 Some(chrono::Duration::zero())
56 }
57 })
58 .map(|d| d.num_milliseconds())
59 .unwrap_or(-1);
60 let active = duration_ms >= -1;
61
62 match msg.data() {
63 InputMessageData::SolidColor {
64 priority, color, ..
65 } => Self {
66 priority: *priority,
67 duration_ms,
68 owner: None,
69 component_id: msg.component(),
70 origin,
71 active,
72 visible,
73 value: Some(color.into()),
74 },
75 InputMessageData::Image { priority, .. }
76 | InputMessageData::LedColors { priority, .. }
77 | InputMessageData::Effect { priority, .. } => Self {
78 priority: *priority,
79 duration_ms,
80 owner: None,
81 component_id: msg.component(),
82 origin,
83 active,
84 visible,
85 value: None,
86 },
87 InputMessageData::Clear { .. } | InputMessageData::ClearAll => {
88 panic!("cannot create PriorityInfo for InputMessage")
89 }
90 }
91 }
92}
93
94#[derive(Debug, Serialize)]
95#[serde(rename_all = "UPPERCASE")]
96pub struct LedColor {
97 pub rgb: [u8; 3],
98 pub hsl: (u16, f32, f32),
99}
100
101impl From<&Color> for LedColor {
102 fn from(c: &Color) -> Self {
103 let hsl = color_to_hsl(*c);
104
105 Self {
106 rgb: [c.red, c.green, c.blue],
107 hsl: (
108 (hsl.hue.into_positive_degrees() * 100.) as u16,
109 hsl.saturation,
110 hsl.lightness,
111 ),
112 }
113 }
114}
115
116pub fn i32_to_duration(d: Option<i32>) -> Option<chrono::Duration> {
117 if let Some(d) = d {
118 if d <= 0 {
119 None
120 } else {
121 Some(chrono::Duration::milliseconds(d as _))
122 }
123 } else {
124 None
125 }
126}