Puppet: selected pins are filled and ringed, unselected hollow (#96)
A selected pin was drawn only 1 px bigger and slightly brighter. Now, like selected and unselected mask vertices in the viewer, a selected pin is filled with its kind colour and ringed in white, and an unselected pin is hollow (dark centre, coloured outline). Drawing only; hit-testing is unchanged. Regression test: selected_puppet_pins_are_filled_and_unselected_hollow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 103b5c41e9e8ea84008593e05af50b01a2800b3e)
This commit is contained in:
parent
7002c92632
commit
a46ebf4dc7
|
|
@ -170,9 +170,18 @@ pub fn draw(
|
|||
}
|
||||
}
|
||||
// Pins grow under the pointer.
|
||||
// Selected pins are filled with their colour and ringed in white; unselected pins are
|
||||
// hollow (dark centre, coloured outline), like selected and unselected mask vertices.
|
||||
// Drawing only: hit-testing uses `pos` alone.
|
||||
let r = if sel { 5.5 } else { 4.5 } + if hover.is_some_and(|h| h.distance(pos) < 8.0) { 1.5 } else { 0.0 };
|
||||
painter.circle_filled(pos, r, if sel { col } else { col.gamma_multiply(0.85) });
|
||||
painter.circle_stroke(pos, r, Stroke::new(1.0, Color32::BLACK));
|
||||
if sel {
|
||||
painter.circle_filled(pos, r, col);
|
||||
painter.circle_stroke(pos, r, Stroke::new(1.0, Color32::BLACK));
|
||||
painter.circle_stroke(pos, r + 2.5, Stroke::new(1.5, Color32::WHITE));
|
||||
} else {
|
||||
painter.circle_filled(pos, r, Color32::from_black_alpha(160));
|
||||
painter.circle_stroke(pos, r, Stroke::new(1.5, col));
|
||||
}
|
||||
hits.push(PinHit { layer: layer.id, pin: pn.uid, kind: pn.kind, pos, rotation: pn.rotation, scale: pn.scale, handle });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -543,6 +543,50 @@ fn puppet_pin_click_selects_and_delete_removes_only_the_pins() {
|
|||
assert!(h.state().session.active_comp().unwrap().layer(LayerId(id)).is_some());
|
||||
}
|
||||
|
||||
/// Filled circles painted this frame (flattening nested shape lists).
|
||||
fn circles(h: &Harness<'_, EffectcraftApp>) -> Vec<egui::epaint::CircleShape> {
|
||||
fn walk(s: &egui::Shape, out: &mut Vec<egui::epaint::CircleShape>) {
|
||||
match s {
|
||||
egui::Shape::Circle(c) => out.push(*c),
|
||||
egui::Shape::Vec(v) => v.iter().for_each(|s| walk(s, out)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let mut out = vec![];
|
||||
for c in &h.output().shapes {
|
||||
walk(&c.shape, &mut out);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Issue #96: a selected puppet pin is filled with its colour and ringed; an unselected one is
|
||||
/// hollow (dark centre, coloured outline), like selected and unselected mask vertices. They used to
|
||||
/// differ by 1 px and a slight brightness change.
|
||||
#[test]
|
||||
fn selected_puppet_pins_are_filled_and_unselected_hollow() {
|
||||
let (mut h, _id, bend) = puppet_harness();
|
||||
let pins: Vec<u64> = h.state().auto.previous.iter().filter_map(|e| e.id.strip_prefix("viewer.puppetPin.").and_then(|r| r.parse().ok())).collect();
|
||||
let position: Vec<u64> = pins.into_iter().filter(|p| *p != bend).collect();
|
||||
let (a, b) = (position[0], position[1]);
|
||||
let pa = rect(&h, &format!("viewer.puppetPin.{a}")).center();
|
||||
let pb = rect(&h, &format!("viewer.puppetPin.{b}")).center();
|
||||
click(&mut h, pa);
|
||||
assert_eq!(h.state().session.state.selected_props.iter().map(|(_, u)| *u).collect::<Vec<_>>(), vec![a]);
|
||||
// Pointer away from the pins (hover enlarges a pin), then look at the painted pins.
|
||||
h.input_mut().events.push(Event::PointerMoved(pos2(5.0, 5.0)));
|
||||
h.run_steps(2);
|
||||
let col = effectcraft_ui_egui::panels::puppet_tool::pin_color(effectcraft_engine::effects::puppet::PinKind::Position);
|
||||
let at = |p: Pos2| circles(&h).into_iter().filter(move |c| c.center.distance(p) < 0.5).collect::<Vec<_>>();
|
||||
let dark = |c: egui::Color32| c.r().max(c.g()).max(c.b()) < 0x60;
|
||||
let sel = at(pa);
|
||||
assert!(sel.iter().any(|c| c.fill == col), "the selected pin is filled with its colour: {sel:?}");
|
||||
assert!(sel.iter().any(|c| c.fill == egui::Color32::TRANSPARENT && c.stroke.color == egui::Color32::WHITE), "and ringed in white: {sel:?}");
|
||||
let unsel = at(pb);
|
||||
assert!(!unsel.is_empty(), "the unselected pin is drawn");
|
||||
assert!(unsel.iter().all(|c| c.fill == egui::Color32::TRANSPARENT || dark(c.fill)), "the unselected pin is hollow: {unsel:?}");
|
||||
assert!(unsel.iter().any(|c| c.stroke.color == col), "with a coloured outline: {unsel:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn puppet_marquee_selects_pins_and_alt_drag_works_over_the_art() {
|
||||
let (mut h, _id, bend) = puppet_harness();
|
||||
|
|
|
|||
Loading…
Reference in New Issue