mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-05 18:18:49 +00:00
Follow-ups to the batch: name numbering keeps no double space (#2908), Material Options error names the parameters (#2924), corrupt file timecodes stay on timecode (#2835), restore #2934's scroll-gutter asserts, #2825's Motion Tile test compiles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e96f47f3c2
commit
26228247e2
5 files changed
+12
-7
No files matched your search
@@ -827,8 +827,8 @@ mod tests {
|
||||
0.0,
|
||||
);
|
||||
assert_eq!((out.img.width, out.img.height), (10, 8));
|
||||
for (x, mirrored) in [(2u32, 0u32), (7, 9)] {
|
||||
for y in 0..out.img.height {
|
||||
for (x, mirrored) in [(2i64, 0i64), (7, 9)] {
|
||||
for y in 0..i64::from(out.img.height) {
|
||||
let a = out.img.get(x, y);
|
||||
assert!((a[3] - 1.0).abs() < 1e-5, "fold x={x},y={y} faded to alpha {}", a[3]);
|
||||
let b = img.get(mirrored, y);
|
||||
|
||||
@@ -245,7 +245,7 @@ fn apply_material(l: &mut Layer, p: &Value, t: Tick, cmd: &str) -> Result<Vec<&'
|
||||
fn material_mismatch(l: Option<&Layer>, missing: &[&str]) -> EngineError {
|
||||
let names = missing.iter().map(|k| format!("`{k}`")).collect::<Vec<_>>().join(", ");
|
||||
let Some(l) = l else { return bad("material.set", format!("no layer has {names}")) };
|
||||
let Some(g) = l.props.sub("materialOptions") else { return bad("material.set", format!("`{}` has no Material Options", l.name)) };
|
||||
let Some(g) = l.props.sub("materialOptions") else { return bad("material.set", format!("`{}` has no Material Options, so it has no {names}", l.name)) };
|
||||
let has: Vec<&str> = g.children.iter().map(|c| c.match_id()).collect();
|
||||
let why = if matches!(l.source, LayerSource::Model { .. }) { ": a 3D model layer keeps its model file's materials" } else { "" };
|
||||
bad(
|
||||
|
||||
@@ -185,6 +185,9 @@ pub fn import(
|
||||
const EDL_MEDIA_TIME_NOTE: &str = "EDL source timecodes were imported as media time";
|
||||
|
||||
/// An EDL's source times are its source timecodes, which FilmCraft's reader keeps as media time.
|
||||
/// The largest start timecode, in frames, a file may have: a day at 1000 fps.
|
||||
const MAX_FILE_TIMECODE: i64 = 24 * 3600 * 1000;
|
||||
|
||||
/// Put the clips of each file that has a start timecode on the file's own time, as FilmCraft does
|
||||
/// when it links the media of an imported EDL. Returns the names of the media that stay on
|
||||
/// timecode though their clips use an hour or more of it (the file is missing or has none).
|
||||
@@ -212,7 +215,9 @@ fn rebase_to_file_timecode(project: &mut fp::Project, probe: &mut dyn FnMut(&str
|
||||
let mut left = Vec::new();
|
||||
for (id, name, path, offline) in files {
|
||||
match if offline { None } else { probe(&path) } {
|
||||
Some(Footage { file_timecode: Some(tc), native_rate, frame_rate, .. }) => {
|
||||
// A corrupt timecode past a day of frames (at up to 1000 fps) would overflow the tick
|
||||
// arithmetic; such a file stays on timecode.
|
||||
Some(Footage { file_timecode: Some(tc), native_rate, frame_rate, .. }) if (0..=MAX_FILE_TIMECODE).contains(&tc) => {
|
||||
filmcraft_interchange::rebase_source_timecode(project, id, tc, crate::rate_out(native_rate.unwrap_or(frame_rate)));
|
||||
}
|
||||
_ if on_timecode.contains(&id) => left.push(name),
|
||||
|
||||
@@ -12,7 +12,7 @@ pub(crate) fn numbered_name(base: &str, taken: impl Fn(&str) -> bool) -> String
|
||||
let head = base.trim_end_matches(|c: char| c.is_ascii_digit());
|
||||
let stem = match head.strip_suffix(' ') {
|
||||
Some(stem) if head.len() < base.len() && !stem.trim_end().is_empty() => stem.trim_end(),
|
||||
_ => base,
|
||||
_ => base.trim_end(),
|
||||
};
|
||||
(2u64..).map(|k| format!("{stem} {k}")).find(|n| !taken(n)).unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -409,13 +409,13 @@ fn panel_rows_stop_before_their_scroll_bar() {
|
||||
assert!(scrolled(&h, bar).1 > 0.0, "{bar}: the rows overflow");
|
||||
let track = rect(&h, bar);
|
||||
if let Some(right) = rightmost(&h, prefix, bar, Some(track)) {
|
||||
if right > track.min.x { eprintln!("MUT {}", format!("{bar}: the rows end at {right}, on the track {track:?}")); }
|
||||
assert!(right <= track.min.x, "{bar}: the rows end at {right}, on the track {track:?}");
|
||||
} else {
|
||||
assert!(matches!(bar, "info.scroll" | "markers.scroll"), "{bar}: no rows beside the track");
|
||||
}
|
||||
let lane = Rect::from_x_y_ranges(track.min.x..=track.max.x, track.y_range());
|
||||
for (text, at) in painted_text(&h) {
|
||||
if at.intersects(lane) { eprintln!("MUT {}", format!("{bar}: {text:?} shows at {at:?}, on the track {track:?}")); }
|
||||
assert!(!at.intersects(lane), "{bar}: {text:?} shows at {at:?}, on the track {track:?}");
|
||||
}
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&folder);
|
||||
|
||||
Reference in new issue
Block a user