private UndoRedo.IUndoable Flatten(UIGates.IC ic) { GateCanvas icgc = new GateCanvas((UIGates.IC)ic, icl); UndoRedo.Transaction undo_inline = new UndoRedo.Transaction("Inline Circuit"); // step 1. make room for the circuit // NOTE: exclude user i/o gates // because these will be removed anyways! Rect bounds = GetBounds(icgc.gates.Values.Where(g => !(g is UIGates.UserIO)), 0); foreach (Gate g in gates.Values) { if (g.Margin.Left > ic.Margin.Left || g.Margin.Top > ic.Margin.Top) { Point origin = new Point(g.Margin.Left, g.Margin.Top); double left = g.Margin.Left; double top = g.Margin.Top; if (g.Margin.Left > ic.Margin.Left && bounds.Width - ic.Width > 0) left += bounds.Width - ic.Width; if (g.Margin.Top > ic.Margin.Top && bounds.Height - ic.Height > 0) top += bounds.Height - ic.Height; g.Margin = new Thickness(left, top, 0, 0); ((GateLocation)g.Tag).x = left; ((GateLocation)g.Tag).y = top; undo_inline.Add(new UndoRedo.MoveGate(g, this, origin, new Point(g.Margin.Left, g.Margin.Top))); } } // steps 2 and 3. // bring in circuit and connect internal wiring Dictionary<Gate, Gate> newgates; // = new Dictionary<Gate, Gate>(); undo_inline.Add(AddGates(icgc, new Point(-bounds.Left + ic.Margin.Left, -bounds.Top + ic.Margin.Top), out newgates)); // step 4. connect external wiring Gates.IC gic = ic.AbGate as Gates.IC; // step 4a. connect inputs for (int i = 0; i < gic.NumberOfInputs; i++) { // for each input, find out which circuits within the ic // it is connected to List<Gates.Terminal> targets = gic.Circuit.GetTargets(new Gates.Terminal(0, gic.Inputs[i])); // and this particular ic input, what supplies it from outside the ic? Gates.Terminal source = c.GetSource(new Gates.Terminal(i, gic)); // then disconnect those inputs // and connect it them from the outer foreach (Gates.Terminal t in targets) { Gates.Terminal tt = new Gates.Terminal(t.portNumber, newgates[icgc.FindGate(t.gate)].AbGate); undo_inline.Add(new UndoRedo.Reverse(new UndoRedo.ConnectWire(c, c.GetSource(tt), tt))); c.Disconnect(tt); if (source != null) { c[tt] = source; undo_inline.Add(new UndoRedo.ConnectWire(c, source, tt)); } } } // step 4b. connect outputs for (int i = 0; i < gic.Output.Length; i++) { // for each output, find out which circuit within the ic // it comes from Gates.Terminal source = gic.Circuit.GetSource(new Gates.Terminal(0, gic.Outputs[i])); // translate into our circuit if (source != null) { source = new Gates.Terminal(source.portNumber, newgates[icgc.FindGate(source.gate)].AbGate); } // and this particular output supplies which sources in our circuit? List<Gates.Terminal> targets = c.GetTargets(new Gates.Terminal(i, gic)); // then disconnect those inputs // and connect it them from the outer foreach (Gates.Terminal t in targets) { undo_inline.Add(new UndoRedo.Reverse(new UndoRedo.ConnectWire(c, c.GetSource(t), t))); c.Disconnect(t); if (source != null) { c[t] = source; undo_inline.Add(new UndoRedo.ConnectWire(c, source, t)); } } } // step 5. delete user i/o and ic ClearSelection(); for (int i = 0; i < gic.NumberOfInputs; i++) { selected.Add(newgates[icgc.FindGate(gic.Inputs[i])]); } for (int i = 0; i < gic.Outputs.Length; i++) { selected.Add(newgates[icgc.FindGate(gic.Outputs[i])]); } selected.Add(ic); undo_inline.Add(DeleteSelectedGates()); // step 6. set selection to newly inlined gates ClearSelection(); foreach (Gate g in newgates.Values) { if (!(g is UIGates.UserIO)) { selected.Add(g); g.Selected = true; } } return undo_inline; }
/// <summary> /// Add all gates from a given canvas into our canvas at the selected offset. /// A clone of each gate will be made, both at the visual and internal level. /// A map will be produced indicated the relationship between the gates in the original /// canvas and the gates added to this canvas. /// </summary> /// <param name="icgc"></param> /// <param name="offset"></param> /// <param name="gatemap"></param> /// <returns></returns> protected UndoRedo.Transaction AddGates(GateCanvas icgc, Point offset, out Dictionary<Gate, Gate> gatemap) { UndoRedo.Transaction addgates = new UndoRedo.Transaction("Add Gates"); gatemap = new Dictionary<Gate, Gate>(); // step 1. bring the circuit in foreach (Gate g in icgc.gates.Values) { gatemap[g] = g.CreateUserInstance(); AddGate(gatemap[g], new GateLocation(offset.X + g.Margin.Left, g.Margin.Top + offset.Y, ((RotateTransform)g.RenderTransform).Angle)); addgates.Add(new UndoRedo.AddGate(this, gatemap[g])); } // step 2. connect internal wiring foreach (ConnectedWire cw in icgc.wires.Values) { Gates.Terminal target = new Gates.Terminal(cw.DestTerminalID.ID, gatemap[icgc.FindGate(cw.DestinationGate)].AbGate); Gates.Terminal source = new Gates.Terminal(cw.OriginTerminalID.ID, gatemap[icgc.FindGate(cw.OriginGate)].AbGate); c[target] = source; addgates.Add(new UndoRedo.ConnectWire(c, source, target)); } return addgates; }