use crate::edges::positions::get_handle_absolute_position;
use crate::types::connection::ConnectionMode;
use crate::types::handle::{Handle, HandleType};
use crate::types::node::{InternalNode, NodeId};
use std::collections::HashMap;
pub(crate) fn get_closest_handle<D>(
position: egui::Pos2,
connection_radius: f32,
node_lookup: &HashMap<NodeId, InternalNode<D>>,
from_handle: &Handle,
mode: ConnectionMode,
) -> Option<Handle> {
let mut best: Option<Handle> = None;
let mut best_dist = f32::INFINITY;
let search_radius = connection_radius + 250.0;
let preferred_type = match from_handle.handle_type {
HandleType::Source => HandleType::Target,
HandleType::Target => HandleType::Source,
};
for node in node_lookup.values() {
if node.node.hidden {
continue;
}
let node_rect = node.rect();
let expanded = node_rect.expand(search_radius);
if !expanded.contains(position) {
continue;
}
let all_handles = node
.internals
.handle_bounds
.source
.iter()
.chain(node.internals.handle_bounds.target.iter());
for handle in all_handles {
if handle.node_id == from_handle.node_id
&& handle.handle_type == from_handle.handle_type
&& handle.id == from_handle.id
{
continue;
}
if mode == ConnectionMode::Strict && handle.handle_type == from_handle.handle_type {
continue;
}
let handle_pos = get_handle_absolute_position(node, handle);
let dist = handle_pos.distance(position);
if dist > connection_radius {
continue;
}
let is_preferred_type = handle.handle_type == preferred_type;
let better = dist < best_dist
|| ((dist - best_dist).abs() < f32::EPSILON
&& is_preferred_type
&& best
.as_ref()
.map(|b| b.handle_type != preferred_type)
.unwrap_or(false));
if better {
best = Some(handle.clone());
best_dist = dist;
}
}
}
best
}