mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 01:15:25 +00:00
Merge pull request #7429 from dotCooCoo/fix/live-shape-replay-negative-radius
Live Shapes: saved object.setLiveShape steps with a negative radius or out-of-range sides replay again
This commit is contained in:
@@ -149,9 +149,22 @@ pub(super) fn set_live_shape(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
};
|
||||
let angle = |k: &str| Ok::<_, EngineError>(number(k, |_| true, "an angle in degrees")?.map(|a| a.rem_euclid(360.0)));
|
||||
let length = |k: &str| number(k, |x| x > 0.0 && x <= crate::MAX_COORD, "a length in points above 0");
|
||||
let radius = number("radius", |r| r >= 0.0, "a radius of 0 or more")?;
|
||||
// Saved steps ([`Session::replay`]) can hold values a direct call refuses, recorded before these
|
||||
// checks: a negative radius is 0, a whole side count of 0 or more is brought into 3 to 1000, and
|
||||
// a fractional or negative one is ignored. A whole number written as 5.0 counts as 5, as in a
|
||||
// direct call.
|
||||
let replaying = s.replaying();
|
||||
let radius = if replaying {
|
||||
number("radius", |_| true, "a number")?.map(|r| r.max(0.0))
|
||||
} else {
|
||||
number("radius", |r| r >= 0.0, "a radius of 0 or more")?
|
||||
};
|
||||
// A polygon's side count: a whole number from 3 to 1000.
|
||||
let sides = number("sides", |n| n.fract() == 0.0 && (3.0..=1000.0).contains(&n), "a whole number from 3 to 1000")?.map(|n| n as u64);
|
||||
let sides = if replaying {
|
||||
number("sides", |_| true, "a number")?.filter(|n| n.fract() == 0.0 && *n >= 0.0).map(|n| n.min(1000.0) as u64)
|
||||
} else {
|
||||
number("sides", |n| n.fract() == 0.0 && (3.0..=1000.0).contains(&n), "a whole number from 3 to 1000")?.map(|n| n as u64)
|
||||
};
|
||||
// An ellipse's pie (Ellipse Properties: Pie Start and End Angle, degrees; Invert Pie swaps them).
|
||||
let (pie_start, pie_end) = (angle("pieStart")?, angle("pieEnd")?);
|
||||
let invert = p.get("invertPie").and_then(Value::as_bool) == Some(true);
|
||||
|
||||
@@ -126,6 +126,30 @@ fn bad_sides_radii_and_keys_are_errors() {
|
||||
assert_eq!(corners(&s, id).0, [0.0; 4]);
|
||||
}
|
||||
|
||||
/// Saved steps play as they did before `sides` and `radius` were checked: a negative radius
|
||||
/// removes the rounding, a whole side count outside 3 to 1000 is brought into that range, and a
|
||||
/// fractional or negative side count is ignored.
|
||||
#[test]
|
||||
fn saved_steps_with_out_of_range_sides_or_radius_still_play() {
|
||||
let (mut s, id) = session();
|
||||
let poly = NodeId(s.execute("shape.polygon", &json!({"cx": 200, "cy": 200, "radius": 80, "sides": 6})).unwrap()["id"].as_u64().unwrap());
|
||||
let replay = |s: &mut Session, p: Value| s.replay("object.setLiveShape", &p).unwrap_or_else(|e| panic!("{p}: {e}"));
|
||||
run(&mut s, json!({"id": id.0, "radius": 6}));
|
||||
replay(&mut s, json!({"id": id.0, "radius": -4}));
|
||||
assert_eq!(corners(&s, id).0, [0.0; 4]);
|
||||
let sides = |s: &Session| match node_path(s, poly).1 {
|
||||
Some(LiveShape::Polygon { sides, .. }) => sides,
|
||||
other => panic!("{other:?}"),
|
||||
};
|
||||
for (n, want) in [(json!(2), 3), (json!(1001), 1000), (json!(2.5), 1000), (json!(-1), 1000), (json!(5.0), 5)] {
|
||||
replay(&mut s, json!({"ids": [poly.0], "sides": n}));
|
||||
assert_eq!(sides(&s), want, "{n}");
|
||||
}
|
||||
// A direct call still refuses them.
|
||||
assert!(s.execute("object.setLiveShape", &json!({"id": id.0, "radius": -4})).is_err());
|
||||
assert!(s.execute("object.setLiveShape", &json!({"ids": [poly.0], "sides": 2})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_selected_corners_round_alone_and_stay_selected() {
|
||||
let (mut s, id) = session();
|
||||
|
||||
Reference in New Issue
Block a user