From f992a2feb04448003e19813241c5ac174c94ba2b Mon Sep 17 00:00:00 2001 From: Timon Schelling Date: Thu, 18 Dec 2025 12:53:02 +0000 Subject: [PATCH] WIP --- .../document/overlays/utility_types_native.rs | 58 ++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/editor/src/messages/portfolio/document/overlays/utility_types_native.rs b/editor/src/messages/portfolio/document/overlays/utility_types_native.rs index 1e86778fb9..b087ec912a 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types_native.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types_native.rs @@ -476,11 +476,13 @@ impl OverlayContextInternal { let mut path = BezPath::new(); if let Some(first) = polygon.last() { - path.move_to(kurbo::Point::new(first.x.round() - 0.5, first.y.round() - 0.5)); + let p = self.snap_to_physical_pixel_center(*first); + path.move_to(kurbo::Point::new(p.x, p.y)); } for point in polygon { - path.line_to(kurbo::Point::new(point.x.round() - 0.5, point.y.round() - 0.5)); + let p = self.snap_to_physical_pixel_center(*point); + path.line_to(kurbo::Point::new(p.x, p.y)); } path.close_path(); @@ -507,8 +509,8 @@ impl OverlayContextInternal { fn dashed_line(&mut self, start: DVec2, end: DVec2, color: Option<&str>, thickness: Option, dash_width: Option, dash_gap_width: Option, dash_offset: Option) { let transform = self.get_transform(); - let start = start.round() - DVec2::splat(0.5); - let end = end.round() - DVec2::splat(0.5); + let start = self.snap_to_physical_pixel_center(start); + let end = self.snap_to_physical_pixel_center(end); let mut path = BezPath::new(); path.move_to(kurbo::Point::new(start.x, start.y)); @@ -526,7 +528,7 @@ impl OverlayContextInternal { fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) { let transform = self.get_transform(); - let position = position.round() - DVec2::splat(0.5); + let position = self.snap_to_physical_pixel_center(position); let circle = kurbo::Circle::new((position.x, position.y), MANIPULATOR_GROUP_MARKER_SIZE / 2.); @@ -539,8 +541,7 @@ impl OverlayContextInternal { fn hover_manipulator_handle(&mut self, position: DVec2, selected: bool) { let transform = self.get_transform(); - - let position = position.round() - DVec2::splat(0.5); + let position = self.snap_to_physical_pixel_center(position); let circle = kurbo::Circle::new((position.x, position.y), (MANIPULATOR_GROUP_MARKER_SIZE + 2.) / 2.); @@ -590,7 +591,7 @@ impl OverlayContextInternal { let color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE); let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE); - let position = position.round() - DVec2::splat(0.5); + let position = self.snap_to_physical_pixel_center(position); let corner = position - DVec2::splat(size) / 2.; let transform = self.get_transform(); @@ -605,7 +606,7 @@ impl OverlayContextInternal { let size = 1.; let color_fill = color.unwrap_or(COLOR_OVERLAY_WHITE); - let position = position.round() - DVec2::splat(0.5); + let position = self.snap_to_physical_pixel_center(position); let corner = position - DVec2::splat(size) / 2.; let transform = self.get_transform(); @@ -617,7 +618,7 @@ impl OverlayContextInternal { fn circle(&mut self, position: DVec2, radius: f64, color_fill: Option<&str>, color_stroke: Option<&str>) { let color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE); let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE); - let position = position.round(); + let position = self.snap_to_physical_pixel(position); let transform = self.get_transform(); let circle = kurbo::Circle::new((position.x, position.y), radius); @@ -693,7 +694,7 @@ impl OverlayContextInternal { self.draw_arc(pivot, arc_radius, offset_angle, (angle) % TAU + offset_angle); } - fn draw_scale(&mut self, start: DVec2, scale: f64, radius: f64, text: &str) { + pub fn draw_scale(&mut self, start: DVec2, scale: f64, radius: f64, text: &str) { let sign = scale.signum(); let mut fill_color = Color::from_rgb_str(COLOR_OVERLAY_WHITE.strip_prefix('#').unwrap()).unwrap().with_alpha(0.05).to_rgba_hex_srgb(); fill_color.insert(0, '#'); @@ -724,7 +725,7 @@ impl OverlayContextInternal { let Some(show_hover_ring) = show_compass_with_hover_ring else { return }; let transform = self.get_transform(); - let center = compass_center.round() - DVec2::splat(0.5); + let center = self.snap_to_physical_pixel_center(compass_center); // Hover ring if show_hover_ring { @@ -769,7 +770,7 @@ impl OverlayContextInternal { fn pivot(&mut self, position: DVec2, angle: f64) { let uv = DVec2::from_angle(angle); - let (x, y) = (position.round() - DVec2::splat(0.5)).into(); + let (x, y) = self.snap_to_physical_pixel_center(position).into(); let transform = self.get_transform(); @@ -799,7 +800,7 @@ impl OverlayContextInternal { } fn dowel_pin(&mut self, position: DVec2, angle: f64, color: Option<&str>) { - let (x, y) = (position.round() - DVec2::splat(0.5)).into(); + let (x, y) = self.snap_to_physical_pixel_center(position).into(); let color = color.unwrap_or(COLOR_OVERLAY_YELLOW_DULL); let transform = self.get_transform(); @@ -906,29 +907,30 @@ impl OverlayContextInternal { }; let start_point = transform.transform_point2(point_to_dvec2(first.start())); + let start_point = self.snap_to_physical_pixel(start_point); path.move_to(kurbo::Point::new(start_point.x, start_point.y)); for curve in curves { match curve { PathSeg::Line(line) => { let a = transform.transform_point2(point_to_dvec2(line.p1)); - let a = a.round() - DVec2::splat(0.5); + let a = self.snap_to_physical_pixel_center(a); path.line_to(kurbo::Point::new(a.x, a.y)); } PathSeg::Quad(quad_bez) => { let a = transform.transform_point2(point_to_dvec2(quad_bez.p1)); let b = transform.transform_point2(point_to_dvec2(quad_bez.p2)); - let a = a.round() - DVec2::splat(0.5); - let b = b.round() - DVec2::splat(0.5); + let a = self.snap_to_physical_pixel_center(a); + let b = self.snap_to_physical_pixel_center(b); path.quad_to(kurbo::Point::new(a.x, a.y), kurbo::Point::new(b.x, b.y)); } PathSeg::Cubic(cubic_bez) => { let a = transform.transform_point2(point_to_dvec2(cubic_bez.p1)); let b = transform.transform_point2(point_to_dvec2(cubic_bez.p2)); let c = transform.transform_point2(point_to_dvec2(cubic_bez.p3)); - let a = a.round() - DVec2::splat(0.5); - let b = b.round() - DVec2::splat(0.5); - let c = c.round() - DVec2::splat(0.5); + let a = self.snap_to_physical_pixel_center(a); + let b = self.snap_to_physical_pixel_center(b); + let c = self.snap_to_physical_pixel_center(c); path.curve_to(kurbo::Point::new(a.x, a.y), kurbo::Point::new(b.x, b.y), kurbo::Point::new(c.x, c.y)); } } @@ -1130,4 +1132,20 @@ impl OverlayContextInternal { self.line(quad.bottom_left(), quad.bottom_right(), None, None); } } + + fn snap_to_physical_pixel(&self, p: DVec2) -> DVec2 { + let s = self.viewport.scale(); + if !s.is_finite() || s <= 0.0 { + return p.round(); + } + (p * s).round() / s + } + + fn snap_to_physical_pixel_center(&self, p: DVec2) -> DVec2 { + let s = self.viewport.scale(); + if !s.is_finite() || s <= 0.0 { + return p.round() - DVec2::splat(0.5); + } + self.snap_to_physical_pixel(p) - DVec2::splat(0.5 / s) + } }