1 use crate::Vec2; 2 use crate::XY; 3 use std::cmp::min; 4 5 /// Location of the view on screen 6 pub type Position = XY<Offset>; 7 8 impl Position { 9 /// Returns a position centered on both axis. center() -> Self10 pub fn center() -> Self { 11 Position::new(Offset::Center, Offset::Center) 12 } 13 14 /// Returns a position absolute on both axis. absolute<T: Into<Vec2>>(offset: T) -> Self15 pub fn absolute<T: Into<Vec2>>(offset: T) -> Self { 16 let offset = offset.into(); 17 Position::new(Offset::Absolute(offset.x), Offset::Absolute(offset.y)) 18 } 19 20 /// Returns a position relative to the parent on both axis. parent<T: Into<XY<isize>>>(offset: T) -> Self21 pub fn parent<T: Into<XY<isize>>>(offset: T) -> Self { 22 let offset = offset.into(); 23 Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y)) 24 } 25 26 /// Computes the offset required to draw a view. 27 /// 28 /// When drawing a view with `size` in a container with `available`, 29 /// and a parent with the absolute coordinates `parent`, drawing the 30 /// child with its top-left corner at the returned coordinates will 31 /// position him appropriately. compute_offset<S, A, P>( &self, size: S, available: A, parent: P, ) -> Vec2 where S: Into<Vec2>, A: Into<Vec2>, P: Into<Vec2>,32 pub fn compute_offset<S, A, P>( 33 &self, 34 size: S, 35 available: A, 36 parent: P, 37 ) -> Vec2 38 where 39 S: Into<Vec2>, 40 A: Into<Vec2>, 41 P: Into<Vec2>, 42 { 43 let available = available.into(); 44 let size = size.into(); 45 let parent = parent.into(); 46 47 Vec2::new( 48 self.x.compute_offset(size.x, available.x, parent.x), 49 self.y.compute_offset(size.y, available.y, parent.y), 50 ) 51 } 52 } 53 54 /// Single-dimensional offset policy. 55 #[derive(PartialEq, Eq, Debug, Clone, Copy, Hash)] 56 pub enum Offset { 57 /// In the center of the screen 58 Center, 59 /// Place top-left corner at the given absolute coordinates 60 Absolute(usize), 61 62 /// Offset from the previous layer's top-left corner. 63 /// 64 /// If this is the first layer, behaves like `Absolute`. 65 Parent(isize), 66 } 67 68 impl Offset { 69 /// Computes a single-dimension offset requred to draw a view. compute_offset( &self, size: usize, available: usize, parent: usize, ) -> usize70 pub fn compute_offset( 71 &self, 72 size: usize, 73 available: usize, 74 parent: usize, 75 ) -> usize { 76 if size > available { 77 0 78 } else { 79 match *self { 80 Offset::Center => (available - size) / 2, 81 Offset::Absolute(offset) => min(offset, available - size), 82 Offset::Parent(offset) => { 83 min((parent as isize + offset) as usize, available - size) 84 } 85 } 86 } 87 } 88 } 89 90 #[cfg(test)] 91 mod tests { 92 93 use super::Position; 94 use crate::Vec2; 95 96 #[test] test_center()97 fn test_center() { 98 let c = Position::center(); 99 assert_eq!(Vec2::new(2, 1), c.compute_offset((1, 1), (5, 3), (0, 0))); 100 assert_eq!(Vec2::new(2, 0), c.compute_offset((1, 3), (5, 3), (0, 0))); 101 assert_eq!(Vec2::new(1, 1), c.compute_offset((3, 1), (5, 3), (0, 0))); 102 assert_eq!(Vec2::new(0, 1), c.compute_offset((5, 1), (5, 3), (0, 0))); 103 assert_eq!(Vec2::new(0, 0), c.compute_offset((5, 3), (5, 3), (0, 0))); 104 assert_eq!(Vec2::new(0, 0), c.compute_offset((5, 3), (3, 1), (0, 0))); 105 } 106 } 107