use concinnity_core::components::Sprite;
use concinnity_core::ecs::World;
use crate::editor::hook::tests::fixtures::{
SIDE_A, SIDE_B, click_at, click_at_mod, drag_to, release_at, two_prop_rig,
};
use crate::editor::hook::tests::fixtures::{active, selected};
use crate::editor::viewport::highlight;
use crate::editor::viewport::marquee;
#[test]
fn shift_click_toggles_selection_membership() {
let (mut world, _, _, mut h) = two_prop_rig(SIDE_A, SIDE_B, 1.0);
click_at(&mut world, &mut h, [200.0, 600.0]);
assert_eq!(active(&h).as_deref(), Some("box_a"));
click_at_mod(&mut world, &mut h, [424.0, 598.0], true);
assert_eq!(
selected(&h),
["box_a", "box_b"],
"shift-click adds the second box"
);
assert_eq!(active(&h).as_deref(), Some("box_b"), "the newest is active");
assert!(!h.form_open(), "a closed form stays closed");
click_at_mod(&mut world, &mut h, [424.0, 598.0], true);
assert_eq!(
selected(&h),
["box_a"],
"a second shift-click removes it again"
);
}
#[test]
fn marquee_drag_selects_the_boxed_assets() {
let (mut world, _, _, mut h) = two_prop_rig(SIDE_A, SIDE_B, 1.0);
click_at(&mut world, &mut h, [80.0, 450.0]);
assert!(h.marquee.is_some(), "an empty-space press arms the marquee");
drag_to(&mut world, &mut h, [560.0, 700.0]);
let rect = world
.get_by_id::<Sprite>(marquee::RECT)
.cloned()
.expect("marquee sprite injected");
assert!(rect.visible, "the rect shows once the drag clears the slop");
assert_eq!(
(rect.x, rect.y, rect.width, rect.height),
(80.0, 450.0, 480.0, 250.0)
);
release_at(&mut world, &mut h, [560.0, 700.0]);
assert_eq!(
selected(&h),
["box_a", "box_b"],
"both boxed props are selected"
);
assert!(h.marquee.is_none(), "release ends the marquee");
assert!(
!world.get_by_id::<Sprite>(marquee::RECT).unwrap().visible,
"the rect hides after release"
);
click_at(&mut world, &mut h, [200.0, 600.0]);
release_at(&mut world, &mut h, [200.0, 600.0]);
assert_eq!(selected(&h), ["box_a"]);
click_at_mod(&mut world, &mut h, [250.0, 450.0], true);
assert!(h.marquee.is_some());
drag_to(&mut world, &mut h, [560.0, 700.0]);
release_at(&mut world, &mut h, [560.0, 700.0]);
assert_eq!(
selected(&h),
["box_a", "box_b"],
"shift-drag adds without replacing"
);
click_at_mod(&mut world, &mut h, [80.0, 450.0], true);
release_at(&mut world, &mut h, [81.0, 450.0]);
assert_eq!(selected(&h).len(), 2, "shift keeps the selection");
click_at(&mut world, &mut h, [80.0, 450.0]);
release_at(&mut world, &mut h, [81.0, 450.0]);
assert_eq!(active(&h).as_deref(), None, "plain still release clears");
}
#[test]
fn selection_rings_cover_every_member() {
let (mut world, _, _, mut h) = two_prop_rig(SIDE_A, SIDE_B, 1.0);
click_at(&mut world, &mut h, [200.0, 600.0]);
click_at_mod(&mut world, &mut h, [424.0, 598.0], true);
let ids = &highlight::ids().sprites;
let ring = |world: &World, i: usize| {
world
.get_by_id::<Sprite>(ids[i])
.cloned()
.expect("ring pool injected")
};
let (r0, r1) = (ring(&world, 0), ring(&world, 1));
assert!(r0.visible && r1.visible, "one ring per member");
assert!(
!ring(&world, 2).visible,
"the rest of the pool stays hidden"
);
assert_ne!(
r0.border_color, r1.border_color,
"the active member's ring is distinguished"
);
let center = |r: &Sprite| (r.x + r.width * 0.5, r.y + r.height * 0.5);
let (c0x, _) = center(&r0);
let (c1x, _) = center(&r1);
assert!(
c0x < c1x,
"rings follow selection order: box_a left of box_b"
);
}