//! Transient connection gestures. Only their final route enters model history. use iced::Point; use oa_core::{routing::*, *}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Context { pub document: Id, pub diagram: Id, pub revision: u64, pub epoch: u64, } #[derive(Debug, Clone)] pub enum Event { SelectBend(Id, usize), Commit(Context, EdgeRoute, Option), AddBend, AddBendAt(oa_core::Position), RemoveBend, Reset, } #[derive(Debug, Clone)] pub enum Handle { Bend(usize), Label { original: Position }, } #[derive(Debug, Clone)] pub struct Gesture { pub context: Context, pub start: Point, pub handle: Handle, pub route: EdgeRoute, pub changed: bool, pub baseline: std::sync::Arc, } impl Gesture { pub fn move_to(&mut self, point: Point, zoom: f32) { let delta = point - self.start; if !self.changed && (delta.x * delta.x + delta.y * delta.y) * zoom * zoom < 9. { return; } self.changed = true; match self.handle { Handle::Bend(index) => { self.route.waypoints[index] = Position { x: (point.x / 5.).round() * 5., y: (point.y / 5.).round() * 5., } } Handle::Label { original } => { if let Some(label) = &mut self.route.label { label.offset = Position { x: original.x + delta.x, y: original.y + delta.y, }; } } } } } pub fn stored_route(diagram: &Diagram, edge: Id) -> EdgeRoute { diagram .routes .iter() .find(|r| r.edge == edge) .cloned() .unwrap_or(EdgeRoute { edge, waypoints: Vec::new(), label: None, }) } /// Insert after the pins preceding the clicked segment along the routed path. pub fn insert_pin(route: &mut EdgeRoute, geometry: &RoutedEdge, point: Position) -> usize { let segment = geometry .points .windows(2) .enumerate() .min_by(|(_, a), (_, b)| { let distance = |span: &[Position]| { project_onto_polyline(span, point).map_or(f32::INFINITY, |p| p.distance) }; distance(a).total_cmp(&distance(b)) }) .map_or(0, |(index, _)| index); let index = pin_insertion_index(geometry, segment, point); route.waypoints.insert(index, point); index } pub fn with_route(diagram: &mut Diagram, route: EdgeRoute) { if let Some(existing) = diagram.routes.iter_mut().find(|r| r.edge == route.edge) { *existing = route; } else { diagram.routes.push(route); } } pub fn point(p: Position) -> Point { Point::new(p.x, p.y) } pub fn position(p: Point) -> Position { Position { x: p.x, y: p.y } }