Skip to content

Commit cde3301

Browse files
committed
Snap group
1 parent 420c50b commit cde3301

File tree

3 files changed

+150
-61
lines changed

3 files changed

+150
-61
lines changed

src/app.rs

Lines changed: 133 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,132 @@ impl DB {
421421
}
422422
out
423423
}
424+
425+
pub fn connected_insntances(&self, id: InstanceId) -> Vec<InstanceId> {
426+
let mut out = vec![id];
427+
for c in &self.connections {
428+
if c.a.ins == id {
429+
out.push(c.b.ins);
430+
} else if c.b.ins == id {
431+
out.push(c.a.ins);
432+
}
433+
}
434+
out
435+
}
436+
437+
pub fn move_nonwires_and_resize_wires(&mut self, ids: &[InstanceId], delta: Vec2) {
438+
// Move all non-wire instances, then adjust connected wire endpoints
439+
for id in ids {
440+
match self.ty(*id) {
441+
InstanceKind::Gate(_) => {
442+
let g = self.get_gate_mut(*id);
443+
g.pos += delta;
444+
}
445+
InstanceKind::Power => {
446+
let p = self.get_power_mut(*id);
447+
p.pos += delta;
448+
}
449+
InstanceKind::Wire => {}
450+
InstanceKind::CustomCircuit(_) => {
451+
let cc = self.get_custom_circuit_mut(*id);
452+
cc.pos += delta;
453+
}
454+
}
455+
}
456+
457+
// Resize wire endpoints attached to any moved instance
458+
for id in ids {
459+
for pin in self.connected_pins_of_instance(*id) {
460+
if matches!(self.ty(pin.ins), InstanceKind::Wire) {
461+
let w = self.get_wire_mut(pin.ins);
462+
if pin.index == 0 {
463+
w.start += delta;
464+
} else {
465+
w.end += delta;
466+
}
467+
}
468+
}
469+
}
470+
}
471+
472+
pub fn move_instance_and_propagate(&mut self, id: InstanceId, delta: Vec2) {
473+
let mut visited = HashSet::new();
474+
self.move_instance_and_propagate_recursive(id, delta, &mut visited);
475+
}
476+
477+
fn move_instance_and_propagate_recursive(
478+
&mut self,
479+
id: InstanceId,
480+
delta: Vec2,
481+
visited: &mut HashSet<InstanceId>,
482+
) {
483+
if !visited.insert(id) {
484+
return;
485+
}
486+
487+
// Move this instance
488+
match self.ty(id) {
489+
InstanceKind::Gate(_) => {
490+
let g = self.get_gate_mut(id);
491+
g.pos += delta;
492+
}
493+
InstanceKind::Power => {
494+
let p = self.get_power_mut(id);
495+
p.pos += delta;
496+
}
497+
InstanceKind::Wire => {
498+
let w = self.get_wire_mut(id);
499+
w.start += delta;
500+
w.end += delta;
501+
}
502+
InstanceKind::CustomCircuit(_) => {
503+
let cc = self.get_custom_circuit_mut(id);
504+
cc.pos += delta;
505+
}
506+
}
507+
508+
// Get connected instances before we recurse
509+
let connected = self.connected_insntances(id);
510+
511+
// Process each connected instance
512+
for connected_id in connected {
513+
if connected_id == id || visited.contains(&connected_id) {
514+
continue;
515+
}
516+
517+
match self.ty(connected_id) {
518+
InstanceKind::Wire => {
519+
// For wires, resize them to stay connected
520+
// Find which pin of the wire is connected to our moved instance
521+
let wire_pins = self.pins_of(connected_id);
522+
for wire_pin in wire_pins {
523+
// Check if this wire pin is connected to any pin of our moved instance
524+
for moved_pin in self.pins_of(id) {
525+
if self
526+
.connections
527+
.contains(&Connection::new(wire_pin, moved_pin))
528+
{
529+
// Update the wire endpoint to match the new pin position
530+
let new_pin_pos = self.pin_position(moved_pin);
531+
let w = self.get_wire_mut(connected_id);
532+
if wire_pin.index == 0 {
533+
w.start = new_pin_pos;
534+
} else {
535+
w.end = new_pin_pos;
536+
}
537+
}
538+
}
539+
}
540+
// Mark as visited but don't propagate further (wires are endpoints)
541+
visited.insert(connected_id);
542+
}
543+
InstanceKind::Gate(_) | InstanceKind::Power | InstanceKind::CustomCircuit(_) => {
544+
// For non-wires, propagate the same delta
545+
self.move_instance_and_propagate_recursive(connected_id, delta, visited);
546+
}
547+
}
548+
}
549+
}
424550
}
425551

426552
#[derive(serde::Deserialize, serde::Serialize)]
@@ -909,7 +1035,8 @@ impl App {
9091035
&& let Some(hovered) = self.hovered
9101036
&& let Some(mouse) = mouse_pos_world
9111037
&& self.drag.is_none()
912-
&& let Some(split_point) = self.wire_branching_action_point(mouse, hovered)
1038+
&& let Hover::Instance(instance_id) = hovered
1039+
&& let Some(split_point) = self.wire_branching_action_point(mouse, instance_id)
9131040
{
9141041
ui.painter().circle_filled(
9151042
split_point - self.viewport_offset,
@@ -1907,10 +2034,11 @@ impl App {
19072034
self.current_dirty = true;
19082035
}
19092036

1910-
pub fn wire_branching_action_point(&self, mouse: Pos2, hovered: Hover) -> Option<Pos2> {
1911-
let Hover::Instance(instance_id) = hovered else {
1912-
return None;
1913-
};
2037+
pub fn wire_branching_action_point(
2038+
&self,
2039+
mouse: Pos2,
2040+
instance_id: InstanceId,
2041+
) -> Option<Pos2> {
19142042
if !self.selected.contains(&instance_id) || self.selected.len() != 1 {
19152043
return None;
19162044
}

src/connection_manager.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,22 +204,22 @@ impl ConnectionManager {
204204
let pin_offset = info.offset;
205205
let current = g.pos + pin_offset;
206206
let desired = target - current;
207-
g.pos += desired;
207+
db.move_instance_and_propagate(src.ins, desired);
208208
}
209209
InstanceKind::Power => {
210210
let p = db.get_power_mut(src.ins);
211211
let info = assets::POWER_ON_GRAPHICS.pins[src.index as usize];
212212
let pin_offset = info.offset;
213213
let current = p.pos + pin_offset;
214214
let desired = target - current;
215-
p.pos += desired;
215+
db.move_instance_and_propagate(src.ins, desired);
216216
}
217217
InstanceKind::CustomCircuit(_) => {
218218
let pin_offset = db.pin_offset(src);
219219
let cc = db.get_custom_circuit_mut(src.ins);
220220
let current = cc.pos + pin_offset;
221221
let desired = target - current;
222-
cc.pos += desired;
222+
db.move_instance_and_propagate(src.ins, desired);
223223
}
224224
}
225225
}

src/drag.rs

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,19 @@ impl App {
5353

5454
self.drag_had_movement = false;
5555

56-
if !self.selected.is_empty()
57-
&& !self.selected.len() == 1
58-
&& matches!(
59-
self.db
60-
.ty(*self.selected.iter().next().expect("checked size")),
61-
InstanceKind::Wire
62-
)
56+
if self.selected.len() == 1
57+
&& let Some(wire_id) = self.selected.iter().next()
58+
&& let Some(split_point) = self.wire_branching_action_point(mouse, *wire_id)
6359
{
60+
self.drag = Some(Drag::BranchWire {
61+
original_wire_id: *wire_id,
62+
split_point,
63+
start_mouse_pos: mouse,
64+
});
65+
return;
66+
}
67+
68+
if !self.selected.is_empty() {
6469
self.drag = Some(Drag::Canvas(CanvasDrag::Selected { start: mouse }));
6570
return;
6671
}
@@ -108,15 +113,6 @@ impl App {
108113
InstanceKind::Wire => {
109114
let wire = self.db.get_wire(instance);
110115

111-
if let Some(split_point) = self.wire_branching_action_point(mouse, hovered) {
112-
self.drag = Some(Drag::BranchWire {
113-
original_wire_id: instance,
114-
split_point,
115-
start_mouse_pos: mouse,
116-
});
117-
return;
118-
}
119-
120116
let wire_center = pos2(
121117
(wire.start.x + wire.end.x) * 0.5,
122118
(wire.start.y + wire.end.y) * 0.5,
@@ -186,7 +182,7 @@ impl App {
186182
};
187183
let desired = new_pos - current_pos;
188184
let ids = [id];
189-
self.move_nonwires_and_resize_wires(&ids, desired);
185+
self.db.move_nonwires_and_resize_wires(&ids, desired);
190186
moved = desired.length_sq() > 0.0;
191187
}
192188
InstanceKind::Wire => {
@@ -220,7 +216,7 @@ impl App {
220216
self.drag = Some(Drag::Canvas(CanvasDrag::Selected { start: mouse }));
221217

222218
let group: Vec<InstanceId> = self.selected.iter().copied().collect();
223-
self.move_nonwires_and_resize_wires(&group, desired);
219+
self.db.move_nonwires_and_resize_wires(&group, desired);
224220
if desired.length_sq() > 0.0 {
225221
self.connection_manager.mark_instances_dirty(&group);
226222
self.drag_had_movement = true;
@@ -399,41 +395,6 @@ impl App {
399395
self.drag_had_movement = false;
400396
}
401397

402-
pub fn move_nonwires_and_resize_wires(&mut self, ids: &[InstanceId], delta: Vec2) {
403-
// Move all non-wire instances, then adjust connected wire endpoints
404-
for id in ids {
405-
match self.db.ty(*id) {
406-
InstanceKind::Gate(_) => {
407-
let g = self.db.get_gate_mut(*id);
408-
g.pos += delta;
409-
}
410-
InstanceKind::Power => {
411-
let p = self.db.get_power_mut(*id);
412-
p.pos += delta;
413-
}
414-
InstanceKind::Wire => {}
415-
InstanceKind::CustomCircuit(_) => {
416-
let cc = self.db.get_custom_circuit_mut(*id);
417-
cc.pos += delta;
418-
}
419-
}
420-
}
421-
422-
// Resize wire endpoints attached to any moved instance
423-
for id in ids {
424-
for pin in self.db.connected_pins_of_instance(*id) {
425-
if matches!(self.db.ty(pin.ins), InstanceKind::Wire) {
426-
let w = self.db.get_wire_mut(pin.ins);
427-
if pin.index == 0 {
428-
w.start += delta;
429-
} else {
430-
w.end += delta;
431-
}
432-
}
433-
}
434-
}
435-
}
436-
437398
pub fn compute_potential_connections(&mut self) {
438399
let pins_to_update = self.connection_manager.pins_to_update(&self.db);
439400
let mut new_connections = Vec::new();

0 commit comments

Comments
 (0)