private void btnCopyAsImage_Click(object sender, RoutedEventArgs e) { if (gateCanvas.selected.Count > 0) { UIGates.IC ic = gateCanvas.CreateIC("(clipboard)", GateCanvas.SELECTED_GATES.SELECTED); GateCanvas tmp = new GateCanvas(ic, icl); tmp.Width = tmp.GetBounds(0, false).Width; tmp.Height = tmp.GetBounds(0, false).Height; BackgroundWorker bg = new BackgroundWorker(); bg.DoWork += (s2, e2) => { System.Threading.Thread.Sleep(500); // prop time // don't use wait on propagation because if there is a loop // it will loop forever }; bg.RunWorkerCompleted += (s2, e2) => { tmp.Mute = true; tmp.UpdateLayout(); tmp.UpdateWireConnections(); Clipboard.SetImage(tmp.CreateImage()); Grid1.Children.Remove(tmp); }; Grid1.Children.Add(tmp); bg.RunWorkerAsync(); } }
/// <summary> /// Create a window based on a given IC and IC List. Provide /// an edit level of either View or Edit as appropriate. /// </summary> /// <param name="IC"></param> /// <param name="useicl"></param> /// <param name="el"></param> public Window1(UIGates.IC IC, ICList useicl, EditLevel el) : this(el) { icl = useicl; gateCanvas.ICL = icl; gateCanvas.UndoProvider = (UndoRedo.UndoManager)Resources["undoManager"]; spGates.ICList = icl; _filename = IC.AbGate.Name; this.Loaded += (sender, e) => { RefreshGateCanvas(IC); spGates.ICName = IC.AbGate.Name; if (el == EditLevel.VIEW) { gateCanvas.IsReadOnly = true; } Dispatcher.BeginInvoke( new Action(() => { Activate(); Focus(); })); }; }
private void SetInfoLine(UIGates.IC ic) { string inf = "Left-drag to place"; if (!_ro) { inf += ", double-click to edit, type to rename"; } InfoLine.SetInfo(ic, inf); }
private void btnCopy_Click(object sender, RoutedEventArgs e) { if (gateCanvas.selected.Count > 0) { UIGates.IC ic = gateCanvas.CreateIC("(clipboard)", GateCanvas.SELECTED_GATES.SELECTED); CircuitXML cx = new CircuitXML(icl); DataObject clipobj = new DataObject(); Clipboard.SetData("IC", cx.CreateCircuitXML(ic).ToString()); btnPaste.IsEnabled = true; } }
/// <summary> /// Create an XML representation of this IC and all nested ICs, recursively. /// </summary> /// <param name="ic"></param> /// <returns></returns> public XElement CreateXML(UIGates.IC ic) { XElement root = new XElement("CircuitGroup"); root.SetAttributeValue("Version", "1.2"); TopologicalSort ts = new TopologicalSort(); List <UIGates.IC> ics = ts.Sort(ic, icl); foreach (UIGates.IC theic in ics) { root.Add(CreateCircuitXML(theic)); } return(root); }
/// <summary> /// Create an IC, but ignore user input and output. This is useful if /// the IC is just a package for some other operation. /// </summary> /// <param name="name"></param> /// <returns></returns> public UIGates.IC CreateNonTerminaledIC(string name) { Gates.IC nic = new Gates.IC(c, new Gates.IOGates.UserInput[0], new Gates.IOGates.UserOutput[0], name); UIGates.IC nuic = new UIGates.IC(nic, new Gate.TerminalID[0]); // finally, hint the IC so that we can remember // where things are placed visually in the future foreach (Gates.AbstractGate g in c) { nuic.locationHints.Add(g, pos(g)); } return((UIGates.IC)nuic.CreateUserInstance()); }
private void btnPaste_Click(object sender, RoutedEventArgs e) { if (Clipboard.ContainsData("IC")) { string xml = Clipboard.GetData("IC") as string; CircuitXML cx = new CircuitXML(icl); try { UIGates.IC ic = cx.LoadCircuit(System.Xml.Linq.XElement.Parse(xml)); gateCanvas.PasteIC(ic); } catch (Exception) { MessageBox.Show("Unable to complete paste; maybe you deleted a needed IC?"); } } }
/// <summary> /// Replace the existing canvas with a new canvas, based on the IC given. /// This is similar to closing this window and replacing it with another window /// based on that IC instead. /// </summary> /// <param name="newgcic"></param> public void RefreshGateCanvas(UIGates.IC newgcic) { Grid1.Children.Remove(gateCanvas); gateCanvas.Circuit.Stop(); gateCanvas = new GateCanvas(newgcic, icl); gateCanvas.UndoProvider = (UndoRedo.UndoManager)Resources["undoManager"]; this.UnregisterName("gateCanvas"); this.RegisterName("gateCanvas", gateCanvas); Grid1.Children.Insert(0 /*Grid1.Children.Count - 4*/,gateCanvas); Grid.SetColumn(gateCanvas, 1); Grid.SetRow(gateCanvas, 1); _basedon = newgcic; if (!string.IsNullOrEmpty(newgcic.AbGate.Name)) { _filename = newgcic.AbGate.Name; spGates.ICName = newgcic.AbGate.Name; UpdateTitle(); } if (MyEditLevel == EditLevel.FULL || MyEditLevel == EditLevel.EDIT) { // monitor the clipboard to provide cut/copy/paste visibility gateCanvas.selected.ListChanged += (s2, e2) => { btnCopy.IsEnabled = gateCanvas.selected.Count > 0; btnCut.IsEnabled = gateCanvas.selected.Count > 0; btnCopyAsImage.IsEnabled = gateCanvas.selected.Count > 0; }; } if (_myEditLevel == EditLevel.FULL) gateCanvas.Circuit.Start(); gateCanvas.SetCaptureICLChanges(); gateCanvas.Zoom = slZoom.Value; gateCanvas.UpdateLayout(); gateCanvas.UpdateWireConnections(); }
/// <summary> /// Replace the existing canvas with a new canvas, based on the IC given. /// This is similar to closing this window and replacing it with another window /// based on that IC instead. /// </summary> /// <param name="newgcic"></param> public void RefreshGateCanvas(UIGates.IC newgcic) { Grid1.Children.Remove(gateCanvas); gateCanvas.Circuit.Stop(); gateCanvas = new GateCanvas(newgcic, icl); gateCanvas.UndoProvider = (UndoRedo.UndoManager)Resources["undoManager"]; this.UnregisterName("gateCanvas"); this.RegisterName("gateCanvas", gateCanvas); Grid1.Children.Insert(0 /*Grid1.Children.Count - 4*/, gateCanvas); Grid.SetColumn(gateCanvas, 1); Grid.SetRow(gateCanvas, 1); _basedon = newgcic; if (!string.IsNullOrEmpty(newgcic.AbGate.Name)) { _filename = newgcic.AbGate.Name; spGates.ICName = newgcic.AbGate.Name; UpdateTitle(); } if (MyEditLevel == EditLevel.FULL || MyEditLevel == EditLevel.EDIT) { // monitor the clipboard to provide cut/copy/paste visibility gateCanvas.selected.ListChanged += (s2, e2) => { btnCopy.IsEnabled = gateCanvas.selected.Count > 0; btnCut.IsEnabled = gateCanvas.selected.Count > 0; btnCopyAsImage.IsEnabled = gateCanvas.selected.Count > 0; }; } if (_myEditLevel == EditLevel.FULL) { gateCanvas.Circuit.Start(); } gateCanvas.SetCaptureICLChanges(); gateCanvas.Zoom = slZoom.Value; gateCanvas.UpdateLayout(); gateCanvas.UpdateWireConnections(); }
/// <summary> /// Load a circuit group from a file. All ICs in the file will be stored /// using the provided StoreIC method. The IC with no name will be returned /// as the primary circuit. /// </summary> /// <param name="path"></param> /// <param name="sic"></param> /// <returns></returns> public UIGates.IC Load(string path, StoreIC sic) { XElement root = XElement.Load(path); // v1.0 and v1.1 did not mark version attribute, so check for null if (root.Attribute("Version") != null && root.Attribute("Version").Value != "1.2") { throw new Exception("Unsupport version " + root.Attribute("Version").Value); } UIGates.IC retic = null; foreach (XElement circuit in root.Elements()) { if (circuit.Attribute("Name") != null) { // check if we need to rename this circuit try { icl.GetIC(circuit.Attribute("Name").Value); // already has an IC by this name UpdateICNames[circuit.Attribute("Name").Value] = icl.GenerateAvailableName(circuit.Attribute("Name").Value); } catch (ArgumentException) { // not found, no problem } } UIGates.IC ic = LoadCircuit(circuit); if (circuit.Attribute("Name") != null) { sic(ic); } else { retic = ic; } } return(retic); }
private void btnCreateIC_Click(object sender, RoutedEventArgs e) { UIGates.IC nic = gateCanvas.CreateIC(icl.GenerateAvailableName("Untitled"), GateCanvas.SELECTED_GATES.SELECTED_IF_TWO_OR_MORE); icl.Add(nic); // can't call seteditname on nic directly // because it doesn't exist in the selector // because the selector makes an instance // so have the selector redirect the request // bg delay is due to animation effect time BackgroundWorker bg = new BackgroundWorker(); bg.DoWork += (s2, e2) => { System.Threading.Thread.Sleep(500); }; bg.RunWorkerCompleted += (s2, e2) => { spGates.SetEditName(nic.AbGate.Name); }; bg.RunWorkerAsync(); ((UndoRedo.UndoManager)Resources["undoManager"]).Add(new UndoRedo.CreateIC(icl, nic)); }
/// <summary> /// Create an IC, but ignore user input and output. This is useful if /// the IC is just a package for some other operation. /// </summary> /// <param name="name"></param> /// <returns></returns> public UIGates.IC CreateNonTerminaledIC(string name) { Gates.IC nic = new Gates.IC(c, new Gates.IOGates.UserInput[0], new Gates.IOGates.UserOutput[0], name); UIGates.IC nuic = new UIGates.IC(nic, new Gate.TerminalID[0]); // finally, hint the IC so that we can remember // where things are placed visually in the future foreach (Gates.AbstractGate g in c) { nuic.locationHints.Add(g, pos(g)); } return (UIGates.IC)nuic.CreateUserInstance(); }
public ChangeICEventArgs(UIGates.IC original, UIGates.IC newic) { this.original = original; this.newic = newic; }
private void g_MouseDoubleClick(object sender, MouseButtonEventArgs e) { BackgroundWorker bg = new BackgroundWorker(); bg.DoWork += (s2, e2) => { System.Threading.Thread.Sleep(500); }; bg.RunWorkerCompleted += (s2, e2) => { DragDrop.DragDropHelper.Cancel(); }; if (_ro) { return; } foreach (Window w in Application.Current.Windows) { if (((Window1)w).BasedOn != null && ((Window1)w).MyEditLevel == Window1.EditLevel.EDIT && ((Window1)w).BasedOn.AbGate.Name == ((UIGates.IC)sender).AbGate.Name) { w.Activate(); return; } } UIGates.IC template = ((UIGates.IC)sender).CreateUserInstance() as UIGates.IC; ((Gates.IC)template.AbGate).Circuit.Start(); Window1 icw = new Window1(template, icl, Window1.EditLevel.EDIT); icw.Show(); icw.Closing += (s2, e2) => { try { // only replace gates if changes made if (!icw.gateCanvas.UndoProvider.IsAtSavePoint) { UIGates.IC oic = icl.GetIC(icw.BasedOn.AbGate.Name); UIGates.IC nic = icw.GetIC(); // check for recursion // can bypass the selector if you are sneaky foreach (Gates.AbstractGate ag in ((Gates.IC)nic.AbGate).Circuit) { if (ag is Gates.IC) { if (((Gates.IC)ag).DeepIncludes(((UIGates.IC)nic).AbGate.Name)) { MessageBox.Show("Recursive circuit detected"); return; } } } // check for decreased inputs // can't undo if (oic.AbGate.NumberOfInputs > nic.AbGate.NumberOfInputs) { if (MessageBox.Show("Reducing the number of inputs will affect all instances of this IC in all circuits. This operation cannot be undone. Proceed?", "Danger Zone", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) != MessageBoxResult.Yes) { return; } } icl[icl.IndexOf(oic)] = nic; if (undoProvider != null) { undoProvider.Add(new UndoRedo.ReplaceIC(icl, oic, nic)); } } } catch (Exception) { } // can fail if this IC has been removed ((Gates.IC)template.AbGate).Circuit.Stop(); }; icl.ChangeIC += (s2, e2) => { if (e2.original.AbGate.Name == ((UIGates.IC)sender).AbGate.Name) { if (e2.newic == null) { icw.Close(); } else { // find the gate being edited foreach (UIGates.IC g in spGates.Children) { if (g.AbGate.Name == e2.newic.AbGate.Name) { icw.RefreshGateCanvas(g.CreateUserInstance() as UIGates.IC); } } } } }; }
/// <summary> /// Create an IC based on the circuit. All user input and outputs /// will be turned into terminals on this IC. The technique is to establish /// a center-point of the gates involved, and establish a "X" shape originating /// from this center. The position of the user i/o gates within this X shape /// determine how they appear on the IC. The goal is to have the layout of /// terminals match the layout and ordering of user inputs and outputs. /// </summary> /// <param name="name"></param> /// <returns></returns> public UIGates.IC CreateIC(string name) { posGates = new List <GTerm>(); List <Gates.IOGates.UserInput> uis = new List <Gates.IOGates.UserInput>(); List <Gates.IOGates.UserOutput> uos = new List <Gates.IOGates.UserOutput>(); // Determine the center-point of the X double maxX = 0, maxY = 0, minX = 0, minY = 0; var pts = createCenter(); maxX = pts.Right; minX = pts.Left; maxY = pts.Bottom; minY = pts.Top; avgX = (maxX + minX) / 2.0; avgY = (maxY + minY) / 2.0; // For all user i/o gates, determine where they fall in the X foreach (Gates.AbstractGate g in c) { if (g is Gates.IOGates.UserInput) { uis.Add((Gates.IOGates.UserInput)g); PositionAndHold(g); } if (g is Gates.IOGates.UserOutput) { uos.Add((Gates.IOGates.UserOutput)g); PositionAndHold(g); } } // Apply a sort to order user i/o gates with respect // to the standard ordering that the IC uses to display its terminals // see Gate class posGates.Sort((firstVal, nextVal) => { if (firstVal.pos != nextVal.pos) { return(firstVal.pos.CompareTo(nextVal.pos)); } else { return(firstVal.offset.CompareTo(nextVal.offset)); } }); Gates.IC nic = new Gates.IC(c, uis.ToArray(), uos.ToArray(), name); List <Gate.TerminalID> tids = new List <Gate.TerminalID>(); // constuct the terminal id list based on the sorted sequence foreach (GTerm gt in posGates) { tids.Add(new Gate.TerminalID(gt.gate is Gates.IOGates.UserInput, gt.gate is Gates.IOGates.UserInput ? uis.IndexOf((Gates.IOGates.UserInput)gt.gate) : uos.IndexOf((Gates.IOGates.UserOutput)gt.gate), gt.pos)); } UIGates.IC nuic = new UIGates.IC(nic, tids.ToArray()); // finally, hint the IC so that we can remember // where things are placed visually in the future foreach (Gates.AbstractGate g in c) { nuic.locationHints.Add(g, pos(g)); } // in some cases, the caller may be using these gates // so we create a clone so there is no interference return((UIGates.IC)nuic.CreateUserInstance()); }
/// <summary> /// Create an XML representation of the given IC, and all nested ICs recursively, /// and save it to the given path. /// </summary> /// <param name="path"></param> /// <param name="ic"></param> public void Save(string path, UIGates.IC ic) { XElement root = CreateXML(ic); root.Save(path); }
private void AddDragDropGate(UIGates.IC g) { AddDragDropGate(spGates.Children.Count, g); }
/// <summary> /// Create an IC based on the circuit. All user input and outputs /// will be turned into terminals on this IC. The technique is to establish /// a center-point of the gates involved, and establish a "X" shape originating /// from this center. The position of the user i/o gates within this X shape /// determine how they appear on the IC. The goal is to have the layout of /// terminals match the layout and ordering of user inputs and outputs. /// </summary> /// <param name="name"></param> /// <returns></returns> public UIGates.IC CreateIC(string name) { posGates = new List<GTerm>(); List<Gates.IOGates.UserInput> uis = new List<Gates.IOGates.UserInput>(); List<Gates.IOGates.UserOutput> uos = new List<Gates.IOGates.UserOutput>(); // Determine the center-point of the X bool fst = true; double maxX = 0, maxY = 0, minX = 0, minY = 0; foreach (Gates.AbstractGate g in c) { Point p = pos(g).GetPoint(); if (fst) { maxX = p.X; minX = p.X; maxY = p.Y; minY = p.Y; fst = false; } maxX = Math.Max(maxX, p.X); maxY = Math.Max(maxY, p.Y); minX = Math.Min(minX, p.X); minY = Math.Min(minY, p.Y); //avgX += p.X; //avgY += p.Y; } //avgX /= c.Count; //avgY /= c.Count; avgX = (maxX + minX) / 2.0; avgY = (maxY + minY) / 2.0; // For all user i/o gates, determine where they fall in the X foreach (Gates.AbstractGate g in c) { if (g is Gates.IOGates.UserInput) { uis.Add((Gates.IOGates.UserInput)g); PositionAndHold(g); } if (g is Gates.IOGates.UserOutput) { uos.Add((Gates.IOGates.UserOutput)g); PositionAndHold(g); } } // Apply a sort to order user i/o gates with respect // to the standard ordering that the IC uses to display its terminals // see Gate class posGates.Sort((firstVal, nextVal) => { if (firstVal.pos != nextVal.pos) return firstVal.pos.CompareTo(nextVal.pos); else return firstVal.offset.CompareTo(nextVal.offset); }); Gates.IC nic = new Gates.IC(c, uis.ToArray(), uos.ToArray(), name); List<Gate.TerminalID> tids = new List<Gate.TerminalID>(); // constuct the terminal id list based on the sorted sequence foreach (GTerm gt in posGates) { tids.Add(new Gate.TerminalID(gt.gate is Gates.IOGates.UserInput, gt.gate is Gates.IOGates.UserInput ? uis.IndexOf((Gates.IOGates.UserInput)gt.gate) : uos.IndexOf((Gates.IOGates.UserOutput)gt.gate), gt.pos)); } UIGates.IC nuic = new UIGates.IC(nic, tids.ToArray()); // finally, hint the IC so that we can remember // where things are placed visually in the future foreach (Gates.AbstractGate g in c) { nuic.locationHints.Add(g, pos(g)); } // in some cases, the caller may be using these gates // so we create a clone so there is no interference return (UIGates.IC)nuic.CreateUserInstance(); }
/// <summary> /// Clone the IC with terminals and location hinting. The IC may optionally /// be renamed in this cloning process. /// </summary> /// <param name="name"></param> /// <returns></returns> public IC CreateUserInstance(string name) { Gates.IC nic = (Gates.IC)((Gates.IC)_gate).Clone(name); // duplicate the term ids because they have individual // refernece to actual terminal IC nuic = new IC(nic, CloneTerminals()); DuplicateLocationHinting(nuic); return nuic; }
/// <summary> /// The "template" here is used as a visual template, that is, a descriptor of /// how the terminals should be laid out and a provided of location hints. /// The IC becomes the actual circuit within the return value. /// Accordingly, it is assumed that the template will be of the same /// "type" as the IC. /// </summary> /// <param name="ic"></param> /// <param name="template"></param> /// <returns></returns> public static IC CreateFromTemplate(Gates.IC ic, IC template) { UIGates.IC nuic = new UIGates.IC( ic, template.CloneTerminals()); template.DuplicateLocationHinting(nuic); return nuic; }
/// <summary> /// Create an XML representation of a given IC. Nested ICs will be referenced, /// but not created by this method. /// </summary> /// <param name="cc"></param> /// <returns></returns> public XElement CreateCircuitXML(UIGates.IC cc) { XElement circuit = new XElement("Circuit"); circuit.SetAttributeValue("Name", cc.AbGate.Name); XElement gates = new XElement("Gates"); Dictionary <Gates.AbstractGate, int> gid = new Dictionary <Gates.AbstractGate, int>(); int cid = 1; Gates.Circuit circ = ((Gates.IC)cc.AbGate).Circuit; foreach (Gates.AbstractGate g in circ) { XElement gt = new XElement("Gate"); gt.SetAttributeValue("Type", g.GetType().Name); gt.SetAttributeValue("Name", g.Name); gt.SetAttributeValue("ID", cid); gt.Add(new XElement("Point")); gt.Element("Point").SetAttributeValue("X", cc.locationHints[g].X); gt.Element("Point").SetAttributeValue("Y", cc.locationHints[g].Y); gt.Element("Point").SetAttributeValue("Angle", cc.locationHints[g].Angle); if (g is Gates.IVariableInputs) { gt.SetAttributeValue("NumInputs", g.NumberOfInputs); } if (g is Gates.IOGates.AbstractNumeric) { gt.SetAttributeValue("Bits", ((Gates.IOGates.AbstractNumeric)g).Bits); gt.SetAttributeValue("SelRep", (int)(((Gates.IOGates.AbstractNumeric)g).SelectedRepresentation)); gt.SetAttributeValue("Value", ((Gates.IOGates.AbstractNumeric)g).Value); } if (g is Gates.IOGates.Clock) { gt.SetAttributeValue("Milliseconds", ((Gates.IOGates.Clock)g).Milliseconds); } if (g is Gates.IOGates.Comment) { gt.Add(new XElement("Comment", ((Gates.IOGates.Comment)g).Value)); } gates.Add(gt); gid.Add(g, cid); cid++; } XElement wires = new XElement("Wires"); foreach (Gates.AbstractGate g in circ) { for (int i = 0; i < g.NumberOfInputs; i++) { Gates.Terminal t = circ.GetSource(new Gates.Terminal(i, g)); if (t != null) { XElement wire = new XElement("Wire", new XElement("From"), new XElement("To")); wire.Element("From").SetAttributeValue("ID", gid[t.gate]); wire.Element("From").SetAttributeValue("Port", t.portNumber); wire.Element("To").SetAttributeValue("ID", gid[g]); wire.Element("To").SetAttributeValue("Port", i); wires.Add(wire); } } } circuit.Add(gates); circuit.Add(wires); return(circuit); }
/// <summary> /// Sort all ICs used within a given IC, deferencing against an IC list /// for canonical instances. /// </summary> /// <param name="ic"></param> /// <param name="icl"></param> /// <returns></returns> public List <UIGates.IC> Sort(UIGates.IC ic, ICList icl) { return(Sort(new UIGates.IC[] { ic }, icl)); }
private void AddDragDropGate(int pos, UIGates.IC g) { g.DataContext = g.CreateUserInstance(); DragDrop.DragDropHelper.SetIsDragSource(g, true); DragDrop.DragDropHelper.SetDragDropControl(g, new DragDrop.GateDragDropAdorner()); DragDrop.DragDropHelper.SetDropTarget(g, "gateCanvas"); DragDrop.DragDropHelper.SetAdornerLayer(g, "adornerLayer"); g.PreviewICNameChanged += (object sender2, string newname, ref bool cancel) => { if (newname == "") { cancel = true; } foreach (Gate g2 in icl) { if (newname == g2.AbGate.Name) { cancel = true; } } }; g.ICNameChanged += (sender2, newname) => { UIGates.IC oic = icl.GetIC((g.AbGate.Name)); UIGates.IC nic = g.CreateUserInstance(newname); icl[icl.IndexOf(oic)] = nic; if (undoProvider != null) { undoProvider.Add(new UndoRedo.ReplaceIC(icl, oic, nic)); } }; ScaleTransform st = new ScaleTransform(); st.CenterX = g.Width / 2.0; st.CenterY = g.Height / 2.0; double fac = 1.0; if (g.Width > MAX_SIZE) { fac = Math.Min(MAX_SIZE / g.Width, fac); } if (g.Height > MAX_SIZE) { fac = Math.Min(MAX_SIZE / g.Height, fac); } st.ScaleY = fac; st.ScaleX = fac; g.LayoutTransform = st; g.ContextMenu = new ContextMenu(); MenuItem exp = new MenuItem(); exp.Header = "Export..."; exp.Click += (sender2, e2) => { Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog(); dlg.DefaultExt = ".ic"; dlg.Filter = "IC (.ic)|*.ic"; bool?result = dlg.ShowDialog(); if (result == true) { CircuitXML cxml = new CircuitXML(icl); try { cxml.Save(dlg.FileName, g); } catch (Exception ex) { MessageBox.Show("Unable to save IC: " + ex.ToString()); } } }; g.ContextMenu.Items.Add(exp); MenuItem del = new MenuItem(); del.Header = "Delete"; del.Click += (sender2, e2) => { if (MessageBox.Show("All instances of this IC in all circuits will be removed. This operation cannot be undone. Proceed?", "Danger Zone", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.Yes) { UIGates.IC todel = icl.GetIC(g.AbGate.Name); icl.Remove(todel); if (undoProvider != null) { undoProvider.Clear(); } } }; g.ContextMenu.Items.Add(del); MenuItem hid = new MenuItem(); hid.Header = "Hide"; hid.Click += (sender2, e2) => { g.Visibility = Visibility.Collapsed; }; //g.ContextMenu.Items.Add(hid); spGates.Children.Insert(pos, g); g.MouseDoubleClick += new MouseButtonEventHandler(g_MouseDoubleClick); expUserGates.IsExpanded = true; g.BringIntoView(); g.IsReadOnly = _ro; g.ContextMenu.IsEnabled = !_ro; if (!string.IsNullOrEmpty(_icname)) { if (((Gates.IC)g.AbGate).DeepIncludes(_icname)) { g.Visibility = Visibility.Collapsed; } } ((Gates.IC)g.AbGate).Circuit.Start(); SetInfoLine(g); }