theframework/
thepalette.rs1pub use crate::prelude::*;
2use std::ops::{Index, IndexMut};
3
4#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
6pub struct ThePalette {
7 #[serde(default)]
8 pub current_index: u16,
9 pub colors: Vec<Option<TheColor>>,
10}
11
12impl Default for ThePalette {
13 fn default() -> Self {
14 Self::empty_256()
15 }
16}
17
18impl ThePalette {
19 pub fn new(colors: Vec<Option<TheColor>>) -> Self {
20 Self {
21 current_index: 0,
22 colors,
23 }
24 }
25
26 pub fn empty_256() -> Self {
27 let mut colors = Vec::new();
28 for _ in 0..256 {
29 colors.push(None);
30 }
31 Self {
32 current_index: 0,
33 colors,
34 }
35 }
36
37 pub fn is_empty(&self) -> bool {
39 for v in self.colors.iter() {
40 if v.is_some() {
41 return false;
42 }
43 }
44 true
45 }
46
47 pub fn get_current_color(&self) -> Option<TheColor> {
49 self.colors[self.current_index as usize].clone()
50 }
51
52 pub fn clear(&mut self) {
54 for v in self.colors.iter_mut() {
55 *v = None;
56 }
57 }
58
59 pub fn load_from_txt(&mut self, txt: String) {
61 let mut index = self.current_index as usize;
62 for line in txt.lines() {
63 if line.starts_with(';') {
65 continue;
66 }
67
68 let mut chars = line.chars();
69
70 if chars.next().is_none() {
72 return;
73 }
74 if chars.next().is_none() {
75 return;
76 }
77
78 let mut r_string = "".to_string();
80 if let Some(c) = chars.next() {
81 r_string.push(c);
82 }
83 if let Some(c) = chars.next() {
84 r_string.push(c);
85 }
86
87 let r = u8::from_str_radix(&r_string, 16);
88
89 let mut g_string = "".to_string();
91 if let Some(c) = chars.next() {
92 g_string.push(c);
93 }
94 if let Some(c) = chars.next() {
95 g_string.push(c);
96 }
97
98 let g = u8::from_str_radix(&g_string, 16);
99
100 let mut b_string = "".to_string();
102 if let Some(c) = chars.next() {
103 b_string.push(c);
104 }
105 if let Some(c) = chars.next() {
106 b_string.push(c);
107 }
108
109 let b = u8::from_str_radix(&b_string, 16);
110
111 if r.is_ok() && g.is_ok() && b.is_ok() {
112 let r = r.ok().unwrap();
113 let g = g.ok().unwrap();
114 let b = b.ok().unwrap();
115
116 if index < self.colors.len() {
117 self.colors[index] = Some(TheColor::from_u8(r, g, b, 0xFF));
118 }
119
120 index += 1;
121 }
122 }
123 }
124
125 pub fn add_unique_color(&mut self, color: TheColor) -> Option<usize> {
128 for (i, existing) in self.colors.iter().enumerate() {
130 if let Some(existing_color) = existing {
131 if *existing_color == color {
132 return Some(i);
133 }
134 }
135 }
136
137 for (i, slot) in self.colors.iter_mut().enumerate() {
139 if slot.is_none() {
140 *slot = Some(color);
141 return Some(i);
142 }
143 }
144
145 None
147 }
148
149 pub fn find_closest_color_index(&self, color: &TheColor) -> Option<usize> {
180 let mut best_index = None;
181 let mut best_distance = f32::MAX;
182
183 for (i, entry) in self.colors.iter().enumerate() {
184 if let Some(existing) = entry {
185 let dr = existing.r - color.r;
187 let dg = existing.g - color.g;
188 let db = existing.b - color.b;
189 let da = existing.a - color.a;
190
191 let dist = dr * dr * 0.30 + dg * dg * 0.59 + db * db * 0.11 + da * da * 0.05;
193
194 if dist < best_distance {
195 best_distance = dist;
196 best_index = Some(i);
197 }
198 }
199 }
200
201 best_index
202 }
203}
204
205impl Index<usize> for ThePalette {
206 type Output = Option<TheColor>;
207
208 fn index(&self, index: usize) -> &Self::Output {
209 if index < self.colors.len() {
210 &self.colors[index]
211 } else {
212 panic!("Color Index out of bounds!");
213 }
214 }
215}
216
217impl IndexMut<usize> for ThePalette {
218 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
219 if index < self.colors.len() {
220 &mut self.colors[index]
221 } else {
222 panic!("Color Index out of bounds!");
223 }
224 }
225}