1use wmidi::U7;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct ColorPaletteIndex(U7);
7
8impl ColorPaletteIndex {
9 fn clamp_new(value: u8) -> Self {
11 Self(U7::clamp_new(value))
12 }
13
14 pub fn try_from(value: u8) -> Result<Self, String> {
16 U7::try_from(value).map(Self).map_err(|_| {
17 format!(
18 "Invalid color index: {}. Must be between 0 and 127.",
19 value
20 )
21 })
22 }
23
24 pub fn as_u8(self) -> u8 {
26 self.0.into()
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct Color {
34 pub r: U7,
35 pub g: U7,
36 pub b: U7,
37}
38
39impl Color {
40 pub fn try_new(r: u8, g: u8, b: u8) -> Result<Self, String> {
42 let r = U7::try_from(r).map_err(|_| format!("Invalid R value: {}. Must be between 0 and 127.", r))?;
43 let g = U7::try_from(g).map_err(|_| format!("Invalid G value: {}. Must be between 0 and 127.", g))?;
44 let b = U7::try_from(b).map_err(|_| format!("Invalid B value: {}. Must be between 0 and 127.", b))?;
45 Ok(Self { r, g, b })
46 }
47
48 pub(crate) fn clamp_new(r: u8, g: u8, b: u8) -> Self {
51 Self {
52 r: U7::clamp_new(r),
53 g: U7::clamp_new(g),
54 b: U7::clamp_new(b),
55 }
56 }
57
58 pub fn from_full_range(r: u8, g: u8, b: u8) -> Self {
61 Self {
62 r: U7::from_u8_lossy((r as f32 * 127.0 / 255.0) as u8),
63 g: U7::from_u8_lossy((g as f32 * 127.0 / 255.0) as u8),
64 b: U7::from_u8_lossy((b as f32 * 127.0 / 255.0) as u8),
65 }
66 }
67
68 pub fn from_color_palette_range(r: u8, g: u8, b: u8) -> Self {
71 Self::map_rgb(r.max(97), g.max(97), b.max(97), 97, 255)
72 }
73
74 pub fn map_rgb(r: u8, g: u8, b: u8, in_min: u8, in_max: u8) -> Self {
76 let out_min = 0;
77 let out_max = 127;
78
79 let map_value = |value: u8| -> U7 {
80 let mapped = ((value as f32 - in_min as f32) / (in_max as f32 - in_min as f32)
81 * (out_max as f32 - out_min as f32)
82 + out_min as f32) as u8;
83 U7::from_u8_lossy(mapped)
84 };
85
86 Self {
87 r: map_value(r),
88 g: map_value(g),
89 b: map_value(b),
90 }
91 }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub enum CommonColor {
98 Off,
99 DarkGray,
100 LightGray,
101 White,
102 DimRed,
103 NormalRed,
104 BrightRed,
105 DimOrange,
106 NormalOrange,
107 BrightOrange,
108 DimYellow,
109 NormalYellow,
110 BrightYellow,
111 DimGreen,
112 NormalGreen,
113 BrightGreen,
114 DimCyan,
115 NormalCyan,
116 BrightCyan,
117 DimBlue,
118 NormalBlue,
119 BrightBlue,
120 DimPurple,
121 NormalPurple,
122 BrightPurple,
123 DimPink,
124 NormalPink,
125 BrightPink,
126}
127
128impl CommonColor {
129 pub fn to_palette_index(self) -> ColorPaletteIndex {
131 let index = match self {
132 CommonColor::Off => 0x00,
133 CommonColor::DarkGray => 0x01,
134 CommonColor::LightGray => 0x02,
135 CommonColor::White => 0x03,
136 CommonColor::DimRed => 0x07,
137 CommonColor::NormalRed => 0x06,
138 CommonColor::BrightRed => 0x05,
139 CommonColor::DimOrange => 0x0B,
140 CommonColor::NormalOrange => 0x0A,
141 CommonColor::BrightOrange => 0x09,
142 CommonColor::DimYellow => 0x0F,
143 CommonColor::NormalYellow => 0x0E,
144 CommonColor::BrightYellow => 0x0D,
145 CommonColor::DimGreen => 0x17,
146 CommonColor::NormalGreen => 0x16,
147 CommonColor::BrightGreen => 0x15,
148 CommonColor::DimCyan => 0x27,
149 CommonColor::NormalCyan => 0x26,
150 CommonColor::BrightCyan => 0x25,
151 CommonColor::DimBlue => 0x2F,
152 CommonColor::NormalBlue => 0x2E,
153 CommonColor::BrightBlue => 0x2D,
154 CommonColor::DimPurple => 0x33,
155 CommonColor::NormalPurple => 0x32,
156 CommonColor::BrightPurple => 0x31,
157 CommonColor::DimPink => 0x37,
158 CommonColor::NormalPink => 0x36,
159 CommonColor::BrightPink => 0x35,
160 };
161 ColorPaletteIndex::clamp_new(index)
162 }
163
164 pub fn to_color(self) -> Color {
166 match self {
167 CommonColor::Off => Color::from_color_palette_range(97, 97, 97),
168 CommonColor::DarkGray => Color::from_color_palette_range(179, 179, 179),
169 CommonColor::LightGray => Color::from_color_palette_range(221, 221, 221),
170 CommonColor::White => Color::from_color_palette_range(255, 255, 255),
171 CommonColor::DimRed => Color::from_color_palette_range(179, 97, 97),
172 CommonColor::NormalRed => Color::from_color_palette_range(221, 97, 97),
173 CommonColor::BrightRed => Color::from_color_palette_range(255, 97, 97),
174 CommonColor::DimOrange => Color::from_color_palette_range(179, 118, 97),
175 CommonColor::NormalOrange => Color::from_color_palette_range(221, 140, 97),
176 CommonColor::BrightOrange => Color::from_color_palette_range(255, 179, 97),
177 CommonColor::DimYellow => Color::from_color_palette_range(179, 179, 97),
178 CommonColor::NormalYellow => Color::from_color_palette_range(221, 221, 97),
179 CommonColor::BrightYellow => Color::from_color_palette_range(255, 255, 97),
180 CommonColor::DimGreen => Color::from_color_palette_range(97, 179, 97),
181 CommonColor::NormalGreen => Color::from_color_palette_range(97, 221, 97),
182 CommonColor::BrightGreen => Color::from_color_palette_range(97, 255, 97),
183 CommonColor::DimCyan => Color::from_color_palette_range(97, 161, 179),
184 CommonColor::NormalCyan => Color::from_color_palette_range(97, 199, 221),
185 CommonColor::BrightCyan => Color::from_color_palette_range(97, 238, 255),
186 CommonColor::DimBlue => Color::from_color_palette_range(97, 97, 179),
187 CommonColor::NormalBlue => Color::from_color_palette_range(97, 97, 221),
188 CommonColor::BrightBlue => Color::from_color_palette_range(97, 97, 255),
189 CommonColor::DimPurple => Color::from_color_palette_range(118, 97, 179),
190 CommonColor::NormalPurple => Color::from_color_palette_range(129, 97, 221),
191 CommonColor::BrightPurple => Color::from_color_palette_range(161, 97, 255),
192 CommonColor::DimPink => Color::from_color_palette_range(179, 97, 179),
193 CommonColor::NormalPink => Color::from_color_palette_range(221, 97, 221),
194 CommonColor::BrightPink => Color::from_color_palette_range(255, 97, 255),
195 }
196 }
197}
198
199impl Into<ColorPaletteIndex> for CommonColor {
200 fn into(self) -> ColorPaletteIndex {
201 self.to_palette_index()
202 }
203}
204
205impl Into<Color> for CommonColor {
206 fn into(self) -> Color {
207 self.to_color()
208 }
209}
210
211pub trait U7Ext {
213 fn clamp_new(value: u8) -> U7;
214}
215
216impl U7Ext for U7 {
217 fn clamp_new(value: u8) -> U7 {
218 U7::from_u8_lossy(value.min(U7::MAX.into()))
220 }
221}