use bevy_ecs::prelude::*;
use super::types::{DoubleClick, PointerLeave, PointerState, WheelDelta};
pub fn clear_transient_pointer_state(
mut query: Query<&mut PointerState>,
mut commands: Commands,
leave_query: Query<Entity, With<PointerLeave>>,
) {
for mut pointer in query.iter_mut() {
pointer.double_click = DoubleClick::None;
pointer.wheel = WheelDelta::default();
}
for entity in leave_query.iter() {
commands.entity(entity).remove::<PointerLeave>();
}
}
pub fn debug_pointer_state_changes(
added_query: Query<(Entity, &PointerState), Added<PointerState>>,
changed_query: Query<(Entity, &PointerState), Changed<PointerState>>,
) {
use tracing::debug;
for (entity, pointer) in added_query.iter() {
debug!(
entity = ?entity,
client_x = pointer.client_point.x,
client_y = pointer.client_point.y,
left = pointer.left_down,
right = pointer.right_down,
middle = pointer.middle_down,
shift = pointer.shift_down,
ctrl = pointer.ctrl_down,
"[PointerState Added] Enter detected"
);
}
for (entity, pointer) in changed_query.iter() {
if pointer.double_click != DoubleClick::None {
debug!(
entity = ?entity,
double_click = ?pointer.double_click,
"[PointerState Changed] DoubleClick detected"
);
}
if pointer.wheel.vertical != 0 || pointer.wheel.horizontal != 0 {
debug!(
entity = ?entity,
vertical = pointer.wheel.vertical,
horizontal = pointer.wheel.horizontal,
"[PointerState Changed] Wheel detected"
);
}
}
}
pub fn debug_pointer_leave(leave_query: Query<Entity, Added<PointerLeave>>) {
use tracing::debug;
for entity in leave_query.iter() {
debug!(
entity = ?entity,
"[PointerLeave Added] Leave detected"
);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_clear_transient_resets_double_click_and_wheel() {
let mut world = World::new();
let e = world
.spawn(PointerState {
double_click: DoubleClick::Left,
wheel: WheelDelta {
vertical: 120,
horizontal: -60,
},
left_down: true,
..Default::default()
})
.id();
let mut schedule = Schedule::default();
schedule.add_systems(clear_transient_pointer_state);
schedule.run(&mut world);
let s = world.get::<PointerState>(e).unwrap();
assert_eq!(s.double_click, DoubleClick::None, "double_click はリセット");
assert_eq!(s.wheel, WheelDelta::default(), "wheel はリセット");
assert!(s.left_down, "ボタン状態は transient ではなく保持される");
}
#[test]
fn test_clear_transient_removes_pointer_leave_marker() {
let mut world = World::new();
let leaving = world.spawn(PointerLeave).id();
let staying = world.spawn(PointerState::default()).id();
let mut schedule = Schedule::default();
schedule.add_systems(clear_transient_pointer_state);
schedule.run(&mut world);
assert!(
world.get::<PointerLeave>(leaving).is_none(),
"PointerLeave マーカーは除去される"
);
assert!(
world.get_entity(staying).is_ok(),
"PointerState 側エンティティは存続"
);
}
#[test]
fn test_clear_transient_no_targets_is_noop() {
let mut world = World::new();
let e = world.spawn_empty().id();
let mut schedule = Schedule::default();
schedule.add_systems(clear_transient_pointer_state);
schedule.run(&mut world);
assert!(world.get_entity(e).is_ok());
}
}