mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-27 11:56:50 -06:00
- Min/max width/height: the W/H sizing menus add min/max (at the current size) and remove them;
limit rows edit or add the missing bound. The layout clamps Fixed, Hug and Fill children and
the frame itself; a hugging text wider than its max width wraps at the max. min > max is kept
ordered by node.set (the other bound follows); in the layout min wins.
- Ignore auto layout (absolute position): a toggle in the Position section; the child stays
where it is, can't Fill, shows constraints and follows them when the auto layout frame resizes
(by hugging, filling or a direct resize).
- Text baseline alignment for horizontal layouts ("Align text baselines"; crossAlign baseline):
first-line baselines line up, other layers align to the top, nested auto layout frames use
their first child's baseline. Measure gains text_baseline.
- Grid auto layout: column/row tracks (fixed px, hug, fr fill) via columnTracks / rowTracks or
layout.setTrack, cells anchored by gridColumn / gridRow with gridColumnSpan / gridRowSpan,
auto placement in reading order, rows grow to fit, hugging grids size to their tracks.
Panel: column/row gap, track size rows, a child's cell and spans. Old files load unchanged
(serde defaults; missing tracks are 1fr).
- Canvas handles: wrapped-row gaps and grid column/row gaps are draggable; a selected grid's
tracks are outlined.
- The layout section moved from right.rs to layout_panel.rs; inspect reports min/max and a
grid child's resolved gridCell; docs list the new props.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
35 lines
1.4 KiB
Rust
35 lines
1.4 KiB
Rust
//! Text measurement for the layout engine.
|
|
|
|
use figcraft_doc::{Document, NodeId, NodeKind, TextAutoResize};
|
|
|
|
pub struct TextMeasure;
|
|
|
|
impl figcraft_layout::Measure for TextMeasure {
|
|
fn text_height(&self, doc: &Document, id: NodeId, width: f64) -> Option<f64> {
|
|
let n = doc.node(id)?;
|
|
let NodeKind::Text(t) = &n.kind else { return None };
|
|
let mut t = t.clone();
|
|
if t.auto_resize == TextAutoResize::WidthAndHeight {
|
|
t.auto_resize = TextAutoResize::Height;
|
|
}
|
|
Some(figcraft_text::layout(&t, Some(width), None).height.max(1.0))
|
|
}
|
|
fn text_size(&self, doc: &Document, id: NodeId) -> Option<(f64, f64)> {
|
|
let n = doc.node(id)?;
|
|
let NodeKind::Text(t) = &n.kind else { return None };
|
|
if t.auto_resize == TextAutoResize::WidthAndHeight {
|
|
return figcraft_text::auto_size(n);
|
|
}
|
|
// Natural (unwrapped) size, whatever the resize mode.
|
|
let mut t = t.clone();
|
|
t.auto_resize = TextAutoResize::WidthAndHeight;
|
|
let l = figcraft_text::layout_cached(&t, None, None);
|
|
Some((l.width.ceil().max(1.0), l.height.max(1.0)))
|
|
}
|
|
fn text_baseline(&self, doc: &Document, id: NodeId) -> Option<f64> {
|
|
let n = doc.node(id)?;
|
|
let (l, dy) = figcraft_text::layout_node(n)?;
|
|
l.lines.first().map(|line| line.baseline + dy).filter(|b| b.is_finite())
|
|
}
|
|
}
|