Skip to main content

droidrun_core/ui/
coord.rs

1/// Coordinate conversion utilities for normalized [0-1000] coordinates.
2use crate::error::{DroidrunError, Result};
3
4/// Maximum value for normalized coordinates.
5pub const NORMALIZED_MAX: i32 = 1000;
6
7/// Convert [0-1000] normalized to absolute pixels.
8pub fn to_absolute(x: i32, y: i32, width: i32, height: i32) -> Result<(i32, i32)> {
9    if width <= 0 || height <= 0 {
10        return Err(DroidrunError::NoDimensions);
11    }
12    Ok((x * width / NORMALIZED_MAX, y * height / NORMALIZED_MAX))
13}
14
15/// Convert absolute pixels to [0-1000] normalized.
16pub fn to_normalized(x: i32, y: i32, width: i32, height: i32) -> Result<(i32, i32)> {
17    if width <= 0 || height <= 0 {
18        return Err(DroidrunError::NoDimensions);
19    }
20    Ok((x * NORMALIZED_MAX / width, y * NORMALIZED_MAX / height))
21}
22
23/// Convert "left,top,right,bottom" bounds string to normalized.
24pub fn bounds_to_normalized(bounds: &str, width: i32, height: i32) -> Result<String> {
25    let parts: Vec<i32> = bounds
26        .split(',')
27        .map(|s| {
28            s.trim()
29                .parse()
30                .map_err(|_| DroidrunError::InvalidBounds(bounds.into()))
31        })
32        .collect::<Result<Vec<_>>>()?;
33
34    if parts.len() != 4 {
35        return Err(DroidrunError::InvalidBounds(bounds.into()));
36    }
37
38    let (nl, nt) = to_normalized(parts[0], parts[1], width, height)?;
39    let (nr, nb) = to_normalized(parts[2], parts[3], width, height)?;
40
41    Ok(format!("{nl},{nt},{nr},{nb}"))
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn test_to_absolute() {
50        let (x, y) = to_absolute(500, 500, 1080, 2400).unwrap();
51        assert_eq!(x, 540);
52        assert_eq!(y, 1200);
53    }
54
55    #[test]
56    fn test_to_absolute_zero() {
57        let (x, y) = to_absolute(0, 0, 1080, 2400).unwrap();
58        assert_eq!(x, 0);
59        assert_eq!(y, 0);
60    }
61
62    #[test]
63    fn test_to_absolute_max() {
64        let (x, y) = to_absolute(1000, 1000, 1080, 2400).unwrap();
65        assert_eq!(x, 1080);
66        assert_eq!(y, 2400);
67    }
68
69    #[test]
70    fn test_to_normalized() {
71        let (x, y) = to_normalized(540, 1200, 1080, 2400).unwrap();
72        assert_eq!(x, 500);
73        assert_eq!(y, 500);
74    }
75
76    #[test]
77    fn test_bounds_to_normalized() {
78        let result = bounds_to_normalized("0,0,1080,2400", 1080, 2400).unwrap();
79        assert_eq!(result, "0,0,1000,1000");
80    }
81
82    #[test]
83    fn test_invalid_dimensions() {
84        assert!(to_absolute(500, 500, 0, 0).is_err());
85    }
86
87    #[test]
88    fn test_invalid_bounds_format() {
89        assert!(bounds_to_normalized("invalid", 1080, 2400).is_err());
90    }
91}