Exemplo n.º 1
0
        private NodeMessage CreateIOBox(PatchMessage patch, string pinType)
        {
            NodeMessage node;

            if (pinType == "String")
            {
                node = patch.AddNode("IOBox (String)");
            }
            else if (pinType == "Value")
            {
                node = patch.AddNode("IOBox (Value Advanced)");
            }
            else if (pinType == "Color")
            {
                node = patch.AddNode("IOBox (Color)");
            }
            else if (pinType == "Enumeration")
            {
                node = patch.AddNode("IOBox (Enumerations)");
            }
            else             //assume node
            {
                node = patch.AddNode("IOBox (Node)");
            }

            node.ComponentMode = ComponentMode.InABox;
            return(node);
        }
Exemplo n.º 2
0
        public PatchRefactorer(IHDEHost hdeHost, INode2[] selectedNodes, INodeBrowserHost nodeBrowserHost, INodeInfoFactory nodeInfoFactory)
        {
            FNodeInfoFactory = nodeInfoFactory;

            int x    = 0;
            int y    = 0;
            int maxX = 0;
            int maxY = 0;

            int minX = int.MaxValue;
            int minY = int.MaxValue;

            //check selection bounds
            foreach (var node in selectedNodes)
            {
                var bounds = node.GetBounds(BoundsType.Node);
                x += bounds.X;
                y += bounds.Y;

                maxX = Math.Max(maxX, bounds.X + bounds.Width);
                maxY = Math.Max(maxY, bounds.Y + bounds.Height);

                minX = Math.Min(minX, bounds.X);
                minY = Math.Min(minY, bounds.Y);
            }

            var CBorder    = 1500;
            int CPinOffset = CBorder / 3;

            x /= selectedNodes.Length;
            y /= selectedNodes.Length;
            var selectionCenter = new Point(x, y);
            var selectionSize   = new Size((maxX - minX) + CBorder * 2, (maxY - minY) + CBorder * 2);

            //create new nodinfo for subpatch
            var patchPath = Path.GetDirectoryName(hdeHost.ActivePatchWindow.Node.NodeInfo.Filename);

            if (!Path.IsPathRooted(patchPath))
            {
                patchPath = hdeHost.ExePath;
            }
            var patchName = GetUniquePatchName(hdeHost.ActivePatchWindow.Node.NodeInfo.Filename);

            patchPath = Path.Combine(patchPath, patchName) + ".v4p";

            var ni = FNodeInfoFactory.CreateNodeInfo(patchName, "", "", patchPath, true);

            ni.InitialComponentMode = TComponentMode.Hidden;
            ni.Type = NodeType.Patch;
            ni.CommitUpdate();

            //modify the current selection XML
            FDocument = new XmlDocument();
            FDocument.LoadXml(hdeHost.GetXMLSnippetFromSelection());

            //create new subpatch
            var subID = nodeBrowserHost.CreateNode(ni, selectionCenter);
            var patch = new PatchMessage(patchPath);

            //in the new subpatch nodes will have new IDs and bounds
            FOldID2NewID.Clear();
            var newNodeID = 0;
            var origNodes = FDocument.SelectNodes("/PATCH/NODE");

            foreach (XmlNode node in origNodes)
            {
                //modify the ID
                var idAttribute = node.Attributes.GetNamedItem("id");
                var oldID       = int.Parse(idAttribute.Value);
                idAttribute.Value = newNodeID.ToString();
                FOldID2NewID.Add(oldID, newNodeID);
                newNodeID++;

                //modify the bounds
                var bounds = node.SelectNodes("BOUNDS");
                foreach (XmlElement bound in bounds)
                {
                    if ((bound.GetAttribute("type") == "Node") || (bound.GetAttribute("type") == "Box"))
                    {
                        var top  = int.Parse(bound.GetAttribute("top"));
                        var left = int.Parse(bound.GetAttribute("left"));

                        bound.SetAttribute("top", (top - minY + CBorder).ToString());
                        bound.SetAttribute("left", (left - minX + CBorder).ToString());
                    }
                }
            }

            //offset linkpoints
            var origLinks = FDocument.SelectNodes("/PATCH/LINK");

            foreach (XmlElement link in origLinks)
            {
                foreach (XmlElement point in link)
                {
                    var px = int.Parse(point.GetAttribute("x"));
                    var py = int.Parse(point.GetAttribute("y"));

                    point.SetAttribute("x", (px - minX + CBorder).ToString());
                    point.SetAttribute("y", (py - minY + CBorder).ToString());
                }
            }

            FInputNames.Clear();
            FOutputNames.Clear();

            //extract all existing iobox names, as those must not be reused
            foreach (var node in selectedNodes)
            {
                if (node.NodeInfo.Name == "IOBox")
                {
                    var inputConnected  = node.FindPin(GetIOBoxPinName(node.NodeInfo.Category, true)).IsConnected();
                    var outputConnected = node.FindPin(GetIOBoxPinName(node.NodeInfo.Category, false)).IsConnected();
                    if (inputConnected && !outputConnected)
                    {
                        FOutputNames.Add(node.FindPin("Descriptive Name").Spread.Trim('|'));
                    }
                    else if (!inputConnected && outputConnected)
                    {
                        FInputNames.Add(node.FindPin("Descriptive Name").Spread.Trim('|'));
                    }
                }
            }

            //now sort the list of nodes in X from left to right
            //in order to get IOBoxes of leftmost nodes also leftmost
            var nodes          = (from n in selectedNodes orderby n.GetBounds(BoundsType.Node).X select n).ToList();
            var oldPinToNewPin = new Dictionary <string, string>();

            var IOpins     = new Dictionary <string, int>();
            var minInputX  = 0;
            var minOutputX = 0;

            //make connections in the selection
            //for each selected nodes input pin...
            foreach (var node in nodes)
            {
                foreach (var pin in node.Pins)
                {
                    foreach (var cpin in pin.ConnectedPins)
                    {
                        if (!cpin.Name.Contains("ROUTER DON'T USE"))                         //hack for S/R nodes
                        {
                            //..if there is a connection to another selected node in the same patch
                            //(pins of IOboxes can also be connected to nodes in parentpatches!)
                            var parent = cpin.ParentNodeByPatch(node.Parent);
                            if (parent != null)
                            {
                                if (FOldID2NewID.ContainsKey(parent.ID))
                                {
                                    //this needs only be done for inputs
                                    if (pin.Direction == PinDirection.Input)
                                    {
                                        var fromID   = parent.ID;
                                        var toID     = pin.ParentNodeByPatch(node.Parent).ID;
                                        var fromName = cpin.NameByParent(parent);
                                        var toName   = pin.NameByParent(node);

                                        //copy over complete link (including linkpoints)
                                        var link = (from XmlElement l in origLinks where
                                                    (l.GetAttribute("srcnodeid") == fromID.ToString() &&
                                                     l.GetAttribute("dstnodeid") == toID.ToString() &&
                                                     l.GetAttribute("srcpinname") == fromName &&
                                                     l.GetAttribute("dstpinname") == toName) select l).First() as XmlElement;
                                        link.SetAttribute("srcnodeid", FOldID2NewID[fromID].ToString());
                                        link.SetAttribute("dstnodeid", FOldID2NewID[toID].ToString());

                                        patch.XML.AppendChild(patch.XML.OwnerDocument.ImportNode(link, true));
                                    }
                                }
                                //..if there is a connection to a not selected node
                                else
                                {
                                    //an IO pin needs to be created
                                    //- if it doesn't exist yet (multiple inputs may connect to an upstream pin and an IO pin may already exist now)
                                    //- if the connected pin belongs to a (preexisting) labeled iobox
                                    string ident = "";
                                    if (pin.Direction == PinDirection.Input)
                                    {
                                        ident = parent.ID.ToString() + cpin.NameByParent(parent);
                                    }
                                    else if (pin.Direction == PinDirection.Output)
                                    {
                                        ident = node.ID.ToString() + pin.NameByParent(node);
                                    }

                                    if ((node.NodeInfo.Name == "IOBox") && (!string.IsNullOrEmpty(node.LabelPin[0])))
                                    {
                                        if (!IOpins.ContainsKey(ident))
                                        {
                                            IOpins.Add(ident, newNodeID);
                                            oldPinToNewPin.Add(ident, node.LabelPin[0]);
                                        }
                                    }

                                    if (!IOpins.ContainsKey(ident))
                                    {
                                        var pinType = pin.Type;
                                        //create an iobox of the right type
                                        var iobox = CreateIOBox(patch, pinType);

                                        iobox.ID = newNodeID;
                                        var bounds = node.GetBounds(BoundsType.Node);

                                        //name the iobox
                                        var labelPin  = iobox.AddPin("Descriptive Name");
                                        var boxBounds = iobox.AddBounds(BoundsType.Box);

                                        if (pin.Direction == PinDirection.Input)
                                        {
                                            boxBounds.Rectangle = new Rectangle(Math.Max(minInputX, bounds.X - minX + CBorder), CPinOffset, 750, 240);

                                            //an input-pin may be connected to an output-pin
                                            //that in turn is connected to multiple inputs
                                            //in those cases name the iobox by concatenating the names of all those pins (which are in the selection!)
                                            //but leave out duplicates
                                            var pinName = GetNameForInput(node.Parent, cpin);
                                            pinName = GetUniqueInputName(pinName);
                                            oldPinToNewPin.Add(ident, pinName);
                                            labelPin.SetAttribute("values", "|" + pinName + "|");

                                            //save it for reference
                                            IOpins.Add(ident, newNodeID);
                                            var ioboxOutput = GetIOBoxPinName(pinType, false);
                                            patch.AddLink(newNodeID, ioboxOutput, FOldID2NewID[pin.ParentNodeByPatch(node.Parent).ID], pin.NameByParent(node));

                                            minInputX = boxBounds.Rectangle.X + boxBounds.Rectangle.Width + 150;
                                        }
                                        else if (pin.Direction == PinDirection.Output)
                                        {
                                            boxBounds.Rectangle = new Rectangle(Math.Max(minOutputX, bounds.X - minX + CBorder), (maxY - minY) + CPinOffset + CBorder, 750, 240);
                                            var origName = pin.NameByParent(node);
                                            var pinName  = GetUniqueOutputName(origName);
                                            oldPinToNewPin.Add(ident, pinName);
                                            labelPin.SetAttribute("values", "|" + pinName + "|");

                                            //save it for reference
                                            IOpins.Add(pin.ParentNodeByPatch(node.Parent).ID.ToString() + origName, newNodeID);
                                            var ioboxInput = GetIOBoxPinName(pinType, true);
                                            patch.AddLink(FOldID2NewID[node.ID], origName, newNodeID, ioboxInput);

                                            minOutputX = boxBounds.Rectangle.X + boxBounds.Rectangle.Width + 150;
                                        }

                                        var nodeBounds = iobox.AddBounds(BoundsType.Node);
                                        nodeBounds.Rectangle = boxBounds.Rectangle;
                                        newNodeID++;
                                    }
                                    else     //IOpin already exists
                                    {
                                        var srcID = IOpins[ident];
                                        //this needs only be done for inputs
                                        if (pin.Direction == PinDirection.Input)
                                        {
                                            patch.AddLink(srcID, GetIOBoxPinName(cpin.Type, false), FOldID2NewID[pin.ParentNodeByPatch(node.Parent).ID], pin.NameByParent(node));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            //remove superfluous links from origXML
            var linksToRemove = FDocument.DocumentElement.SelectNodes("/PATCH/LINK");

            foreach (XmlElement link in linksToRemove)
            {
                FDocument.DocumentElement.RemoveChild(link);
            }

            foreach (XmlElement node in patch.XML)
            {
                var n = FDocument.ImportNode(node, true);
                FDocument.DocumentElement.AppendChild(n);
            }
            hdeHost.SendXMLSnippet(patchPath, FDocument.OuterXml, true);

            //make connections to new subpatch
            patch = new PatchMessage("");

            foreach (var node in selectedNodes)
            {
                foreach (var pin in node.Pins)
                {
                    foreach (var cpin in pin.ConnectedPins)
                    {
                        if (!cpin.Name.Contains("ROUTER DON'T USE"))                          //hack for S/R nodes
                        //..if there is a connection to a not selected node..
                        {
                            var parent = cpin.ParentNodeByPatch(node.Parent);
                            //..in the same patch..
                            if (parent != null)
                            {
                                if (!FOldID2NewID.ContainsKey(parent.ID))
                                {
                                    if (pin.Direction == PinDirection.Input)
                                    {
                                        patch.AddLink(parent.ID, cpin.NameByParent(parent), subID, oldPinToNewPin[parent.ID.ToString() + cpin.NameByParent(parent)]);
                                    }
                                    else if (pin.Direction == PinDirection.Output)
                                    {
                                        patch.AddLink(subID, oldPinToNewPin[pin.ParentNodeByPatch(node.Parent).ID.ToString() + pin.NameByParent(node)], parent.ID, cpin.NameByParent(parent));
                                    }
                                }
                            }
                            else     //..in the parentpatch
                            {
                                if (pin.Direction == PinDirection.Input)
                                {
                                    patch.AddLink(node.ID, cpin.Name, subID, node.LabelPin.Spread.Trim('|'));
                                }
                                else if (pin.Direction == PinDirection.Output)
                                {
                                    patch.AddLink(subID, node.LabelPin.Spread.Trim('|'), node.ID, cpin.Name);
                                }
                            }
                        }
                    }
                }
            }

            //..and remove selected nodes
            //if they are not labeled ioboxes that are connected in a parentpatch!
            foreach (var node in selectedNodes)
            {
                var delete = true;
                //if this is a labeled iobox check if any of its pins is connected in a parentpatch to not delete it in that case
                if ((node.NodeInfo.Name == "IOBox") &&
                    (!string.IsNullOrEmpty(node.LabelPin.Spread)))
                {
                    foreach (var pin in node.Pins)
                    {
                        foreach (var cpin in pin.ConnectedPins)
                        {
                            if (cpin.ParentNodeByPatch(node.Parent) == null)
                            {
                                delete = false;
                                break;
                            }
                        }
                    }
                }

                if (delete)
                {
                    var nodeMessage = patch.AddNode(node.ID);
                    nodeMessage.DeleteMe = true;
                }
            }

            var nodeMsg = patch.AddNode(subID);

            nodeMsg.ComponentMode = ComponentMode.Hidden;
            //enabling this fukcs it up:
            var nodeB = nodeMsg.AddBounds(BoundsType.Node);

            nodeB.Rectangle = new Rectangle(selectionCenter.X, selectionCenter.Y, 0, 0);
            var boxB = nodeMsg.AddBounds(BoundsType.Box);

            boxB.Rectangle = new Rectangle(selectionCenter.X - selectionSize.Width / 2, selectionCenter.Y - selectionSize.Height / 2, selectionSize.Width, selectionSize.Height);
            var windowB = nodeMsg.AddBounds(BoundsType.Window);

            windowB.Rectangle = new Rectangle(300 + selectionCenter.X + hdeHost.ActivePatchWindow.Bounds.X * 15, 300 + selectionCenter.Y + hdeHost.ActivePatchWindow.Bounds.Y * 15, selectionSize.Width, selectionSize.Height);

            hdeHost.SendXMLSnippet(hdeHost.ActivePatchWindow.Node.NodeInfo.Filename, patch.ToString(), true);
        }