use crate::display_metrics::DisplayMetrics;
use input_pipeline::{Position, Size};
#[derive(Clone, Copy, Debug)]
pub struct ScreenCoordinates {
x_pixels: f32,
y_pixels: f32,
display_metrics: DisplayMetrics,
}
#[allow(dead_code)]
impl ScreenCoordinates {
pub fn from_pixels(x: f32, y: f32, display_metrics: DisplayMetrics) -> Self {
Self { x_pixels: x, y_pixels: y, display_metrics }
}
pub fn from_pips(x: f32, y: f32, display_metrics: DisplayMetrics) -> Self {
Self {
x_pixels: x * display_metrics.pixels_per_pip(),
y_pixels: y * display_metrics.pixels_per_pip(),
display_metrics,
}
}
pub fn from_mm(x: f32, y: f32, display_metrics: DisplayMetrics) -> Self {
Self {
x_pixels: x * display_metrics.pixels_per_pip() * display_metrics.mm_per_pip(),
y_pixels: y * display_metrics.pixels_per_pip() * display_metrics.mm_per_pip(),
display_metrics,
}
}
pub fn from_position(position: &Position, display_metrics: DisplayMetrics) -> Self {
Self { x_pixels: position.x, y_pixels: position.y, display_metrics }
}
pub fn pixels(&self) -> (f32, f32) {
(self.x_pixels, self.y_pixels)
}
pub fn pips(&self) -> (f32, f32) {
(
self.x_pixels / self.display_metrics.pixels_per_pip(),
self.y_pixels / self.display_metrics.pixels_per_pip(),
)
}
pub fn mm(&self) -> (f32, f32) {
let (x_pips, y_pips) = self.pips();
(x_pips / self.display_metrics.mm_per_pip(), y_pips / self.display_metrics.mm_per_pip())
}
pub fn position(&self) -> Position {
Position { x: self.x_pixels, y: self.y_pixels }
}
}
#[derive(Clone, Copy, Debug)]
pub struct ScreenSize {
width_pixels: f32,
height_pixels: f32,
display_metrics: DisplayMetrics,
}
#[allow(dead_code)]
impl ScreenSize {
pub fn from_pixels(width: f32, height: f32, display_metrics: DisplayMetrics) -> Self {
Self { width_pixels: width, height_pixels: height, display_metrics }
}
pub fn from_pips(width: f32, height: f32, display_metrics: DisplayMetrics) -> Self {
Self {
width_pixels: width * display_metrics.pixels_per_pip(),
height_pixels: height * display_metrics.pixels_per_pip(),
display_metrics,
}
}
pub fn from_mm(width: f32, height: f32, display_metrics: DisplayMetrics) -> Self {
Self {
width_pixels: width * display_metrics.pixels_per_pip() * display_metrics.mm_per_pip(),
height_pixels: height * display_metrics.pixels_per_pip() * display_metrics.mm_per_pip(),
display_metrics,
}
}
pub fn from_size(size: &Size, display_metrics: DisplayMetrics) -> Self {
Self { width_pixels: size.width, height_pixels: size.height, display_metrics }
}
pub fn pixels(&self) -> (f32, f32) {
(self.width_pixels, self.height_pixels)
}
pub fn pips(&self) -> (f32, f32) {
(
self.width_pixels / self.display_metrics.pixels_per_pip(),
self.height_pixels / self.display_metrics.pixels_per_pip(),
)
}
pub fn mm(&self) -> (f32, f32) {
let (width_pips, height_pips) = self.pips();
(
width_pips / self.display_metrics.mm_per_pip(),
height_pips / self.display_metrics.mm_per_pip(),
)
}
pub fn size(&self) -> Size {
Size { width: self.width_pixels, height: self.height_pixels }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[inline]
fn assert_close_enough(left: (f32, f32), right: (f32, f32)) {
const EPSILON: f32 = 0.0001;
assert!(left.0 > right.0 - EPSILON, "Left: {:?} Right: {:?}", left, right);
assert!(left.0 < right.0 + EPSILON, "Left: {:?} Right: {:?}", left, right);
assert!(left.1 > right.1 - EPSILON, "Left: {:?} Right: {:?}", left, right);
assert!(left.1 < right.1 + EPSILON, "Left: {:?} Right: {:?}", left, right);
}
#[inline]
fn assert_postion_close_enough(left: Position, right: Position) {
assert_close_enough((left.x, left.y), (right.x, right.y));
}
#[test]
fn test_pixel_constructor() {
let display_metrics =
DisplayMetrics::new(Size { width: 1000.0, height: 500.0 }, Some(10.0), None, None);
let coords = ScreenCoordinates::from_pixels(100.0, 100.0, display_metrics);
assert_close_enough(coords.pixels(), (100.0, 100.0));
assert_close_enough(coords.pips(), (52.2449, 52.2449));
assert_close_enough(coords.mm(), (272.9529, 272.9529));
assert_postion_close_enough(coords.position(), Position { x: 100.0, y: 100.0 });
}
#[test]
fn test_pip_constructor() {
let display_metrics =
DisplayMetrics::new(Size { width: 1000.0, height: 500.0 }, Some(10.0), None, None);
let coords = ScreenCoordinates::from_pips(52.2449, 52.2449, display_metrics);
assert_close_enough(coords.pixels(), (100.0, 100.0));
assert_close_enough(coords.pips(), (52.2449, 52.2449));
assert_close_enough(coords.mm(), (272.9529, 272.9529));
assert_postion_close_enough(coords.position(), Position { x: 100.0, y: 100.0 });
}
#[test]
fn test_mm_constructor() {
let display_metrics =
DisplayMetrics::new(Size { width: 1000.0, height: 500.0 }, Some(10.0), None, None);
let coords = ScreenCoordinates::from_mm(272.9529, 272.9529, display_metrics);
assert_close_enough(coords.pixels(), (100.0, 100.0));
assert_close_enough(coords.pips(), (52.2449, 52.2449));
assert_close_enough(coords.mm(), (272.9529, 272.9529));
assert_postion_close_enough(coords.position(), Position { x: 100.0, y: 100.0 });
}
#[test]
fn test_position_constructor() {
let display_metrics =
DisplayMetrics::new(Size { width: 1000.0, height: 500.0 }, Some(10.0), None, None);
let coords =
ScreenCoordinates::from_position(&Position { x: 100.0, y: 100.0 }, display_metrics);
assert_close_enough(coords.pixels(), (100.0, 100.0));
assert_close_enough(coords.pips(), (52.2449, 52.2449));
assert_close_enough(coords.mm(), (272.9529, 272.9529));
assert_postion_close_enough(coords.position(), Position { x: 100.0, y: 100.0 });
}
}