mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-01 13:47:21 -06:00
Fix #3826: the toolbar's Gradient chip lines up with Color and None
Filled rectangles are drawn on whole pixels, but the gradient chip is a mesh, which was drawn at its exact position. At a fractional position or display scale the Gradient button under the Fill/Stroke proxy sat up to half a pixel off the Color and None buttons beside it. gradient_chip now rounds its rect to pixels first, which also lines it up wherever else a gradient chip sits next to a color chip.
This commit is contained in:
@@ -509,6 +509,43 @@ mod gradient_chip_tests {
|
||||
assert_eq!(colors[2 * 5 + 2], Color32::WHITE);
|
||||
assert_eq!(colors[0], Color32::BLACK);
|
||||
}
|
||||
|
||||
/// At a position and display scale that fall between pixels, the gradient chip covers the same
|
||||
/// pixel rows as a colour or None chip beside it (#3826). Filled rectangles are drawn on whole
|
||||
/// pixels, so the toolbar's Gradient button sat up to half a pixel off its neighbors.
|
||||
#[test]
|
||||
fn gradient_chip_lines_up_with_a_solid_chip() {
|
||||
let ctx = egui::Context::default();
|
||||
ctx.set_pixels_per_point(1.5);
|
||||
// Without anti-aliasing, a filled rectangle's mesh is exactly the rectangle it fills.
|
||||
ctx.tessellation_options_mut(|o| o.feathering = false);
|
||||
let chip = |x: f32| Rect::from_min_size(pos2(x, 40.3), vec2(11.0, 11.0));
|
||||
let mut shapes = Vec::new();
|
||||
for _ in 0..2 {
|
||||
let mut out = ctx.run_ui(egui::RawInput::default(), |ui| {
|
||||
paint_chip(ui, chip(10.2), &Paint::solid(Color::BLACK));
|
||||
gradient_chip(ui, chip(23.2), &paint(GradientKind::Linear, 0.0));
|
||||
});
|
||||
out.textures_delta.clear();
|
||||
assert_eq!(out.pixels_per_point, 1.5);
|
||||
shapes = out.shapes;
|
||||
}
|
||||
let bounds = |shape: egui::epaint::ClippedShape| {
|
||||
let mut r = Rect::NOTHING;
|
||||
for p in ctx.tessellate(vec![shape], 1.5) {
|
||||
if let egui::epaint::Primitive::Mesh(m) = p.primitive {
|
||||
m.vertices.iter().for_each(|v| r.extend_with(v.pos));
|
||||
}
|
||||
}
|
||||
r
|
||||
};
|
||||
let n = shapes.len();
|
||||
assert!(n >= 2, "{n} shapes");
|
||||
let gradient = bounds(shapes.remove(n - 1));
|
||||
let solid = bounds(shapes.remove(n - 2));
|
||||
assert_eq!((gradient.top(), gradient.bottom()), (solid.top(), solid.bottom()), "gradient {gradient:?}, solid {solid:?}");
|
||||
assert_eq!(gradient, egui::emath::GuiRounding::round_to_pixels(chip(23.2), 1.5));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -25,8 +25,11 @@ pub fn paint_chip(ui: &Ui, rect: Rect, paint: &Paint) {
|
||||
}
|
||||
|
||||
/// Draw a gradient preview into `rect`, laid out as the gradient would be on an object of that
|
||||
/// shape: linear along its angle, radial from the centre, freeform from its colour points.
|
||||
/// shape: linear along its angle, radial from the centre, freeform from its colour points. The
|
||||
/// rect is rounded to whole pixels, as filled rectangles are when drawn, so the chip lines up with
|
||||
/// a colour chip beside it (#3826).
|
||||
pub fn gradient_chip(ui: &Ui, rect: Rect, gradient: &vectorcraft_color::GradientPaint) {
|
||||
let rect = egui::emath::GuiRounding::round_to_pixels(rect, ui.pixels_per_point());
|
||||
if !(rect.width() > 0.0 && rect.height() > 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user