/// <summary> /// Returns a list of all modules, internal connections between them, and connections /// to external modules</summary> /// <param name="graphContainer">Circuit container</param> /// <param name="objects">Enumeration of all selected objects, edges possible</param> /// <param name="modules">Modules in selected objects, filled by method</param> /// <param name="internalConnections">Collection of all internal connections, filled by method</param> /// <param name="incomingConnections">Collection of all incoming connections, filled by method</param> /// <param name="outgoingConnections">Collection of all outgoing connections, filled by method</param> public static void GetSubGraph( ICircuitContainer graphContainer, IEnumerable <object> objects, // [in] selected objects, edges possible HashSet <Element> modules, // [out] elements in the selected objects ICollection <Wire> internalConnections, ICollection <Wire> incomingConnections, ICollection <Wire> outgoingConnections) { // build the set of modules, and add them to result foreach (var module in objects.AsIEnumerable <Element>()) { modules.Add(module); } // add connections to modules foreach (var connection in graphContainer.Wires) { bool output = modules.Contains(connection.OutputElement); bool input = modules.Contains(connection.InputElement); if (output && input) { internalConnections.Add(connection); } else if (output) { outgoingConnections.Add(connection); } else if (input) { incomingConnections.Add(connection); } } }
// returns a list of all modules, internal connections between them, and connections // to external modules private static void GetSubCircuit( IEnumerable <object> objects, ICircuitContainer circuit, HashSet <Element> modules, ICollection <Wire> connections, ICollection <Wire> internalConnections, ICollection <Wire> externalConnections) { // build the set of modules, and add them to result foreach (Element module in Adapters.AsIEnumerable <Element>(objects)) { modules.Add(module); } // add connections to modules foreach (Wire connection in circuit.Wires) { bool output = modules.Contains(connection.OutputElement); bool input = modules.Contains(connection.InputElement); if (output && input) { connections.Add(connection); } else if (output) { externalConnections.Add(connection); } else if (input) { internalConnections.Add(connection); } } }
/// <summary> /// Ungroups the given group, causing its child elements to be moved to the given container</summary> /// <param name="group">The group to destroy while preserving its child elements</param> /// <param name="circuitContainer">The container that currently holds the group</param> /// <remarks>This method is intended to help with persistence of circuit groups.</remarks> public static void UngroupGroup(Group group, ICircuitContainer circuitContainer) { // restore external connections to modules in group foreach (Wire connection in circuitContainer.Wires) { if (connection.InputElement.As <Group>() == group) { var pin = connection.InputPin.As <GroupPin>(); Element element = pin.InternalElement; connection.SetInput(element, element.Type.Inputs[pin.InternalPinIndex]); } else if (connection.OutputElement.As <Group>() == group) { var pin = connection.OutputPin.As <GroupPin>(); Element element = pin.InternalElement; connection.SetOutput(element, element.Type.Outputs[pin.InternalPinIndex]); } } // restore modules IList <Element> modules = group.Elements; for (int i = modules.Count - 1; i >= 0; i--) { Element element = modules[i]; modules.RemoveAt(i); // location restores to parent space element.Bounds = new Rectangle(element.Bounds.Location.X + group.Bounds.Location.X - group.Info.Offset.X, element.Bounds.Location.Y + group.Bounds.Location.Y - group.Info.Offset.Y, element.Bounds.Width, element.Bounds.Height); circuitContainer.Elements.Add(element); } // restore internal connections IList <Wire> connections = group.Wires; for (int i = connections.Count - 1; i >= 0; i--) { Wire wire = connections[i]; connections.RemoveAt(i); circuitContainer.Wires.Add(wire); } // remove group circuitContainer.Elements.Remove(group); }
/// Gets location offset from oldContainer to newContainer, compensate renderer displacements for element title /// and margin sub-nodes location are defined relative to the parent container private Point GetRelativeOffset(ICircuitContainer oldContainer, ICircuitContainer newContainer) { AdaptableControl control = m_viewingContext.Cast <AdaptableControl>(); var offset = new Point(); var oldDomContainer = oldContainer.Cast <DomNode>(); var newDomContainer = newContainer.Cast <DomNode>(); var commonAncestor = DomNode.GetLowestCommonAncestor(oldDomContainer, newDomContainer); var upPath = oldDomContainer.Lineage.TakeWhile(x => x != commonAncestor); var upOffset = GetWorldOffset(control, upPath.AsIEnumerable <Element>()); offset.Offset(upOffset.X, upOffset.Y); var downPath = newDomContainer.Lineage.TakeWhile(x => x != commonAncestor).Reverse(); var downOffset = GetWorldOffset(control, downPath.AsIEnumerable <Element>()); offset.Offset(-downOffset.X, -downOffset.Y); return(offset); }
/// <summary> /// Populates a newly created group with circuit elements that are currently in the given graph</summary> /// <param name="newGroup">A new group, empty of circuit elements</param> /// <param name="elementsToGroup">The circuit elements to move into 'newGroup'.</param> /// <param name="graphContainer">The container for the circuit elements and their wires. These will /// be removed from 'graphContainer' and placed into 'newGroup'.</param> /// <remarks>This method is intended to help with persistence of circuit groups.</remarks> public static void CreateGroup(Group newGroup, IEnumerable <object> elementsToGroup, ICircuitContainer graphContainer) { // get the selected modules and the connections between them HashSet <Element> modules = new HashSet <Element>(); List <Wire> internalConnections = new List <Wire>(); List <Wire> externalConnections = new List <Wire>(); CircuitUtil.GetSubGraph(graphContainer, elementsToGroup, modules, internalConnections, externalConnections, externalConnections); // the group must be added before transferring modules and connections to it, // so that the history mechanism will capture all the changes. graphContainer.Elements.Add(newGroup); // transfer modules foreach (Element module in modules) { graphContainer.Elements.Remove(module); newGroup.Elements.Add(module); } // auto-generate sub-graph group pins to support the external connections to group // group pins may have multiple external connections newGroup.UpdateGroupPins(modules, internalConnections, externalConnections); // transfer internal connections (those between grouped modules) foreach (Wire connection in internalConnections) { graphContainer.Wires.Remove(connection); newGroup.Wires.Add(connection); } // initalize group pin's index and pinY newGroup.InitializeGroupPinIndexes(internalConnections); if (graphContainer.Is <Group>()) // making a group inside a group { // remap group pins in the parent group var parentGroup = graphContainer.Cast <Group>(); // remap parent group pins that reference the new group's subnodes to the new group foreach (var grpPin in parentGroup.InputGroupPins) { if (modules.Contains(grpPin.InternalElement)) { // adjust the internal pin index first for (int j = 0; j < newGroup.Inputs.Count; ++j) { var newGrpPin = newGroup.Inputs[j] as GroupPin; if (newGrpPin.InternalElement.DomNode == grpPin.InternalElement.DomNode && newGrpPin.InternalPinIndex == grpPin.InternalPinIndex) { grpPin.InternalPinIndex = j; newGrpPin.Name = grpPin.Name; //grpPin.Name = newGroup.Name + ":" + newGrpPin.Name; break; } } // now update node references for the parent group pin grpPin.InternalElement = newGroup; } } foreach (var grpPin in parentGroup.OutputGroupPins) { if (modules.Contains(grpPin.InternalElement)) { // adjust the internal pin index first for (int j = 0; j < newGroup.Outputs.Count; ++j) { var newGrpPin = newGroup.Outputs[j] as GroupPin; if (newGrpPin.InternalElement.DomNode == grpPin.InternalElement.DomNode && newGrpPin.InternalPinIndex == grpPin.InternalPinIndex) { grpPin.InternalPinIndex = j; newGrpPin.Name = grpPin.Name; //grpPin.Name = newGroup.Name + ":" + newGrpPin.Name; break; } } // now update node references for the parent group pin grpPin.InternalElement = newGroup; } } } newGroup.OnChanged(EventArgs.Empty); // notify the change( derived class of Group may need custom actions) // Remap external connections from grouped modules to group. foreach (Wire connection in externalConnections) { var groupInputPin = newGroup.MatchedGroupPin(connection.InputElement, connection.InputPin.Index, true); if (groupInputPin != null) { groupInputPin.SetPinTarget(true); // reroute original edge connection.SetInput(newGroup, groupInputPin); connection.InputPinTarget = groupInputPin.PinTarget; } var groupOutputPin = newGroup.MatchedGroupPin(connection.OutputElement, connection.OutputPin.Index, false); if (groupOutputPin != null) { groupOutputPin.SetPinTarget(false); // reroute original edge connection.SetOutput(newGroup, groupOutputPin); connection.OutputPinTarget = groupOutputPin.PinTarget; } } // find upper-left corner of the subnodes Point minLocation = new Point(int.MaxValue, int.MaxValue); foreach (var module in newGroup.Elements) { if (minLocation.X > module.Bounds.Location.X) { minLocation.X = module.Bounds.Location.X; } if (minLocation.Y > module.Bounds.Location.Y) { minLocation.Y = module.Bounds.Location.Y; } } // offset sub-nodes location so they are relative to the parent foreach (var module in newGroup.Elements) { var relLoc = module.Bounds.Location; relLoc.Offset(-minLocation.X, -minLocation.Y); module.Bounds = new Rectangle(relLoc, module.Bounds.Size); module.Position = module.Bounds.Location; } }
// returns a list of all modules, internal connections between them, and connections // to external modules private static void GetSubCircuit( IEnumerable<object> objects, ICircuitContainer circuit, HashSet<Element> modules, ICollection<Wire> connections, ICollection<Wire> internalConnections, ICollection<Wire> externalConnections) { // build the set of modules, and add them to result foreach (Element module in Adapters.AsIEnumerable<Element>(objects)) modules.Add(module); // add connections to modules foreach (Wire connection in circuit.Wires) { bool output = modules.Contains(connection.OutputElement); bool input = modules.Contains(connection.InputElement); if (output && input) { connections.Add(connection); } else if (output) { externalConnections.Add(connection); } else if (input) { internalConnections.Add(connection); } } }
/// <summary> /// Populates a newly created group with circuit elements that are currently in the given graph</summary> /// <param name="newGroup">A new group, empty of circuit elements</param> /// <param name="elementsToGroup">The circuit elements to move into 'newGroup'.</param> /// <param name="graphContainer">The container for the circuit elements and their wires. These will /// be removed from 'graphContainer' and placed into 'newGroup'.</param> /// <remarks>This method is intended to help with persistence of circuit groups.</remarks> public static void CreateGroup(Group newGroup, IEnumerable<object> elementsToGroup, ICircuitContainer graphContainer) { // get the selected modules and the connections between them HashSet<Element> modules = new HashSet<Element>(); List<Wire> internalConnections = new List<Wire>(); List<Wire> externalConnections = new List<Wire>(); CircuitUtil.GetSubGraph(graphContainer, elementsToGroup, modules, internalConnections, externalConnections, externalConnections); // the group must be added before transferring modules and connections to it, // so that the history mechanism will capture all the changes. graphContainer.Elements.Add(newGroup); // transfer modules foreach (Element module in modules) { graphContainer.Elements.Remove(module); newGroup.Elements.Add(module); } // auto-generate sub-graph group pins to support the external connections to group // group pins may have multiple external connections newGroup.UpdateGroupPins(modules, internalConnections, externalConnections); // transfer internal connections (those between grouped modules) foreach (Wire connection in internalConnections) { graphContainer.Wires.Remove(connection); newGroup.Wires.Add(connection); } // initialize group pin's index and pinY newGroup.InitializeGroupPinIndexes(internalConnections); if (graphContainer.Is<Group>()) // making a group inside a group { // remap group pins in the parent group var parentGroup = graphContainer.Cast<Group>(); // remap parent group pins that reference the new group's subnodes to the new group foreach (var grpPin in parentGroup.InputGroupPins) { if (modules.Contains(grpPin.InternalElement)) { // adjust the internal pin index first foreach (var newGrpPin in newGroup.InputGroupPins) { if (newGrpPin.InternalElement.DomNode == grpPin.InternalElement.DomNode && newGrpPin.InternalPinIndex == grpPin.InternalPinIndex) { grpPin.InternalPinIndex = newGrpPin.Index; newGrpPin.Name = grpPin.Name; //grpPin.Name = newGroup.Name + ":" + newGrpPin.Name; break; } } // now update node references for the parent group pin grpPin.InternalElement = newGroup; } } foreach (var grpPin in parentGroup.OutputGroupPins) { if (modules.Contains(grpPin.InternalElement)) { // adjust the internal pin index first foreach (var newGrpPin in newGroup.OutputGroupPins) { if (newGrpPin.InternalElement.DomNode == grpPin.InternalElement.DomNode && newGrpPin.InternalPinIndex == grpPin.InternalPinIndex) { grpPin.InternalPinIndex = newGrpPin.Index; newGrpPin.Name = grpPin.Name; //grpPin.Name = newGroup.Name + ":" + newGrpPin.Name; break; } } // now update node references for the parent group pin grpPin.InternalElement = newGroup; } } } newGroup.OnChanged(EventArgs.Empty); // notify the change( derived class of Group may need custom actions) // Remap external connections from grouped modules to group. foreach (Wire connection in externalConnections) { var groupInputPin = newGroup.MatchedGroupPin(connection.InputElement, connection.InputPin.Index, true); if (groupInputPin != null) { groupInputPin.SetPinTarget(true); // reroute original edge connection.SetInput(newGroup, groupInputPin); connection.InputPinTarget = groupInputPin.PinTarget; } var groupOutputPin = newGroup.MatchedGroupPin(connection.OutputElement, connection.OutputPin.Index, false); if (groupOutputPin != null) { groupOutputPin.SetPinTarget(false); // reroute original edge connection.SetOutput(newGroup, groupOutputPin); connection.OutputPinTarget = groupOutputPin.PinTarget; } } // find upper-left corner of the subnodes Point minLocation = new Point(int.MaxValue, int.MaxValue); foreach (var module in newGroup.Elements) { if (minLocation.X > module.Bounds.Location.X) minLocation.X = module.Bounds.Location.X; if (minLocation.Y > module.Bounds.Location.Y) minLocation.Y = module.Bounds.Location.Y; } // offset sub-nodes location so they are relative to the parent foreach (var module in newGroup.Elements) { var relLoc = module.Bounds.Location; relLoc.Offset(-minLocation.X, -minLocation.Y); module.Bounds = new Rectangle(relLoc, module.Bounds.Size); module.Position = module.Bounds.Location; } }
/// <summary> /// Ungroups the given group, causing its child elements to be moved to the given container</summary> /// <param name="group">The group to destroy while preserving its child elements</param> /// <param name="circuitContainer">The container that currently holds the group</param> /// <remarks>This method is intended to help with persistence of circuit groups.</remarks> public static void UngroupGroup(Group group, ICircuitContainer circuitContainer) { // restore external connections to modules in group foreach (Wire connection in circuitContainer.Wires) { if (connection.InputElement.As<Group>() == group) { var pin = connection.InputPin.As<GroupPin>(); Element element = pin.InternalElement; connection.SetInput(element, element.InputPin(pin.InternalPinIndex)); } else if (connection.OutputElement.As<Group>() == group) { var pin = connection.OutputPin.As<GroupPin>(); Element element = pin.InternalElement; connection.SetOutput(element, element.OutputPin(pin.InternalPinIndex)); } } // restore modules IList<Element> modules = group.Elements; for (int i = modules.Count - 1; i >= 0; i--) { Element element = modules[i]; modules.RemoveAt(i); // location restores to parent space element.Bounds = new Rectangle(element.Bounds.Location.X + group.Bounds.Location.X - group.Info.Offset.X, element.Bounds.Location.Y + group.Bounds.Location.Y - group.Info.Offset.Y, element.Bounds.Width, element.Bounds.Height); circuitContainer.Elements.Add(element); } // restore internal connections IList<Wire> connections = group.Wires; for (int i = connections.Count - 1; i >= 0; i--) { Wire wire = connections[i]; connections.RemoveAt(i); circuitContainer.Wires.Add(wire); } // remove group circuitContainer.Elements.Remove(group); }