use bevy::ecs::entity::Entity;
use bevy::ecs::observer::On;
use bevy::ecs::query::With;
use bevy::ecs::system::{Commands, Query, Res};
use std::time::Duration;
use tracing::{debug, trace, warn};
use super::{MissionControlActive, MouseHeldMarker, Timeout, WMEventTrigger, WindowDraggedMarker};
use crate::ecs::params::{ActiveDisplay, Configuration, Windows};
use crate::ecs::{ActiveWorkspaceMarker, Scrolling, focus_entity, reshuffle_around};
use crate::events::Event;
use crate::manager::WindowManager;
#[allow(clippy::needless_pass_by_value)]
pub(super) fn mouse_moved_trigger(
trigger: On<WMEventTrigger>,
windows: Windows,
window_manager: Res<WindowManager>,
mut config: Configuration,
mut commands: Commands,
) {
let Event::MouseMoved { point } = trigger.event().0 else {
return;
};
if !config.focus_follows_mouse() {
return;
}
if config.mission_control_active() {
return;
}
if config.ffm_flag().is_some() {
trace!("ffm_window_id > 0");
return;
}
let Ok(window_id) = window_manager.find_window_at_point(&point) else {
debug!("can not find window at point {point:?}");
return;
};
if windows
.focused()
.is_some_and(|(window, _)| window.id() == window_id)
{
trace!("allready focused {window_id}");
return;
}
let Some((window, entity)) = windows.find(window_id) else {
trace!("can not find focused window: {window_id}");
return;
};
let child_window = window_manager
.get_associated_windows(window_id)
.into_iter()
.find_map(|child_wid| {
windows.find(child_wid).and_then(|(window, _)| {
window
.child_role()
.inspect_err(|err| {
warn!("getting role {window_id}: {err}");
})
.is_ok_and(|child| child)
.then_some(window)
})
});
if let Some(child) = child_window {
debug!("found child of {}: {}", child.id(), window.id());
}
config.set_skip_reshuffle(true);
config.set_ffm_flag(Some(window.id()));
focus_entity(entity, false, &mut commands);
}
#[allow(clippy::needless_pass_by_value, clippy::too_many_arguments)]
pub(super) fn mouse_down_trigger(
trigger: On<WMEventTrigger>,
windows: Windows,
active_workspace: Query<(Entity, Option<&Scrolling>), With<ActiveWorkspaceMarker>>,
window_manager: Res<WindowManager>,
mission_control_active: Res<MissionControlActive>,
config: Configuration,
mouse_held: Query<Entity, With<MouseHeldMarker>>,
mut commands: Commands,
) {
let Event::MouseDown { point } = trigger.event().0 else {
return;
};
if mission_control_active.0 {
return;
}
trace!("{point:?}");
let Some((_, entity)) = window_manager
.find_window_at_point(&point)
.ok()
.and_then(|window_id| windows.find(window_id))
else {
return;
};
for (entity, scroll) in active_workspace {
if scroll.is_some() {
commands.entity(entity).try_remove::<Scrolling>();
}
}
for held in &mouse_held {
commands.entity(held).despawn();
}
if config.window_hidden_ratio() >= 1.0 {
} else {
let timeout = Timeout::new(Duration::from_secs(5), None);
commands.spawn((MouseHeldMarker(entity), timeout));
}
}
#[allow(clippy::needless_pass_by_value)]
pub(super) fn mouse_up_trigger(
trigger: On<WMEventTrigger>,
mouse_held: Query<(Entity, &MouseHeldMarker)>,
mut commands: Commands,
) {
let Event::MouseUp { .. } = trigger.event().0 else {
return;
};
for (held_entity, marker) in &mouse_held {
reshuffle_around(marker.0, &mut commands);
commands.entity(held_entity).despawn();
}
}
#[allow(clippy::needless_pass_by_value)]
pub(super) fn mouse_dragged_trigger(
trigger: On<WMEventTrigger>,
active_display: ActiveDisplay,
windows: Windows,
mut drag_marker: Query<(&mut Timeout, &mut WindowDraggedMarker)>,
window_manager: Res<WindowManager>,
mission_control_active: Res<MissionControlActive>,
mut commands: Commands,
) {
const DRAG_MARKER_TIMEOUT_MS: u64 = 1000;
let Event::MouseDragged { point } = trigger.event().0 else {
return;
};
if mission_control_active.0 {
return;
}
let Some((window, entity)) = window_manager
.0
.find_window_at_point(&point)
.ok()
.and_then(|window_id| windows.find(window_id))
else {
return;
};
if let Ok((mut timeout, mut marker)) = drag_marker.single_mut() {
if entity != marker.entity {
let marker = marker.as_mut();
marker.entity = entity;
marker.display_id = active_display.id();
timeout.timer.reset();
}
} else {
debug!(
"Adding a drag marker ({entity}, {}) to window id {}.",
active_display.id(),
window.id(),
);
let timeout = Timeout::new(Duration::from_millis(DRAG_MARKER_TIMEOUT_MS), None);
commands.spawn((
timeout,
WindowDraggedMarker {
entity,
display_id: active_display.id(),
},
));
}
}