1use crate::error::{ConfigError, Result};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11pub struct ColorRGBA {
12 pub r: u8,
13 pub g: u8,
14 pub b: u8,
15 pub a: u8,
16}
17
18impl ColorRGBA {
19 pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
21 Self {
22 r,
23 g,
24 b,
25 a,
26 }
27 }
28
29 pub fn from_hex(hex: &str) -> Result<Self> {
31 if !hex.starts_with('#') || hex.len() != 9 {
32 return Err(ConfigError::ColorError(
33 "Invalid hex color format. Expected '#RRGGBBAA'".to_string(),
34 ));
35 }
36
37 let r = u8::from_str_radix(&hex[1..3], 16).map_err(|_| {
38 ConfigError::ColorError("Invalid red component".to_string())
39 })?;
40 let g = u8::from_str_radix(&hex[3..5], 16).map_err(|_| {
41 ConfigError::ColorError("Invalid green component".to_string())
42 })?;
43 let b = u8::from_str_radix(&hex[5..7], 16).map_err(|_| {
44 ConfigError::ColorError("Invalid blue component".to_string())
45 })?;
46 let a = u8::from_str_radix(&hex[7..9], 16).map_err(|_| {
47 ConfigError::ColorError("Invalid alpha component".to_string())
48 })?;
49
50 Ok(Self::new(r, g, b, a))
51 }
52
53 pub fn to_hex(&self) -> String {
55 format!("#{:02X}{:02X}{:02X}{:02X}", self.r, self.g, self.b, self.a)
56 }
57}
58
59#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
61pub struct Vector2D {
62 x: f64,
63 y: f64,
64}
65
66impl Vector2D {
67 pub fn new(x: f64, y: f64) -> Result<Self> {
69 if x.is_finite() && y.is_finite() {
70 Ok(Self {
71 x,
72 y,
73 })
74 } else {
75 Err(ConfigError::ValidationError(
76 "Vector components must be finite numbers".to_string(),
77 ))
78 }
79 }
80
81 pub fn x(&self) -> f64 {
83 self.x
84 }
85
86 pub fn y(&self) -> f64 {
88 self.y
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
93pub enum Position {
94 Top,
95 Bottom,
96 Left,
97 Right,
98 TopLeft,
99 TopRight,
100 BottomLeft,
101 BottomRight,
102 Center,
103}
104
105impl Default for Position {
106 fn default() -> Self {
107 Position::TopRight
108 }
109}
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
112pub enum MouseButton {
113 Left,
114 Right,
115 Middle,
116}
117
118impl Default for MouseButton {
119 fn default() -> Self {
120 MouseButton::Left
121 }
122}
123
124pub use eframe::egui::{Color32, Key};
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_color_conversion() {
133 let color = ColorRGBA::new(255, 128, 0, 255);
134 assert_eq!(color.to_hex(), "#FF8000FF");
135
136 let parsed = ColorRGBA::from_hex("#FF8000FF").unwrap();
137 assert_eq!(color, parsed);
138 }
139
140 #[test]
141 fn test_vector_validation() {
142 assert!(Vector2D::new(1.0, 2.0).is_ok());
143 assert!(Vector2D::new(f64::INFINITY, 2.0).is_err());
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
148#[serde(from = "&str", into = "String")]
149pub struct SerializableKey(Key);
150
151impl From<&str> for SerializableKey {
152 fn from(s: &str) -> Self {
153 Self(match s {
155 "Equals" => Key::Equals,
156 "Plus" => Key::Plus,
157 "Minus" => Key::Minus,
158 "W" => Key::W,
159 "S" => Key::S,
160 "F" => Key::F,
161 "Q" => Key::Q,
162 "Num0" => Key::Num0,
163 _ => Key::Equals, })
165 }
166}
167
168impl From<SerializableKey> for String {
169 fn from(key: SerializableKey) -> Self {
170 match key.0 {
171 Key::Equals => "Equals",
172 Key::Plus => "Plus",
173 Key::Minus => "Minus",
174 Key::W => "W",
175 Key::S => "S",
176 Key::F => "F",
177 Key::Num0 => "Num0",
178 _ => "Equal",
179 }
180 .to_string()
181 }
182}