Desktop: Snap overlays to physical instead of logical pixels (#3493)
WIP
This commit is contained in:
parent
c7e3d01e2b
commit
9c56c852ca
|
|
@ -491,11 +491,13 @@ impl OverlayContextInternal {
|
||||||
|
|
||||||
let mut path = BezPath::new();
|
let mut path = BezPath::new();
|
||||||
if let Some(first) = polygon.last() {
|
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 {
|
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();
|
path.close_path();
|
||||||
|
|
||||||
|
|
@ -522,8 +524,8 @@ impl OverlayContextInternal {
|
||||||
fn dashed_line(&mut self, start: DVec2, end: DVec2, color: Option<&str>, thickness: Option<f64>, dash_width: Option<f64>, dash_gap_width: Option<f64>, dash_offset: Option<f64>) {
|
fn dashed_line(&mut self, start: DVec2, end: DVec2, color: Option<&str>, thickness: Option<f64>, dash_width: Option<f64>, dash_gap_width: Option<f64>, dash_offset: Option<f64>) {
|
||||||
let transform = self.get_transform();
|
let transform = self.get_transform();
|
||||||
|
|
||||||
let start = start.round() - DVec2::splat(0.5);
|
let start = self.snap_to_physical_pixel_center(start);
|
||||||
let end = end.round() - DVec2::splat(0.5);
|
let end = self.snap_to_physical_pixel_center(end);
|
||||||
|
|
||||||
let mut path = BezPath::new();
|
let mut path = BezPath::new();
|
||||||
path.move_to(kurbo::Point::new(start.x, start.y));
|
path.move_to(kurbo::Point::new(start.x, start.y));
|
||||||
|
|
@ -541,7 +543,7 @@ impl OverlayContextInternal {
|
||||||
|
|
||||||
fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) {
|
fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) {
|
||||||
let transform = self.get_transform();
|
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.);
|
let circle = kurbo::Circle::new((position.x, position.y), MANIPULATOR_GROUP_MARKER_SIZE / 2.);
|
||||||
|
|
||||||
|
|
@ -554,8 +556,7 @@ impl OverlayContextInternal {
|
||||||
|
|
||||||
fn hover_manipulator_handle(&mut self, position: DVec2, selected: bool) {
|
fn hover_manipulator_handle(&mut self, position: DVec2, selected: bool) {
|
||||||
let transform = self.get_transform();
|
let transform = self.get_transform();
|
||||||
|
let position = self.snap_to_physical_pixel_center(position);
|
||||||
let position = position.round() - DVec2::splat(0.5);
|
|
||||||
|
|
||||||
let circle = kurbo::Circle::new((position.x, position.y), (MANIPULATOR_GROUP_MARKER_SIZE + 2.) / 2.);
|
let circle = kurbo::Circle::new((position.x, position.y), (MANIPULATOR_GROUP_MARKER_SIZE + 2.) / 2.);
|
||||||
|
|
||||||
|
|
@ -605,7 +606,7 @@ impl OverlayContextInternal {
|
||||||
let color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE);
|
let color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE);
|
||||||
let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);
|
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 corner = position - DVec2::splat(size) / 2.;
|
||||||
|
|
||||||
let transform = self.get_transform();
|
let transform = self.get_transform();
|
||||||
|
|
@ -620,7 +621,7 @@ impl OverlayContextInternal {
|
||||||
let size = 1.;
|
let size = 1.;
|
||||||
let color_fill = color.unwrap_or(COLOR_OVERLAY_WHITE);
|
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 corner = position - DVec2::splat(size) / 2.;
|
||||||
|
|
||||||
let transform = self.get_transform();
|
let transform = self.get_transform();
|
||||||
|
|
@ -632,7 +633,7 @@ impl OverlayContextInternal {
|
||||||
fn circle(&mut self, position: DVec2, radius: f64, color_fill: Option<&str>, color_stroke: Option<&str>) {
|
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_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE);
|
||||||
let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);
|
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 transform = self.get_transform();
|
||||||
let circle = kurbo::Circle::new((position.x, position.y), radius);
|
let circle = kurbo::Circle::new((position.x, position.y), radius);
|
||||||
|
|
@ -708,7 +709,7 @@ impl OverlayContextInternal {
|
||||||
self.draw_arc(pivot, arc_radius, offset_angle, (angle) % TAU + offset_angle);
|
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 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();
|
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, '#');
|
fill_color.insert(0, '#');
|
||||||
|
|
@ -739,7 +740,7 @@ impl OverlayContextInternal {
|
||||||
let Some(show_hover_ring) = show_compass_with_hover_ring else { return };
|
let Some(show_hover_ring) = show_compass_with_hover_ring else { return };
|
||||||
|
|
||||||
let transform = self.get_transform();
|
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
|
// Hover ring
|
||||||
if show_hover_ring {
|
if show_hover_ring {
|
||||||
|
|
@ -784,7 +785,7 @@ impl OverlayContextInternal {
|
||||||
|
|
||||||
fn pivot(&mut self, position: DVec2, angle: f64) {
|
fn pivot(&mut self, position: DVec2, angle: f64) {
|
||||||
let uv = DVec2::from_angle(angle);
|
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();
|
let transform = self.get_transform();
|
||||||
|
|
||||||
|
|
@ -814,7 +815,7 @@ impl OverlayContextInternal {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dowel_pin(&mut self, position: DVec2, angle: f64, color: Option<&str>) {
|
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 color = color.unwrap_or(COLOR_OVERLAY_YELLOW_DULL);
|
||||||
|
|
||||||
let transform = self.get_transform();
|
let transform = self.get_transform();
|
||||||
|
|
@ -921,29 +922,30 @@ impl OverlayContextInternal {
|
||||||
};
|
};
|
||||||
|
|
||||||
let start_point = transform.transform_point2(point_to_dvec2(first.start()));
|
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));
|
path.move_to(kurbo::Point::new(start_point.x, start_point.y));
|
||||||
|
|
||||||
for curve in curves {
|
for curve in curves {
|
||||||
match curve {
|
match curve {
|
||||||
PathSeg::Line(line) => {
|
PathSeg::Line(line) => {
|
||||||
let a = transform.transform_point2(point_to_dvec2(line.p1));
|
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));
|
path.line_to(kurbo::Point::new(a.x, a.y));
|
||||||
}
|
}
|
||||||
PathSeg::Quad(quad_bez) => {
|
PathSeg::Quad(quad_bez) => {
|
||||||
let a = transform.transform_point2(point_to_dvec2(quad_bez.p1));
|
let a = transform.transform_point2(point_to_dvec2(quad_bez.p1));
|
||||||
let b = transform.transform_point2(point_to_dvec2(quad_bez.p2));
|
let b = transform.transform_point2(point_to_dvec2(quad_bez.p2));
|
||||||
let a = a.round() - DVec2::splat(0.5);
|
let a = self.snap_to_physical_pixel_center(a);
|
||||||
let b = b.round() - DVec2::splat(0.5);
|
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));
|
path.quad_to(kurbo::Point::new(a.x, a.y), kurbo::Point::new(b.x, b.y));
|
||||||
}
|
}
|
||||||
PathSeg::Cubic(cubic_bez) => {
|
PathSeg::Cubic(cubic_bez) => {
|
||||||
let a = transform.transform_point2(point_to_dvec2(cubic_bez.p1));
|
let a = transform.transform_point2(point_to_dvec2(cubic_bez.p1));
|
||||||
let b = transform.transform_point2(point_to_dvec2(cubic_bez.p2));
|
let b = transform.transform_point2(point_to_dvec2(cubic_bez.p2));
|
||||||
let c = transform.transform_point2(point_to_dvec2(cubic_bez.p3));
|
let c = transform.transform_point2(point_to_dvec2(cubic_bez.p3));
|
||||||
let a = a.round() - DVec2::splat(0.5);
|
let a = self.snap_to_physical_pixel_center(a);
|
||||||
let b = b.round() - DVec2::splat(0.5);
|
let b = self.snap_to_physical_pixel_center(b);
|
||||||
let c = c.round() - DVec2::splat(0.5);
|
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));
|
path.curve_to(kurbo::Point::new(a.x, a.y), kurbo::Point::new(b.x, b.y), kurbo::Point::new(c.x, c.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1145,4 +1147,20 @@ impl OverlayContextInternal {
|
||||||
self.line(quad.bottom_left(), quad.bottom_right(), None, None);
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue