mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-27 20:06:53 -06:00
#881: keep fixed grids at width 0 drawing bands as before (no hairlines)
This commit is contained in:
@@ -1189,10 +1189,7 @@ pub enum GridAlign {
|
||||
#[serde(default)]
|
||||
pub struct LayoutGrid {
|
||||
pub kind: GridKind,
|
||||
/// Grid: cell size. Fixed (not stretched) columns/rows: their width/height. 0 (or Auto) draws
|
||||
/// a one-pixel hairline at each band's start, like the square grid, and the bands step by
|
||||
/// `gutter` alone (there is no width to add); a positive value draws a band that many document
|
||||
/// units wide. A stretched grid works its bands out from the frame and ignores `size`.
|
||||
/// Grid: cell size. Fixed (not stretched) columns/rows: their width/height.
|
||||
pub size: f64,
|
||||
/// Columns/rows: how many (0: Auto, as many fixed-size ones as fit; a stretched grid has 1).
|
||||
pub count: u32,
|
||||
|
||||
@@ -1047,17 +1047,12 @@ pub fn grid_lines(g: &LayoutGrid, w: f64, h: f64) -> Vec<Rect> {
|
||||
let total = if cols { w } else { h };
|
||||
let gutter = if g.gutter.is_finite() { g.gutter.max(0.0) } else { 0.0 };
|
||||
let offset = if g.offset.is_finite() { g.offset.max(0.0) } else { 0.0 };
|
||||
// Auto width (size 0, a non-stretched grid) draws a one-pixel hairline at the band's
|
||||
// start, like the square grid; otherwise a filled band of `size`. Auto has no width of
|
||||
// its own, so the gutter alone is the step between the lines.
|
||||
let auto = g.size <= 0.0 && g.align != GridAlign::Stretch;
|
||||
let fixed = if g.size.is_finite() && g.size > 0.0 { g.size } else { 0.0 };
|
||||
let count = match g.count {
|
||||
// Auto: as many fixed-size columns (rows) as fit in the room the type leaves them.
|
||||
0 if g.align != GridAlign::Stretch => {
|
||||
let size = if g.size.is_finite() && g.size > 0.0 { g.size } else { 60.0 };
|
||||
let room = if g.align == GridAlign::Center { total } else { total - offset };
|
||||
let step = fixed + gutter;
|
||||
if step > 0.0 { ((room + gutter) / step).floor().clamp(1.0, 500.0) as usize } else { 1 }
|
||||
((room + gutter) / (size + gutter)).floor().clamp(1.0, 500.0) as usize
|
||||
}
|
||||
n => n.clamp(1, 500) as usize,
|
||||
};
|
||||
@@ -1067,7 +1062,7 @@ pub fn grid_lines(g: &LayoutGrid, w: f64, h: f64) -> Vec<Rect> {
|
||||
(offset, size)
|
||||
}
|
||||
_ => {
|
||||
let size = fixed;
|
||||
let size = if g.size.is_finite() && g.size > 0.0 { g.size } else { 60.0 };
|
||||
let span = size * count as f64 + gutter * (count - 1) as f64;
|
||||
let start = match g.align {
|
||||
GridAlign::Min => offset,
|
||||
@@ -1079,12 +1074,7 @@ pub fn grid_lines(g: &LayoutGrid, w: f64, h: f64) -> Vec<Rect> {
|
||||
};
|
||||
for i in 0..count {
|
||||
let a = start + i as f64 * (size + gutter);
|
||||
if auto {
|
||||
// A one-pixel hairline where the band would start (the square grid's lines).
|
||||
out.push(if cols { Rect::new(a, 0.0, a, h) } else { Rect::new(0.0, a, w, a) });
|
||||
} else {
|
||||
out.push(if cols { Rect::new(a, 0.0, a + size, h) } else { Rect::new(0.0, a, w, a + size) });
|
||||
}
|
||||
out.push(if cols { Rect::new(a, 0.0, a + size, h) } else { Rect::new(0.0, a, w, a + size) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1114,16 +1104,11 @@ pub fn grid_snap_lines_in(doc: &Document, frame: NodeId, xf: Affine) -> (Vec<f64
|
||||
match g.kind {
|
||||
GridKind::Columns => {
|
||||
xs.push(a.x);
|
||||
// An Auto-width band is one line, not an edge pair.
|
||||
if (b.x - a.x).abs() > 1e-9 {
|
||||
xs.push(b.x);
|
||||
}
|
||||
xs.push(b.x);
|
||||
}
|
||||
GridKind::Rows => {
|
||||
ys.push(a.y);
|
||||
if (b.y - a.y).abs() > 1e-9 {
|
||||
ys.push(b.y);
|
||||
}
|
||||
ys.push(b.y);
|
||||
}
|
||||
GridKind::Grid => {
|
||||
if (r.x0 - r.x1).abs() < 1e-9 {
|
||||
|
||||
@@ -447,41 +447,3 @@ fn grid_hostile_values() {
|
||||
assert!(x.is_finite() && y.is_finite() && w.is_finite() && h.is_finite());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grid_lines_auto_width_columns_rows_hairline() {
|
||||
// Columns with Auto width (size 0, non-stretched) draw one-pixel hairlines at each band's
|
||||
// start, like the square grid; a set width draws filled bands.
|
||||
let g = LayoutGrid { kind: GridKind::Columns, align: GridAlign::Min, count: 3, size: 0.0, gutter: 10.0, offset: 0.0, ..LayoutGrid::default() };
|
||||
let lines = grid_lines(&g, 300.0, 50.0);
|
||||
assert_eq!(lines.len(), 3, "three hairlines");
|
||||
for r in &lines {
|
||||
assert!((r.x0 - r.x1).abs() < 1e-9 && (r.y0 - r.y1).abs() > 1.0, "a vertical hairline: {r:?}");
|
||||
}
|
||||
// Auto has no width of its own, so the gutter alone is the step between the lines (no band
|
||||
// width hidden in it).
|
||||
let xs: Vec<f64> = lines.iter().map(|r| r.x0).collect();
|
||||
assert_eq!(xs, [0.0, 10.0, 20.0], "Auto steps by the gutter: {xs:?}");
|
||||
// Auto count: as many hairlines as the gutter fits.
|
||||
let g = LayoutGrid { kind: GridKind::Columns, align: GridAlign::Min, count: 0, size: 0.0, gutter: 10.0, offset: 0.0, ..LayoutGrid::default() };
|
||||
let lines = grid_lines(&g, 300.0, 50.0);
|
||||
assert_eq!(lines.len(), 31, "300 wide, 10 apart: 31 lines");
|
||||
// A positive width draws filled bands again.
|
||||
let g = LayoutGrid { kind: GridKind::Columns, align: GridAlign::Min, count: 3, size: 8.0, gutter: 10.0, offset: 0.0, ..LayoutGrid::default() };
|
||||
let lines = grid_lines(&g, 300.0, 50.0);
|
||||
assert!(lines.iter().all(|r| (r.x1 - r.x0).abs() > 1e-9), "a set width draws bands");
|
||||
|
||||
// Rows Auto width: horizontal hairlines.
|
||||
let g = LayoutGrid { kind: GridKind::Rows, align: GridAlign::Min, count: 2, size: 0.0, gutter: 10.0, offset: 0.0, ..LayoutGrid::default() };
|
||||
let lines = grid_lines(&g, 50.0, 200.0);
|
||||
assert_eq!(lines.len(), 2, "two hairlines");
|
||||
for r in &lines {
|
||||
assert!((r.y0 - r.y1).abs() < 1e-9 && (r.x0 - r.x1).abs() > 1.0, "a horizontal hairline: {r:?}");
|
||||
}
|
||||
// A stretched grid works its bands out from the frame whatever its width says.
|
||||
let g =
|
||||
LayoutGrid { kind: GridKind::Columns, align: GridAlign::Stretch, count: 4, size: 0.0, gutter: 10.0, offset: 0.0, ..LayoutGrid::default() };
|
||||
let lines = grid_lines(&g, 400.0, 50.0);
|
||||
assert!(lines.iter().all(|r| (r.x1 - r.x0) > 1.0), "stretch draws bands, not hairlines: {lines:?}");
|
||||
assert!((lines[0].x0 - 0.0).abs() < 1e-9 && (lines[3].x1 - 400.0).abs() < 1e-9, "the bands fill the frame");
|
||||
}
|
||||
|
||||
@@ -923,12 +923,7 @@ fn overlays(app: &FigApp, painter: &egui::Painter, t: &Tokens) -> Vec<(NodeId, [
|
||||
let a = w * Point::new(r.x0, r.y0);
|
||||
let b = w * Point::new(r.x1, r.y1);
|
||||
let (sa, sb) = (app.to_screen(a.x, a.y), app.to_screen(b.x, b.y));
|
||||
// The square grid and an Auto-width line draw one-pixel hairlines; a filled
|
||||
// band (a column/row with a set width) is painted as a rectangle.
|
||||
if g.kind == figcraft_doc::GridKind::Grid
|
||||
|| (r.x0 - r.x1).abs() < 1e-9
|
||||
|| (r.y0 - r.y1).abs() < 1e-9
|
||||
{
|
||||
if g.kind == figcraft_doc::GridKind::Grid {
|
||||
painter.line_segment([sa, sb], stroke(col, 1.0));
|
||||
} else {
|
||||
painter.rect_filled(Rect::from_two_pos(sa, sb), CornerRadius::ZERO, col);
|
||||
|
||||
Reference in New Issue
Block a user