mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-29 12:46:53 -06:00
crates/engine/src/cmd/object.rs: next's side with 069fe47b's auto-size guard, plus the PR's object.fit locked-objects note and the bottom-on-the-last-baseline fit; the reapplied fit_text_frame_tests module dropped, its baseline assertion added to next's copy. crates/tools/src/select.rs, crates/tools/src/tests.rs: keep next's side. crates/ui-egui/src/canvas.rs: drop the reapplied duplicate of the handle double-click test. ROADMAP.md: next's line with the locked-objects note; no second copy.
This commit is contained in:
+1
-1
@@ -537,7 +537,7 @@ Newest first.
|
||||
- **2026-10-12** · On screen, blend modes blend with the objects below and not with the paper, as in InDesign and in PDF export: a Color Dodge or Screen object over blank paper shows as it is. No readiness percentage change.
|
||||
- **2026-10-12** · A gradient feather on a group fades the group as one, on screen and in PDF. Before, the screen ignored it, and PDF masked the group with a box of zero size because a group has no path of its own. No readiness percentage change.
|
||||
- **2026-10-12** · In a CMYK transparency blend space (print documents), blend modes blend in CMYK on screen as in InDesign. Color Dodge with 100% K text turns coloured areas under it white and leaves the paper alone, where RGB blending changed almost nothing. PDF export already did this. No readiness percentage change.
|
||||
- **2026-10-12** · Double-clicking a frame handle fits the frame to its content as in InDesign (a corner fits both sides, an edge only its own). Object › Fitting › Fit Frame to Content now fits text frames to their text too, growing them for overset text. No readiness percentage change.
|
||||
- **2026-10-12** · Double-clicking a frame handle fits the frame to its content as in InDesign (a corner fits both sides, an edge only its own). Object › Fitting › Fit Frame to Content now fits text frames to their text too, growing them for overset text; fitting leaves locked objects and objects on locked layers as they are. No readiness percentage change.
|
||||
- **2026-10-11** · Moving a sheared and rotated text frame no longer leaves trails of text behind: canvas repaints cover the frame's whole text box, not just its outline. No readiness percentage change.
|
||||
- **2026-10-12** · Words in capitals hyphenate like capitalized words (FERRUM COM-MODI), as in InDesign; Hyphenate Capitalized Words off keeps them whole. No readiness percentage change.
|
||||
- **2026-10-12** · Load Swatches refuses an `.ase` file with more than 100,000 colors, and `swatch.load` merges a file of 100,000 colors in under 0.1 s (it took 9.6 s of CPU in a test build). No readiness percentage change.
|
||||
|
||||
@@ -567,7 +567,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Fitting",
|
||||
["Object", "Fitting"],
|
||||
None,
|
||||
"{mode: fillProportionally (preserves aspect ratio, covers frame, clips overflow)|fitProportionally (preserves aspect ratio, shows whole image, may leave empty space)|fitContentToFrame (stretches content to frame)|centerContent (keeps current size, positions at fitting alignment)|fitFrameToContent (resizes frame to content), axis?: both|height|width (frame-local sides Fit Frame to Content moves; default both), ids?}",
|
||||
"{mode: fillProportionally (preserves aspect ratio, covers frame, clips overflow)|fitProportionally (preserves aspect ratio, shows whole image, may leave empty space)|fitContentToFrame (stretches content to frame)|centerContent (keeps current size, positions at fitting alignment)|fitFrameToContent (resizes frame to content), axis?: both|height|width (frame-local sides Fit Frame to Content moves; default both), ids?} — locked objects and objects on locked layers are left as they are",
|
||||
has_selection,
|
||||
fit
|
||||
),
|
||||
@@ -2781,7 +2781,7 @@ fn fitted_text_frame(d: &Document, id: ItemId, height: bool, width: bool) -> Res
|
||||
// First fit the height at the existing width, then measure the complete text's width.
|
||||
// Recheck height after fitting width, since a small width change can change a line break.
|
||||
if height {
|
||||
out = fit_text_height(out, &mut compose)?;
|
||||
out = fit_text_height(out, id, tf.options.inset[2], &mut compose)?;
|
||||
}
|
||||
if width && tf.options.columns <= 1 {
|
||||
let cs = compose(out);
|
||||
@@ -2792,13 +2792,18 @@ fn fitted_text_frame(d: &Document, id: ItemId, height: bool, width: bool) -> Res
|
||||
}
|
||||
}
|
||||
if height {
|
||||
out = fit_text_height(out, &mut compose)?;
|
||||
out = fit_text_height(out, id, tf.options.inset[2], &mut compose)?;
|
||||
}
|
||||
}
|
||||
Ok(Some(out))
|
||||
}
|
||||
|
||||
fn fit_text_height(mut rect: Rect, compose: &mut impl FnMut(Rect) -> Arc<designcraft_compose::ComposedStory>) -> Result<Rect> {
|
||||
fn fit_text_height(
|
||||
mut rect: Rect,
|
||||
id: ItemId,
|
||||
inset_bottom: f64,
|
||||
compose: &mut impl FnMut(Rect) -> Arc<designcraft_compose::ComposedStory>,
|
||||
) -> Result<Rect> {
|
||||
let mut low = 1.0;
|
||||
let limit = 20_000.0;
|
||||
let mut high = rect.height().clamp(1.0, limit);
|
||||
@@ -2825,6 +2830,13 @@ fn fit_text_height(mut rect: Rect, compose: &mut impl FnMut(Rect) -> Arc<designc
|
||||
}
|
||||
}
|
||||
rect.y1 = rect.y0 + high;
|
||||
// A line is set when its baseline is within 0.01 pt of the bottom, so the search stops just
|
||||
// short of the lowest baseline. The bottom goes onto it (plus the inset): the frame then fits
|
||||
// its text exactly and still does when it is scaled up.
|
||||
let lowest = compose(rect).frame(id).and_then(|ft| ft.lines.iter().map(|l| l.baseline).reduce(f64::max));
|
||||
if let Some(b) = lowest.map(|b| b + inset_bottom).filter(|b| b.is_finite() && *b > rect.y1 && *b - rect.y1 <= 0.02) {
|
||||
rect.y1 = b;
|
||||
}
|
||||
Ok(rect)
|
||||
}
|
||||
|
||||
@@ -4731,7 +4743,11 @@ mod fit_text_frame_tests {
|
||||
assert!(b.x0 == 100.0 && b.width() > 100.0 && b.width() < 250.0, "{b:?}");
|
||||
let d = s.doc().unwrap().doc.clone();
|
||||
let sid = d.item(id).unwrap().text_frame().unwrap().story;
|
||||
assert!(!s.cache.get(&d, sid, None).is_overset(), "still fits");
|
||||
let cs = s.cache.get(&d, sid, None);
|
||||
assert!(!cs.is_overset(), "still fits");
|
||||
// The bottom is on the baseline, so a frame scaled up with its text still fits.
|
||||
let baseline = cs.frame(id).unwrap().lines[0].baseline;
|
||||
assert!((b.y1 - baseline).abs() < 1e-9, "{b:?} {baseline}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user