1 use crate::Canvas; 2 use geom::{trim_f64, Polygon, Pt2D}; 3 use serde::{Deserialize, Serialize}; 4 5 /// ScreenPt is in units of logical pixels, as opposed to physical pixels. 6 #[derive(Debug, Clone, Copy, PartialEq)] 7 pub struct ScreenPt { 8 pub x: f64, 9 pub y: f64, 10 } 11 12 impl ScreenPt { new(x: f64, y: f64) -> ScreenPt13 pub fn new(x: f64, y: f64) -> ScreenPt { 14 ScreenPt { x, y } 15 } 16 17 // The geom layer operates in map-space, but currently reusing lots of geom abstractions for 18 // screen-space. to_pt(self) -> Pt2D19 pub fn to_pt(self) -> Pt2D { 20 Pt2D::new(self.x, self.y) 21 } 22 } 23 24 impl From<winit::dpi::LogicalPosition<f64>> for ScreenPt { from(lp: winit::dpi::LogicalPosition<f64>) -> ScreenPt25 fn from(lp: winit::dpi::LogicalPosition<f64>) -> ScreenPt { 26 ScreenPt { x: lp.x, y: lp.y } 27 } 28 } 29 30 /// ScreenRectangle is in units of logical pixels, as opposed to physical pixels. 31 #[derive(Clone, Debug)] 32 pub struct ScreenRectangle { 33 pub x1: f64, 34 pub y1: f64, 35 pub x2: f64, 36 pub y2: f64, 37 } 38 39 impl ScreenRectangle { top_left(top_left: ScreenPt, dims: ScreenDims) -> ScreenRectangle40 pub fn top_left(top_left: ScreenPt, dims: ScreenDims) -> ScreenRectangle { 41 ScreenRectangle { 42 x1: top_left.x, 43 y1: top_left.y, 44 x2: top_left.x + dims.width, 45 y2: top_left.y + dims.height, 46 } 47 } 48 placeholder() -> ScreenRectangle49 pub fn placeholder() -> ScreenRectangle { 50 ScreenRectangle { 51 x1: 0.0, 52 y1: 0.0, 53 x2: 0.0, 54 y2: 0.0, 55 } 56 } 57 contains(&self, pt: ScreenPt) -> bool58 pub fn contains(&self, pt: ScreenPt) -> bool { 59 pt.x >= self.x1 && pt.x <= self.x2 && pt.y >= self.y1 && pt.y <= self.y2 60 } 61 pt_to_percent(&self, pt: ScreenPt) -> Option<(f64, f64)>62 pub fn pt_to_percent(&self, pt: ScreenPt) -> Option<(f64, f64)> { 63 if self.contains(pt) { 64 Some(( 65 (pt.x - self.x1) / self.width(), 66 (pt.y - self.y1) / self.height(), 67 )) 68 } else { 69 None 70 } 71 } percent_to_pt(&self, x: f64, y: f64) -> ScreenPt72 pub fn percent_to_pt(&self, x: f64, y: f64) -> ScreenPt { 73 ScreenPt::new(self.x1 + x * self.width(), self.y1 + y * self.height()) 74 } 75 76 // TODO Remove these in favor of dims() width(&self) -> f6477 pub fn width(&self) -> f64 { 78 self.x2 - self.x1 79 } 80 height(&self) -> f6481 pub fn height(&self) -> f64 { 82 self.y2 - self.y1 83 } 84 dims(&self) -> ScreenDims85 pub fn dims(&self) -> ScreenDims { 86 ScreenDims::new(self.x2 - self.x1, self.y2 - self.y1) 87 } 88 center(&self) -> ScreenPt89 pub fn center(&self) -> ScreenPt { 90 ScreenPt::new((self.x1 + self.x2) / 2.0, (self.y1 + self.y2) / 2.0) 91 } 92 to_polygon(&self) -> Polygon93 pub fn to_polygon(&self) -> Polygon { 94 Polygon::rectangle(self.width(), self.height()).translate(self.x1, self.y1) 95 } 96 } 97 98 /// ScreenDims is in units of logical pixels, as opposed to physical pixels. 99 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] 100 pub struct ScreenDims { 101 pub width: f64, 102 pub height: f64, 103 } 104 105 impl ScreenDims { new(width: f64, height: f64) -> ScreenDims106 pub fn new(width: f64, height: f64) -> ScreenDims { 107 ScreenDims { 108 width: trim_f64(width), 109 height: trim_f64(height), 110 } 111 } 112 top_left_for_corner(&self, corner: ScreenPt, canvas: &Canvas) -> ScreenPt113 pub fn top_left_for_corner(&self, corner: ScreenPt, canvas: &Canvas) -> ScreenPt { 114 // TODO Ideally also avoid covered canvas areas 115 if corner.x + self.width < canvas.window_width { 116 // corner.x is the left corner 117 if corner.y + self.height < canvas.window_height { 118 // corner.y is the top corner 119 corner 120 } else { 121 // corner.y is the bottom corner 122 ScreenPt::new(corner.x, corner.y - self.height) 123 } 124 } else { 125 // corner.x is the right corner 126 if corner.y + self.height < canvas.window_height { 127 // corner.y is the top corner 128 ScreenPt::new(corner.x - self.width, corner.y) 129 } else { 130 // corner.y is the bottom corner 131 ScreenPt::new(corner.x - self.width, corner.y - self.height) 132 } 133 } 134 } 135 scaled(&self, factor: f64) -> ScreenDims136 pub fn scaled(&self, factor: f64) -> ScreenDims { 137 ScreenDims::new(self.width * factor, self.height * factor) 138 } 139 } 140 141 impl From<winit::dpi::LogicalSize<f64>> for ScreenDims { from(size: winit::dpi::LogicalSize<f64>) -> ScreenDims142 fn from(size: winit::dpi::LogicalSize<f64>) -> ScreenDims { 143 ScreenDims { 144 width: size.width, 145 height: size.height, 146 } 147 } 148 } 149 150 impl From<ScreenDims> for winit::dpi::LogicalSize<f64> { from(dims: ScreenDims) -> winit::dpi::LogicalSize<f64>151 fn from(dims: ScreenDims) -> winit::dpi::LogicalSize<f64> { 152 winit::dpi::LogicalSize::new(dims.width, dims.height) 153 } 154 } 155