diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index 616a422..8c112b9 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -183,7 +183,7 @@ impl Autorouter { .unwrap() .vertex_index(); - selection.contains(&source_vertex.into()) && selection.contains(&to_vertex.into()) + selection.contains(source_vertex.into()) && selection.contains(to_vertex.into()) }) .collect() } diff --git a/src/autorouter/selection.rs b/src/autorouter/selection.rs index 5f6bcc7..45fa5e4 100644 --- a/src/autorouter/selection.rs +++ b/src/autorouter/selection.rs @@ -1,26 +1,83 @@ use std::collections::HashSet; -use crate::layout::NodeIndex; +use crate::{ + drawing::{graph::PrimitiveIndex, rules::RulesTrait}, + graph::GenericIndex, + layout::{zone::ZoneWeight, Layout, NodeIndex}, +}; #[derive(Debug, Clone)] pub struct Selection { - set: HashSet, + pins: HashSet, + primitives: HashSet, + zones: HashSet>, } impl Selection { pub fn new() -> Selection { Self { - set: HashSet::new(), + pins: HashSet::new(), + primitives: HashSet::new(), + zones: HashSet::new(), } } - pub fn toggle_at_node(&mut self, node: NodeIndex) { - if !self.set.insert(node) { - self.set.remove(&node); + pub fn toggle_at_node(&mut self, layout: &Layout, node: NodeIndex) { + let maybe_pin = layout.node_pin(node); + + if let Some(ref pin) = maybe_pin { + if self.contains(node) { + self.remove_pin(layout, pin); + } else { + self.add_pin(layout, pin); + } } } - pub fn contains(&self, node: &NodeIndex) -> bool { - self.set.contains(node) + fn add_pin(&mut self, layout: &Layout, pin: &String) { + for primitive in layout.drawing().primitive_nodes().filter(|primitive| { + layout + .node_pin(NodeIndex::Primitive(*primitive)) + .is_some_and(|p| p == pin) + }) { + self.primitives.insert(primitive); + } + + for zone in layout.zone_nodes().filter(|zone| { + layout + .node_pin(NodeIndex::Compound(*zone)) + .is_some_and(|p| p == pin) + }) { + self.zones.insert(zone); + } + + self.pins.insert(pin.clone()); + } + + fn remove_pin(&mut self, layout: &Layout, pin: &String) { + for primitive in layout.drawing().primitive_nodes().filter(|primitive| { + layout + .node_pin(NodeIndex::Primitive(*primitive)) + .is_some_and(|p| p == pin) + }) { + self.primitives.remove(&primitive); + } + + for zone in layout.zone_nodes().filter(|zone| { + layout + .node_pin(NodeIndex::Compound(*zone)) + .is_some_and(|p| p == pin) + }) { + self.zones.remove(&zone); + } + + self.pins.remove(pin); + } + + pub fn contains(&self, node: NodeIndex) -> bool { + match node { + NodeIndex::Primitive(primitive) => self.primitives.contains(&primitive), + NodeIndex::Compound(zone) => self.zones.contains(&zone), + } } } diff --git a/src/bin/topola-egui/app.rs b/src/bin/topola-egui/app.rs index 72b5a62..5d4b866 100644 --- a/src/bin/topola-egui/app.rs +++ b/src/bin/topola-egui/app.rs @@ -323,7 +323,7 @@ impl eframe::App for App { let color = if shared_data.highlighteds.contains(&primitive) || overlay .selection() - .contains(&GenericNode::Primitive(primitive)) + .contains(GenericNode::Primitive(primitive)) { egui::Color32::from_rgb(100, 100, 255) } else { @@ -333,12 +333,12 @@ impl eframe::App for App { } for zone in layout.layer_zone_nodes(1) { - let color = - if overlay.selection().contains(&GenericNode::Compound(zone)) { - egui::Color32::from_rgb(100, 100, 255) - } else { - egui::Color32::from_rgb(52, 52, 200) - }; + let color = if overlay.selection().contains(GenericNode::Compound(zone)) + { + egui::Color32::from_rgb(100, 100, 255) + } else { + egui::Color32::from_rgb(52, 52, 200) + }; painter.paint_polygon(&layout.zone(zone).shape().polygon, color) } @@ -348,7 +348,7 @@ impl eframe::App for App { let color = if shared_data.highlighteds.contains(&primitive) || overlay .selection() - .contains(&GenericNode::Primitive(primitive)) + .contains(GenericNode::Primitive(primitive)) { egui::Color32::from_rgb(255, 100, 100) } else { @@ -358,12 +358,12 @@ impl eframe::App for App { } for zone in layout.layer_zone_nodes(0) { - let color = - if overlay.selection().contains(&GenericNode::Compound(zone)) { - egui::Color32::from_rgb(255, 100, 100) - } else { - egui::Color32::from_rgb(200, 52, 52) - }; + let color = if overlay.selection().contains(GenericNode::Compound(zone)) + { + egui::Color32::from_rgb(255, 100, 100) + } else { + egui::Color32::from_rgb(200, 52, 52) + }; painter.paint_polygon(&layout.zone(zone).shape().polygon, color) } diff --git a/src/bin/topola-egui/overlay.rs b/src/bin/topola-egui/overlay.rs index 4eb4f36..d0464ff 100644 --- a/src/bin/topola-egui/overlay.rs +++ b/src/bin/topola-egui/overlay.rs @@ -73,7 +73,7 @@ impl Overlay { }; if shape.contains_point(p) { - self.selection.toggle_at_node(node); + self.selection.toggle_at_node(layout, node); return true; } false diff --git a/src/layout/layout.rs b/src/layout/layout.rs index bea5ae3..d1bc613 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -85,7 +85,7 @@ impl Layout { weight: FixedDotWeight, zone: GenericIndex, ) -> Result { - let pin = self.node_to_pin.get(&GenericNode::Compound(zone)); + let pin = self.node_pin(GenericNode::Compound(zone)); let maybe_dot = self.drawing.add_fixed_dot(weight); if let Ok(dot) = maybe_dot { @@ -119,7 +119,7 @@ impl Layout { weight: FixedSegWeight, zone: GenericIndex, ) -> Result { - let pin = self.node_to_pin.get(&GenericNode::Compound(zone)); + let pin = self.node_pin(GenericNode::Compound(zone)); let maybe_seg = self.add_fixed_seg(from, to, weight, pin.cloned()); if let Ok(seg) = maybe_seg { @@ -173,6 +173,10 @@ impl Layout { self.drawing.compounds(node) } + pub fn node_pin(&self, node: NodeIndex) -> Option<&String> { + self.node_to_pin.get(&node) + } + pub fn band_length(&self, face: DotIndex) -> f64 { // TODO. 0.0