focus_tracker_core/
config.rs

1use std::time::Duration;
2
3/// Configuration for icon processing behavior
4#[derive(Debug, Clone)]
5pub struct IconConfig {
6    /// Target size for icons (width and height will be equal)
7    /// Default: None (use platform default size)
8    pub size: Option<u32>,
9
10    /// The algorithm to use for icon scaling, supports Windows and Linux x11
11    pub filter_type: image::imageops::FilterType,
12}
13
14impl Default for IconConfig {
15    fn default() -> Self {
16        Self {
17            size: None,
18            filter_type: image::imageops::FilterType::Lanczos3,
19        }
20    }
21}
22
23impl IconConfig {
24    /// Create a new icon configuration with default settings
25    pub fn new() -> Self {
26        Self::default()
27    }
28
29    /// Set the icon size (width and height will be equal)
30    ///
31    /// # Arguments
32    /// * `size` - The icon size in pixels
33    ///
34    /// # Panics
35    /// Panics if the size is zero or too large (> 512)
36    pub fn with_size(mut self, size: u32) -> Self {
37        self.validate_size(size);
38        self.size = Some(size);
39        self
40    }
41
42    /// Get the icon size, using a default if none is configured
43    pub fn get_size_or_default(&self) -> u32 {
44        self.size.unwrap_or(128) // Default to 128x128
45    }
46
47    /// Validate the icon size
48    fn validate_size(&self, size: u32) {
49        if size == 0 {
50            panic!("Icon size cannot be zero");
51        }
52        if size > 512 {
53            panic!("Icon size cannot be greater than 512 pixels");
54        }
55    }
56}
57
58/// Configuration for focus tracking behavior
59#[derive(Debug, Clone)]
60pub struct FocusTrackerConfig {
61    /// Polling interval for focus change detection
62    /// Default: 100ms
63    pub poll_interval: Duration,
64    /// Icon processing configuration
65    /// Default: IconConfig::default()
66    pub icon: IconConfig,
67}
68
69impl Default for FocusTrackerConfig {
70    fn default() -> Self {
71        Self {
72            poll_interval: Duration::from_millis(100),
73            icon: IconConfig::default(),
74        }
75    }
76}
77
78impl FocusTrackerConfig {
79    /// Create a new configuration with default settings
80    pub fn new() -> Self {
81        Self::default()
82    }
83
84    /// Set the icon configuration
85    ///
86    /// # Arguments
87    /// * `icon` - The icon configuration
88    pub fn with_icon_config(mut self, icon: IconConfig) -> Self {
89        self.icon = icon;
90        self
91    }
92
93    /// Set the icon size (convenience method)
94    ///
95    /// # Arguments
96    /// * `size` - The icon size in pixels
97    ///
98    /// # Panics
99    /// Panics if the size is zero or too large (> 512)
100    pub fn with_icon_size(mut self, size: u32) -> Self {
101        self.icon = self.icon.with_size(size);
102        self
103    }
104
105    /// Set the polling interval for focus change detection
106    ///
107    /// # Arguments
108    /// * `interval` - The polling interval duration
109    ///
110    /// # Panics
111    /// Panics if the interval is zero or too large (> 10 seconds)
112    pub fn with_poll_interval(mut self, interval: Duration) -> Self {
113        self.validate_poll_interval(interval);
114        self.poll_interval = interval;
115        self
116    }
117
118    /// Set the polling interval in milliseconds
119    ///
120    /// # Arguments
121    /// * `ms` - The polling interval in milliseconds
122    ///
123    /// # Panics
124    /// Panics if the interval is zero or too large (> 10000ms)
125    pub fn with_poll_interval_ms(self, ms: u64) -> Self {
126        self.with_poll_interval(Duration::from_millis(ms))
127    }
128
129    /// Validate the polling interval
130    fn validate_poll_interval(&self, interval: Duration) {
131        if interval.is_zero() {
132            panic!("Poll interval cannot be zero");
133        }
134        if interval > Duration::from_secs(10) {
135            panic!("Poll interval cannot be greater than 10 seconds");
136        }
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    #[test]
145    fn test_default_config() {
146        let config = FocusTrackerConfig::default();
147        assert_eq!(config.poll_interval, Duration::from_millis(100));
148    }
149
150    #[test]
151    fn test_default_icon_config() {
152        let config = FocusTrackerConfig::default();
153        assert_eq!(config.icon.size, None);
154    }
155
156    #[test]
157    fn test_builder_pattern() {
158        let config = FocusTrackerConfig::new().with_poll_interval_ms(250);
159        assert_eq!(config.poll_interval, Duration::from_millis(250));
160    }
161
162    #[test]
163    fn test_icon_config_builder() {
164        let config = FocusTrackerConfig::new().with_icon_size(64);
165        assert_eq!(config.icon.size, Some(64));
166    }
167
168    #[test]
169    fn test_icon_config_default_size() {
170        let icon_config = IconConfig::new();
171        assert_eq!(icon_config.get_size_or_default(), 128);
172    }
173
174    #[test]
175    fn test_icon_config_with_size() {
176        let icon_config = IconConfig::new().with_size(256);
177        assert_eq!(icon_config.size, Some(256));
178        assert_eq!(icon_config.get_size_or_default(), 256);
179    }
180
181    #[test]
182    #[should_panic(expected = "Icon size cannot be zero")]
183    fn test_zero_icon_size_panics() {
184        IconConfig::new().with_size(0);
185    }
186
187    #[test]
188    #[should_panic(expected = "Icon size cannot be greater than 512 pixels")]
189    fn test_large_icon_size_panics() {
190        IconConfig::new().with_size(1024);
191    }
192
193    #[test]
194    fn test_with_poll_interval() {
195        let config = FocusTrackerConfig::new().with_poll_interval(Duration::from_millis(500));
196        assert_eq!(config.poll_interval, Duration::from_millis(500));
197    }
198
199    #[test]
200    #[should_panic(expected = "Poll interval cannot be zero")]
201    fn test_zero_interval_panics() {
202        FocusTrackerConfig::new().with_poll_interval(Duration::from_millis(0));
203    }
204
205    #[test]
206    #[should_panic(expected = "Poll interval cannot be greater than 10 seconds")]
207    fn test_large_interval_panics() {
208        FocusTrackerConfig::new().with_poll_interval(Duration::from_secs(11));
209    }
210}