vectorcraft/crates/ui-egui/src/tests_docsetup.rs

110 lines
5.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! The canvas draws Document Setup: the red bleed outline and the transparency grid in the
//! document's colours and cell size, also in a rotated view; a white Background Contents hides
//! the grid and Simulate Colored Paper tints the artboard.
use serde_json::json;
use vectorcraft_engine::Session;
use crate::theme::Tokens;
use crate::{VectorcraftApp, canvas};
/// One headless canvas frame: its shapes, the transparency grid tile uploaded in it (2 × 2
/// pixels: the grid colours) and the grid mesh, if any.
fn frame(app: &mut VectorcraftApp) -> (Vec<egui::Shape>, Option<Vec<egui::Color32>>, Option<egui::Mesh>) {
let ctx = egui::Context::default();
let raw = egui::RawInput { screen_rect: Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(800.0, 600.0))), ..Default::default() };
let mut out = ctx.run_ui(raw, |ui| canvas::show(app, ui));
let tile = ctx.tex_manager().read().allocated().find(|(_, m)| m.name == canvas::TRANSPARENCY_GRID).map(|(id, _)| *id);
let pixels = tile.and_then(|id| out.textures_delta.set.iter().find(|(t, _)| **t == id)).and_then(|(_, deltas)| match &deltas.first()?.image {
egui::ImageData::Color(img) => Some(img.pixels.clone()),
});
out.textures_delta.clear();
let shapes: Vec<egui::Shape> = out.shapes.into_iter().map(|c| c.shape).collect();
let mut all = vec![];
flatten(&shapes, &mut all);
let mesh = all.into_iter().find_map(|s| match s {
egui::Shape::Mesh(m) if Some(m.texture_id) == tile => Some((*m).clone()),
_ => None,
});
(shapes, pixels, mesh)
}
fn flatten(shapes: &[egui::Shape], out: &mut Vec<egui::Shape>) {
for s in shapes {
match s {
egui::Shape::Vec(v) => flatten(v, out),
s => out.push(s.clone()),
}
}
}
/// The closed outlines drawn in `color`: their corner points.
fn outlines(shapes: &[egui::Shape], color: egui::Color32) -> Vec<Vec<egui::Pos2>> {
let mut all = vec![];
flatten(shapes, &mut all);
all.into_iter()
.filter_map(|s| match s {
egui::Shape::Path(p) if p.closed && p.stroke.color == egui::epaint::ColorMode::Solid(color) => Some(p.points),
_ => None,
})
.collect()
}
fn app() -> VectorcraftApp {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 100})).unwrap();
app
}
#[test]
fn the_bleed_draws_as_a_red_outline_around_each_artboard() {
let mut app = app();
let red = Tokens::for_brightness(Default::default()).bleed;
assert!(outlines(&frame(&mut app).0, red).is_empty(), "no bleed, no outline");
app.run("document.setup", json!({"bleed": [10, 10, 20, 20]})).unwrap();
let (shapes, _, _) = frame(&mut app);
let found = outlines(&shapes, red);
assert_eq!(found.len(), 1);
// The artboard is 200 × 100 pt; the bleed grows it by 40 × 20 pt at the fitted zoom.
let ab = outlines(&shapes, egui::Color32::from_gray(0)).into_iter().next().unwrap();
let span = |q: &[egui::Pos2]| (q[2].x - q[0].x, q[2].y - q[0].y);
let ((bw, bh), (aw, ah)) = (span(&found[0]), span(&ab));
let zoom = aw / 200.0;
assert!((bw - 240.0 * zoom).abs() < 0.5 && (bh - 120.0 * zoom).abs() < 0.5 && (ah - 100.0 * zoom).abs() < 0.5, "{found:?} {ab:?}");
// A rotated view turns the outline with the artboard.
app.view_mut().unwrap().rotation = 30.0;
let q = &outlines(&frame(&mut app).0, red)[0];
assert!((q[1].y - q[0].y).abs() > 10.0, "the top edge is no longer horizontal: {q:?}");
}
#[test]
fn the_grid_takes_the_document_colours_also_rotated() {
let mut app = app();
app.run("view.transparencyGrid", json!({"on": true})).unwrap();
app.run("document.setup", json!({"gridColors": ["#ff0000", "#0000ff"], "gridSize": "large"})).unwrap();
let (_, tile, _) = frame(&mut app);
let (red, blue) = (egui::Color32::from_rgb(255, 0, 0), egui::Color32::from_rgb(0, 0, 255));
assert_eq!(tile, Some(vec![red, blue, blue, red]));
// Rotated: still one textured mesh over the artboard's turned corners.
app.view_mut().unwrap().rotation = 45.0;
let m = frame(&mut app).2.expect("the grid mesh");
assert!((m.vertices[1].pos.y - m.vertices[0].pos.y).abs() > 10.0);
// Large cells are 16 screen points: the 200 pt artboard spans 200 × zoom / 32 tile repeats.
let zoom = app.view_mut().unwrap().zoom as f32;
assert!((m.vertices[1].uv.x - 200.0 * zoom / 32.0).abs() < 1e-3, "{:?}", m.vertices[1].uv);
}
#[test]
fn white_background_hides_the_grid_and_paper_tints_the_artboard() {
let mut app = app();
app.run("view.transparencyGrid", json!({"on": true})).unwrap();
app.run("document.setup", json!({"backgroundContents": "white"})).unwrap();
assert!(frame(&mut app).2.is_none());
app.run("view.transparencyGrid", json!({"on": false})).unwrap();
app.run("document.setup", json!({"simulatePaper": true, "gridColors": ["#ffeecc", "#cccccc"]})).unwrap();
let mut all = vec![];
flatten(&frame(&mut app).0, &mut all);
let paper = egui::Color32::from_rgb(0xff, 0xee, 0xcc);
assert!(all.iter().any(|s| matches!(s, egui::Shape::Path(p) if p.fill == paper)), "the artboard shows the paper colour");
}