mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-25 00:58:12 +08:00
Snap overlays to device instead of UI pixels on web (#4281)
Snap overlays to physical instead of logical pixels on web
This commit is contained in:
@@ -230,10 +230,12 @@ impl OverlayContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.render_context.begin_path();
|
self.render_context.begin_path();
|
||||||
self.render_context.move_to(polygon.last().unwrap().x.round() - 0.5, polygon.last().unwrap().y.round() - 0.5);
|
let last = self.snap_to_physical_pixel_center(*polygon.last().unwrap());
|
||||||
|
self.render_context.move_to(last.x, last.y);
|
||||||
|
|
||||||
for point in polygon {
|
for point in polygon {
|
||||||
self.render_context.line_to(point.x.round() - 0.5, point.y.round() - 0.5);
|
let p = self.snap_to_physical_pixel_center(*point);
|
||||||
|
self.render_context.line_to(p.x, p.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(color_fill) = color_fill {
|
if let Some(color_fill) = color_fill {
|
||||||
@@ -286,8 +288,8 @@ impl OverlayContext {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
self.render_context.begin_path();
|
self.render_context.begin_path();
|
||||||
self.render_context.move_to(start.x, start.y);
|
self.render_context.move_to(start.x, start.y);
|
||||||
@@ -328,7 +330,7 @@ impl OverlayContext {
|
|||||||
dash_offset: Option<f64>,
|
dash_offset: Option<f64>,
|
||||||
) {
|
) {
|
||||||
let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);
|
let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);
|
||||||
let center = center.round();
|
let center = self.snap_to_physical_pixel(center);
|
||||||
|
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
|
|
||||||
@@ -397,7 +399,7 @@ impl OverlayContext {
|
|||||||
transform: Option<DAffine2>,
|
transform: Option<DAffine2>,
|
||||||
) {
|
) {
|
||||||
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);
|
||||||
|
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
|
|
||||||
@@ -455,7 +457,7 @@ impl OverlayContext {
|
|||||||
pub fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) {
|
pub fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) {
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
|
|
||||||
let position = position.round() - DVec2::splat(0.5);
|
let position = self.snap_to_physical_pixel_center(position);
|
||||||
|
|
||||||
self.render_context.begin_path();
|
self.render_context.begin_path();
|
||||||
self.render_context
|
self.render_context
|
||||||
@@ -553,7 +555,7 @@ impl OverlayContext {
|
|||||||
pub fn hover_manipulator_handle(&mut self, position: DVec2, selected: bool) {
|
pub fn hover_manipulator_handle(&mut self, position: DVec2, selected: bool) {
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
|
|
||||||
let position = position.round() - DVec2::splat(0.5);
|
let position = self.snap_to_physical_pixel_center(position);
|
||||||
|
|
||||||
self.render_context.begin_path();
|
self.render_context.begin_path();
|
||||||
self.render_context
|
self.render_context
|
||||||
@@ -622,7 +624,7 @@ impl OverlayContext {
|
|||||||
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.;
|
||||||
|
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
@@ -642,7 +644,7 @@ impl OverlayContext {
|
|||||||
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.;
|
||||||
|
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
@@ -727,7 +729,7 @@ impl OverlayContext {
|
|||||||
|
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
|
|
||||||
let center = compass_center.round() - DVec2::splat(0.5);
|
let center = self.snap_to_physical_pixel_center(compass_center);
|
||||||
|
|
||||||
// Save the old line width to restore it later
|
// Save the old line width to restore it later
|
||||||
let old_line_width = self.render_context.line_width();
|
let old_line_width = self.render_context.line_width();
|
||||||
@@ -781,7 +783,7 @@ impl OverlayContext {
|
|||||||
|
|
||||||
pub fn pivot(&mut self, position: DVec2, angle: f64) {
|
pub 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();
|
||||||
|
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
|
|
||||||
@@ -816,7 +818,7 @@ impl OverlayContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn dowel_pin(&mut self, position: DVec2, angle: f64, color: Option<&str>) {
|
pub 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);
|
||||||
|
|
||||||
self.start_dpi_aware_transform();
|
self.start_dpi_aware_transform();
|
||||||
@@ -941,29 +943,30 @@ impl OverlayContext {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
self.render_context.move_to(start_point.x, start_point.y);
|
self.render_context.move_to(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);
|
||||||
self.render_context.line_to(a.x, a.y);
|
self.render_context.line_to(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);
|
||||||
self.render_context.quadratic_curve_to(a.x, a.y, b.x, b.y);
|
self.render_context.quadratic_curve_to(a.x, a.y, 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);
|
||||||
self.render_context.bezier_curve_to(a.x, a.y, b.x, b.y, c.x, c.y);
|
self.render_context.bezier_curve_to(a.x, a.y, b.x, b.y, c.x, c.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1110,6 +1113,22 @@ impl OverlayContext {
|
|||||||
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Pivot {
|
pub enum Pivot {
|
||||||
|
|||||||
Reference in New Issue
Block a user