/// <summary> /// Deserialize a function definition from a given path. A side effect of this function is that /// the node is added to the dictionary of loadedNodes. /// </summary> /// <param name="funcDefGuid">The function guid we're currently loading</param> /// <param name="controller">Reference to the calling controller</param> /// <param name="def">The resultant function definition</param> /// <returns></returns> private bool GetDefinitionFromPath(Guid funcDefGuid, DynamoController controller, out FunctionDefinition def) { try { var xmlPath = GetNodePath(funcDefGuid); #region read xml file var xmlDoc = new XmlDocument(); xmlDoc.Load(xmlPath); string funName = null; string category = ""; string description = ""; double cx = DynamoView.CANVAS_OFFSET_X; double cy = DynamoView.CANVAS_OFFSET_Y; double zoom = 1.0; string id = ""; // load the header foreach (XmlNode node in xmlDoc.GetElementsByTagName("dynWorkspace")) { foreach (XmlAttribute att in node.Attributes) { if (att.Name.Equals("X")) { cx = double.Parse(att.Value, CultureInfo.InvariantCulture); } else if (att.Name.Equals("Y")) { cy = double.Parse(att.Value, CultureInfo.InvariantCulture); } else if (att.Name.Equals("zoom")) { zoom = double.Parse(att.Value, CultureInfo.InvariantCulture); } else if (att.Name.Equals("Name")) { funName = att.Value; } else if (att.Name.Equals("Category")) { category = att.Value; } else if (att.Name.Equals("Description")) { description = att.Value; } else if (att.Name.Equals("ID")) { id = att.Value; } } } // we have a dyf and it lacks an ID field, we need to assign it // a deterministic guid based on its name. By doing it deterministically, // files remain compatible if (string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(funName)) { id = GuidUtility.Create(GuidUtility.UrlNamespace, funName).ToString(); } #endregion DynamoCommands.WriteToLogCmd.Execute("Loading node definition for \"" + funName + "\" from: " + xmlPath); var ws = new FuncWorkspace( funName, category.Length > 0 ? category : BuiltinNodeCategories.SCRIPTING_CUSTOMNODES, description, cx, cy) { WatchChanges = false }; ws.Zoom = zoom; def = new FunctionDefinition(Guid.Parse(id)) { Workspace = ws }; // load a dummy version, so any nodes depending on this node // will find an (empty) identifier on compilation FScheme.Expression dummyExpression = FScheme.Expression.NewNumber_E(0); controller.FSchemeEnvironment.DefineSymbol(def.FunctionId.ToString(), dummyExpression); this.loadedNodes.Add(def.FunctionId, def); XmlNodeList elNodes = xmlDoc.GetElementsByTagName("dynElements"); XmlNodeList cNodes = xmlDoc.GetElementsByTagName("dynConnectors"); XmlNodeList nNodes = xmlDoc.GetElementsByTagName("dynNotes"); XmlNode elNodesList = elNodes[0]; XmlNode cNodesList = cNodes[0]; XmlNode nNodesList = nNodes[0]; #region instantiate nodes var badNodes = new List <Guid>(); foreach (XmlNode elNode in elNodesList.ChildNodes) { XmlAttribute typeAttrib = elNode.Attributes["type"]; XmlAttribute guidAttrib = elNode.Attributes["guid"]; XmlAttribute nicknameAttrib = elNode.Attributes["nickname"]; XmlAttribute xAttrib = elNode.Attributes["x"]; XmlAttribute yAttrib = elNode.Attributes["y"]; XmlAttribute lacingAttrib = elNode.Attributes["lacing"]; XmlAttribute isVisAttrib = elNode.Attributes["isVisible"]; XmlAttribute isUpstreamVisAttrib = elNode.Attributes["isUpstreamVisible"]; string typeName = typeAttrib.Value; const string oldNamespace = "Dynamo.Elements."; if (typeName.StartsWith(oldNamespace)) { typeName = "Dynamo.Nodes." + typeName.Remove(0, oldNamespace.Length); } //test the GUID to confirm that it is non-zero //if it is zero, then we have to fix it //this will break the connectors, but it won't keep //propagating bad GUIDs var guid = new Guid(guidAttrib.Value); if (guid == Guid.Empty) { guid = Guid.NewGuid(); } string nickname = nicknameAttrib.Value; double x = double.Parse(xAttrib.Value, CultureInfo.InvariantCulture); double y = double.Parse(yAttrib.Value, CultureInfo.InvariantCulture); bool isVisible = true; if (isVisAttrib != null) { isVisible = isVisAttrib.Value == "true" ? true : false; } bool isUpstreamVisible = true; if (isUpstreamVisAttrib != null) { isUpstreamVisible = isUpstreamVisAttrib.Value == "true" ? true : false; } //Type t = Type.GetType(typeName); TypeLoadData tData; Type t; if (!controller.BuiltInTypesByName.TryGetValue(typeName, out tData)) { //try and get a system type by this name t = Type.GetType(typeName); //if we still can't find the type, try the also known as attributes if (t == null) { //try to get the also known as values foreach (KeyValuePair <string, TypeLoadData> kvp in controller.BuiltInTypesByName) { var akaAttribs = kvp.Value.Type.GetCustomAttributes(typeof(AlsoKnownAsAttribute), false); if (akaAttribs.Any()) { if ((akaAttribs[0] as AlsoKnownAsAttribute).Values.Contains(typeName)) { controller.DynamoViewModel.Log(string.Format("Found matching node for {0} also known as {1}", kvp.Key, typeName)); t = kvp.Value.Type; } } } } if (t == null) { controller.DynamoViewModel.Log("Could not load node of type: " + typeName); controller.DynamoViewModel.Log("Loading will continue but nodes might be missing from your workflow."); //return false; badNodes.Add(guid); continue; } } else { t = tData.Type; } dynNodeModel el = dynSettings.Controller.DynamoViewModel.CreateNodeInstance(t, nickname, guid); if (lacingAttrib != null) { LacingStrategy lacing = LacingStrategy.First; Enum.TryParse(lacingAttrib.Value, out lacing); el.ArgumentLacing = lacing; } el.IsVisible = isVisible; el.IsUpstreamVisible = isUpstreamVisible; // note - this is because the connectors fail to be created if there's not added // to the canvas ws.Nodes.Add(el); el.WorkSpace = ws; var node = el; node.X = x; node.Y = y; if (el == null) { return(false); } el.DisableReporting(); el.Load(elNode); // inject the node properties from the xml // moved this logic to LoadNode in dynFunction --SJE //if (el is dynFunction) //{ // var fun = el as dynFunction; // // we've found a custom node, we need to attempt to load its guid. // // if it doesn't exist (i.e. its a legacy node), we need to assign it one, // // deterministically // Guid funId; // try // { // funId = Guid.Parse(fun.Symbol); // } // catch // { // funId = GuidUtility.Create(GuidUtility.UrlNamespace, nicknameAttrib.Value); // fun.Symbol = funId.ToString(); // } // // if it's not a recurisve node and it's not yet loaded, load it // if (funcDefGuid != funId && !this.loadedNodes.ContainsKey(funId)) // { // dynSettings.Controller.CustomNodeLoader.GetFunctionDefinition(funId); // fun.Definition = this.loadedNodes[funId]; // } // else if ( this.loadedNodes.ContainsKey(funId )) // { // fun.Definition = this.loadedNodes[funId]; // } //} } #endregion #region instantiate connectors foreach (XmlNode connector in cNodesList.ChildNodes) { XmlAttribute guidStartAttrib = connector.Attributes[0]; XmlAttribute intStartAttrib = connector.Attributes[1]; XmlAttribute guidEndAttrib = connector.Attributes[2]; XmlAttribute intEndAttrib = connector.Attributes[3]; XmlAttribute portTypeAttrib = connector.Attributes[4]; var guidStart = new Guid(guidStartAttrib.Value); var guidEnd = new Guid(guidEndAttrib.Value); int startIndex = Convert.ToInt16(intStartAttrib.Value); int endIndex = Convert.ToInt16(intEndAttrib.Value); int portType = Convert.ToInt16(portTypeAttrib.Value); //find the elements to connect dynNodeModel start = null; dynNodeModel end = null; if (badNodes.Contains(guidStart) || badNodes.Contains(guidEnd)) { continue; } foreach (dynNodeModel e in ws.Nodes) { if (e.GUID == guidStart) { start = e; } else if (e.GUID == guidEnd) { end = e; } if (start != null && end != null) { break; } } try { var newConnector = dynConnectorModel.Make( start, end, startIndex, endIndex, portType); if (newConnector != null) { ws.Connectors.Add(newConnector); } } catch { DynamoCommands.WriteToLogCmd.Execute(string.Format("ERROR : Could not create connector between {0} and {1}.", start.NickName, end.NickName)); } } #endregion #region instantiate notes if (nNodesList != null) { foreach (XmlNode note in nNodesList.ChildNodes) { XmlAttribute textAttrib = note.Attributes[0]; XmlAttribute xAttrib = note.Attributes[1]; XmlAttribute yAttrib = note.Attributes[2]; string text = textAttrib.Value; double x = Convert.ToDouble(xAttrib.Value); double y = Convert.ToDouble(yAttrib.Value); //dynNoteView n = Bench.AddNote(text, x, y, ws); //Bench.AddNote(text, x, y, ws); var paramDict = new Dictionary <string, object>(); paramDict.Add("x", x); paramDict.Add("y", y); paramDict.Add("text", text); paramDict.Add("workspace", ws); dynSettings.Controller.DynamoViewModel.AddNoteCommand.Execute(paramDict); } } #endregion foreach (dynNodeModel e in ws.Nodes) { e.EnableReporting(); } ws.FilePath = xmlPath; var expression = CompileFunction(def); controller.FSchemeEnvironment.DefineSymbol(def.FunctionId.ToString(), expression); ws.WatchChanges = true; } catch (Exception ex) { DynamoCommands.WriteToLogCmd.Execute("There was an error opening the workbench."); DynamoCommands.WriteToLogCmd.Execute(ex); if (controller.Testing) { Assert.Fail(ex.Message); } def = null; return(false); } return(true); }
/// <summary> /// Collapse a set of nodes in a given workspace. Has the side effects of prompting the user /// first in order to obtain the name and category for the new node, /// writes the function to a dyf file, adds it to the FunctionDict, adds it to search, and compiles and /// places the newly created symbol (defining a lambda) in the Controller's FScheme Environment. /// </summary> /// <param name="selectedNodes"> The function definition for the user-defined node </param> /// <param name="currentWorkspace"> The workspace where</param> internal static void Collapse(IEnumerable <dynNodeModel> selectedNodes, dynWorkspaceModel currentWorkspace) { var selectedNodeSet = new HashSet <dynNodeModel>(selectedNodes); //First, prompt the user to enter a name string newNodeName = "", newNodeCategory = "", newNodeDescription = "A collapsed node"; if (!dynSettings.Controller.DynamoViewModel.ShowNewFunctionDialog(ref newNodeName, ref newNodeCategory, ref newNodeDescription)) { return; } var newNodeWorkspace = new FuncWorkspace(newNodeName, newNodeCategory, newNodeDescription, 0, 0) { WatchChanges = false }; var newNodeDefinition = new FunctionDefinition(Guid.NewGuid()) { Workspace = newNodeWorkspace }; currentWorkspace.DisableReporting(); #region Determine Inputs and Outputs //Step 1: determine which nodes will be inputs to the new node var inputs = new HashSet <Tuple <dynNodeModel, int, Tuple <int, dynNodeModel> > >( selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.InPortData.Count).Where(node.HasInput) .Select(data => Tuple.Create(node, data, node.Inputs[data])) .Where(input => !selectedNodeSet.Contains(input.Item3.Item2)))); var outputs = new HashSet <Tuple <dynNodeModel, int, Tuple <int, dynNodeModel> > >( selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.OutPortData.Count).Where(node.HasOutput).SelectMany( data => node.Outputs[data] .Where(output => !selectedNodeSet.Contains(output.Item2)) .Select(output => Tuple.Create(node, data, output))))); #endregion #region Detect 1-node holes (higher-order function extraction) var curriedNodeArgs = new HashSet <dynNodeModel>( inputs .Select(x => x.Item3.Item2) .Intersect(outputs.Select(x => x.Item3.Item2))) .Select( outerNode => { var node = new dynApply1(); //MVVM : Don't make direct reference to view here //MVVM: no reference to view here //dynNodeView nodeUI = node.NodeUI; var elNameAttrib = node.GetType().GetCustomAttributes(typeof(NodeNameAttribute), true)[0] as NodeNameAttribute; if (elNameAttrib != null) { node.NickName = elNameAttrib.Name; } node.GUID = Guid.NewGuid(); //store the element in the elements list newNodeWorkspace.Nodes.Add(node); node.WorkSpace = newNodeWorkspace; node.DisableReporting(); //MVVM : Can't set view location here //dynSettings.Bench.WorkBench.Children.Add(nodeUI); //Place it in an appropriate spot //Canvas.SetLeft(nodeUI, Canvas.GetLeft(outerNode.NodeUI)); //Canvas.SetTop(nodeUI, Canvas.GetTop(outerNode.NodeUI)); node.X = outerNode.X; node.Y = outerNode.Y; //Fetch all input ports // in order // that have inputs // and whose input comes from an inner node List <int> inPortsConnected = Enumerable.Range(0, outerNode.InPortData.Count) .Where( x => outerNode.HasInput(x) && selectedNodeSet.Contains( outerNode.Inputs[x].Item2)) .ToList(); var nodeInputs = outputs .Where(output => output.Item3.Item2 == outerNode) .Select( output => new { InnerNodeInputSender = output.Item1, OuterNodeInPortData = output.Item3.Item1 }).ToList(); nodeInputs.ForEach(_ => node.AddInput()); node.RegisterAllPorts(); //MVVM: don't call update layout here //dynSettings.Bench.WorkBench.UpdateLayout(); return(new { OuterNode = outerNode, InnerNode = node, Outputs = inputs.Where(input => input.Item3.Item2 == outerNode) .Select(input => input.Item3.Item1), Inputs = nodeInputs, OuterNodePortDataList = inPortsConnected }); }).ToList(); #endregion #region UI Positioning Calculations double avgX = selectedNodeSet.Average(node => node.X); double avgY = selectedNodeSet.Average(node => node.Y); double leftMost = selectedNodeSet.Min(node => node.X); double topMost = selectedNodeSet.Min(node => node.Y); double rightMost = selectedNodeSet.Max(node => node.X + node.Width); #endregion #region Move selection to new workspace var connectors = new HashSet <dynConnectorModel>(currentWorkspace.Connectors.Where( conn => selectedNodeSet.Contains(conn.Start.Owner) && selectedNodeSet.Contains(conn.End.Owner))); //Step 2: move all nodes to new workspace // remove from old foreach (var ele in selectedNodeSet) { currentWorkspace.Nodes.Remove(ele); } foreach (var ele in connectors) { currentWorkspace.Connectors.Remove(ele); } // add to new newNodeWorkspace.Nodes.AddRange(selectedNodeSet); newNodeWorkspace.Connectors.AddRange(connectors); double leftShift = leftMost - 250; foreach (dynNodeModel node in newNodeWorkspace.Nodes) { node.X = node.X - leftShift; node.Y = node.Y - topMost; } #endregion #region Insert new node into the current workspace //Step 5: insert new node into original workspace var collapsedNode = dynSettings.Controller.DynamoViewModel.CreateFunction( inputs.Select(x => x.Item1.InPortData[x.Item2].NickName), outputs .Where(x => !curriedNodeArgs.Any(y => y.OuterNode == x.Item3.Item2)) .Select(x => x.Item1.OutPortData[x.Item2].NickName), newNodeDefinition); collapsedNode.GUID = Guid.NewGuid(); currentWorkspace.Nodes.Add(collapsedNode); collapsedNode.WorkSpace = currentWorkspace; collapsedNode.X = avgX; collapsedNode.Y = avgY; #endregion #region Destroy all hanging connectors //Step 6: connect inputs and outputs var removeConnectors = currentWorkspace.Connectors.Where(c => selectedNodeSet.Contains(c.Start.Owner) || selectedNodeSet.Contains(c.End.Owner)) .ToList(); foreach (dynConnectorModel connector in removeConnectors) { connector.NotifyConnectedPortsOfDeletion(); currentWorkspace.Connectors.Remove(connector); } #endregion newNodeWorkspace.Nodes.ToList().ForEach(x => x.DisableReporting()); var inConnectors = new List <Tuple <dynNodeModel, int, int> >(); #region Process inputs var uniqueInputSenders = new Dictionary <Tuple <dynNodeModel, int>, dynSymbol>(); //Step 3: insert variables (reference step 1) foreach (var input in Enumerable.Range(0, inputs.Count).Zip(inputs, Tuple.Create)) { int inputIndex = input.Item1; dynNodeModel inputReceiverNode = input.Item2.Item1; int inputReceiverData = input.Item2.Item2; dynNodeModel inputNode = input.Item2.Item3.Item2; int inputData = input.Item2.Item3.Item1; dynSymbol node; var key = Tuple.Create(inputNode, inputData); if (uniqueInputSenders.ContainsKey(key)) { node = uniqueInputSenders[key]; } else { //MVVM : replace NodeUI reference with node inConnectors.Add(Tuple.Create(inputNode, inputData, inputIndex)); //Create Symbol Node node = new dynSymbol { Symbol = inputReceiverNode.InPortData[inputReceiverData].NickName }; //MVVM : Don't make direct reference to view here //dynNodeView nodeUI = node.NodeUI; var elNameAttrib = node.GetType().GetCustomAttributes(typeof(NodeNameAttribute), true)[0] as NodeNameAttribute; if (elNameAttrib != null) { node.NickName = elNameAttrib.Name; } node.GUID = Guid.NewGuid(); //store the element in the elements list newNodeWorkspace.Nodes.Add(node); node.WorkSpace = newNodeWorkspace; node.DisableReporting(); //MVVM : Do not add view directly to canvas /*dynSettings.Bench.WorkBench.Children.Add(nodeUI); * * //Place it in an appropriate spot * Canvas.SetLeft(nodeUI, 0); * Canvas.SetTop(nodeUI, inputIndex * (50 + node.NodeUI.Height)); * * dynSettings.Bench.WorkBench.UpdateLayout();*/ node.X = 0; node.Y = inputIndex * (50 + node.Height); uniqueInputSenders[key] = node; } var curriedNode = curriedNodeArgs.FirstOrDefault(x => x.OuterNode == inputNode); if (curriedNode == null) { var conn1 = dynConnectorModel.Make(node, inputReceiverNode, 0, inputReceiverData, 0); if (conn1 != null) { newNodeWorkspace.Connectors.Add(conn1); } } else { //Connect it to the applier var conn = dynConnectorModel.Make(node, curriedNode.InnerNode, 0, 0, 0); if (conn != null) { newNodeWorkspace.Connectors.Add(conn); } //Connect applier to the inner input receive var conn2 = dynConnectorModel.Make( curriedNode.InnerNode, inputReceiverNode, 0, inputReceiverData, 0); if (conn2 != null) { newNodeWorkspace.Connectors.Add(conn2); } } } #endregion #region Process outputs //List of all inner nodes to connect an output. Unique. var outportList = new List <Tuple <dynNodeModel, int> >(); var outConnectors = new List <Tuple <dynNodeModel, int, int> >(); int i = 0; foreach (var output in outputs) { if (outportList.All(x => !(x.Item1 == output.Item1 && x.Item2 == output.Item2))) { dynNodeModel outputSenderNode = output.Item1; int outputSenderData = output.Item2; dynNodeModel outputReceiverNode = output.Item3.Item2; if (curriedNodeArgs.Any(x => x.OuterNode == outputReceiverNode)) { continue; } outportList.Add(Tuple.Create(outputSenderNode, outputSenderData)); //Create Symbol Node var node = new dynOutput { Symbol = outputSenderNode.OutPortData[outputSenderData].NickName }; //dynNodeView nodeUI = node.NodeUI; var elNameAttrib = node.GetType().GetCustomAttributes(typeof(NodeNameAttribute), false)[0] as NodeNameAttribute; if (elNameAttrib != null) { node.NickName = elNameAttrib.Name; } node.GUID = Guid.NewGuid(); //store the element in the elements list newNodeWorkspace.Nodes.Add(node); node.WorkSpace = newNodeWorkspace; node.DisableReporting(); //MVVM : Do not add view directly to canvas /*dynSettings.Bench.WorkBench.Children.Add(nodeUI); * * //Place it in an appropriate spot * Canvas.SetLeft(nodeUI, rightMost + 75 - leftShift); * Canvas.SetTop(nodeUI, i * (50 + node.NodeUI.Height)); * * dynSettings.Bench.WorkBench.UpdateLayout();*/ node.X = rightMost + 75 - leftShift; node.Y = i * (50 + node.Height); var conn = dynConnectorModel.Make( outputSenderNode, node, outputSenderData, 0, 0); if (conn != null) { newNodeWorkspace.Connectors.Add(conn); } i++; } } //Connect outputs to new node foreach (var output in outputs) { //Node to be connected to in CurrentSpace dynNodeModel outputSenderNode = output.Item1; //Port to be connected to on outPutNode_outer int outputSenderData = output.Item2; int outputReceiverData = output.Item3.Item1; dynNodeModel outputReceiverNode = output.Item3.Item2; var curriedNode = curriedNodeArgs.FirstOrDefault( x => x.OuterNode == outputReceiverNode); if (curriedNode == null) { // we create the connectors in the current space later //MVVM : replaced multiple dynNodeView refrences with dynNode outConnectors.Add( Tuple.Create( outputReceiverNode, outportList.FindIndex( x => x.Item1 == outputSenderNode && x.Item2 == outputSenderData), outputReceiverData)); } else { int targetPort = curriedNode.Inputs .First( x => x.InnerNodeInputSender == outputSenderNode) .OuterNodeInPortData; int targetPortIndex = curriedNode.OuterNodePortDataList.IndexOf(targetPort); //Connect it (new dynConnector) var conn = dynConnectorModel.Make( outputSenderNode, curriedNode.InnerNode, outputSenderData, targetPortIndex + 1, 0); if (conn != null) { newNodeWorkspace.Connectors.Add(conn); } } } #endregion //set the name on the node collapsedNode.NickName = newNodeName; currentWorkspace.Nodes.Remove(collapsedNode); // save and load the definition from file var customNodeInfo = new CustomNodeInfo(newNodeDefinition.FunctionId, newNodeName, newNodeCategory, "", ""); dynSettings.Controller.CustomNodeManager.SetNodeInfo(customNodeInfo); var path = dynSettings.Controller.DynamoViewModel.SaveFunctionOnly(newNodeDefinition); dynSettings.Controller.CustomNodeManager.SetNodePath(newNodeDefinition.FunctionId, path); dynSettings.Controller.SearchViewModel.Add(newNodeName, newNodeCategory, "No description provided", newNodeDefinition.FunctionId); dynSettings.Controller.DynamoViewModel.CreateNodeCommand.Execute(new Dictionary <string, object>() { { "name", collapsedNode.Definition.FunctionId.ToString() }, { "x", avgX }, { "y", avgY } }); var newlyPlacedCollapsedNode = currentWorkspace.Nodes .Where(node => node is dynFunction) .First(node => ((dynFunction)node).Definition.FunctionId == newNodeDefinition.FunctionId); // place the node as intended, not centered newlyPlacedCollapsedNode.X = avgX; newlyPlacedCollapsedNode.Y = avgY; newlyPlacedCollapsedNode.DisableReporting(); foreach (var nodeTuple in inConnectors) { var conn = dynConnectorModel.Make( nodeTuple.Item1, newlyPlacedCollapsedNode, nodeTuple.Item2, nodeTuple.Item3, 0); if (conn != null) { currentWorkspace.Connectors.Add(conn); } } foreach (var nodeTuple in outConnectors) { var conn = dynConnectorModel.Make( newlyPlacedCollapsedNode, nodeTuple.Item1, nodeTuple.Item2, nodeTuple.Item3, 0); if (conn != null) { currentWorkspace.Connectors.Add(conn); } } newlyPlacedCollapsedNode.EnableReporting(); currentWorkspace.EnableReporting(); newNodeWorkspace.WatchChanges = true; }
internal FunctionDefinition NewFunction(Guid id, string name, string category, bool display, double workspaceOffsetX = dynBench.CANVAS_OFFSET_X, double workspaceOffsetY = dynBench.CANVAS_OFFSET_Y ) { //Add an entry to the funcdict var workSpace = new FuncWorkspace( name, category, workspaceOffsetX, workspaceOffsetY); List<dynNode> newElements = workSpace.Nodes; List<dynConnector> newConnectors = workSpace.Connectors; var functionDefinition = new FunctionDefinition(id) { Workspace = workSpace }; this.CustomNodeLoader.AddFunctionDefinition(functionDefinition.FunctionId, functionDefinition); // add the element to search SearchViewModel.Add(workSpace); if (display) { if (!ViewingHomespace) { var def = dynSettings.Controller.CustomNodeLoader.GetDefinitionFromWorkspace(CurrentSpace); if (def != null) SaveFunction( def ); } DynamoController.hideWorkspace(CurrentSpace); CurrentSpace = workSpace; Bench.homeButton.IsEnabled = true; Bench.workspaceLabel.Content = CurrentSpace.Name; Bench.editNameButton.Visibility = Visibility.Visible; Bench.editNameButton.IsHitTestVisible = true; Bench.setFunctionBackground(); dynSettings.ReturnFocusToSearch(); } return functionDefinition; }
internal dynWorkspace NewFunction(string name, string category, bool display) { //Add an entry to the funcdict var workSpace = new FuncWorkspace(name, category, dynBench.CANVAS_OFFSET_X, dynBench.CANVAS_OFFSET_Y); var newElements = workSpace.Nodes; var newConnectors = workSpace.Connectors; this.FunctionDict[name] = workSpace; //Add an entry to the View menu System.Windows.Controls.MenuItem i = new System.Windows.Controls.MenuItem(); i.Header = name; i.Click += new RoutedEventHandler(Bench.ChangeView_Click); Bench.viewMenu.Items.Add(i); Bench.viewMenuItemsDict[name] = i; //Add an entry to the Add menu //System.Windows.Controls.MenuItem mi = new System.Windows.Controls.MenuItem(); //mi.Header = name; //mi.Click += new RoutedEventHandler(AddElement_Click); //AddMenu.Items.Add(mi); //this.addMenuItemsDict[name] = mi; dynFunction newEl = new dynFunction( workSpace.Nodes.Where(el => el is dynSymbol) .Select(s => ((dynSymbol)s).Symbol), new List<String>() { "out" }, name ); newEl.NodeUI.DisableInteraction(); newEl.NodeUI.MouseDown += delegate { Bench.BeginDragElement(newEl.NodeUI, name, Mouse.GetPosition(newEl.NodeUI)); newEl.NodeUI.Visibility = System.Windows.Visibility.Hidden; }; newEl.NodeUI.GUID = Guid.NewGuid(); newEl.NodeUI.Margin = new Thickness(5, 30, 5, 5); newEl.NodeUI.LayoutTransform = new ScaleTransform(.8, .8); newEl.NodeUI.State = ElementState.DEAD; Expander expander; if (Bench.addMenuCategoryDict.ContainsKey(category)) { expander = Bench.addMenuCategoryDict[category]; } else { expander = new Expander() { Header = category, Height = double.NaN, Margin = new Thickness(0, 5, 0, 0), Content = new WrapPanel() { Height = double.NaN, Width = 240 }, HorizontalAlignment = System.Windows.HorizontalAlignment.Left, //FontWeight = FontWeights.Bold }; Bench.addMenuCategoryDict[category] = expander; var sortedExpanders = new SortedList<string, Expander>(); foreach (Expander child in Bench.SideStackPanel.Children) { sortedExpanders.Add((string)child.Header, child); } sortedExpanders.Add(category, expander); Bench.SideStackPanel.Children.Clear(); foreach (Expander child in sortedExpanders.Values) { Bench.SideStackPanel.Children.Add(child); } } var wp = (WrapPanel)expander.Content; var sortedElements = new SortedList<string, dynNodeUI>(); foreach (dynNodeUI child in wp.Children) { sortedElements.Add(child.NickName, child); } sortedElements.Add(name, newEl.NodeUI); wp.Children.Clear(); foreach (dynNodeUI child in sortedElements.Values) { wp.Children.Add(child); } Bench.addMenuItemsDictNew[name] = newEl.NodeUI; searchDict.Add(newEl.NodeUI, name.Split(' ').Where(x => x.Length > 0)); if (display) { //Store old workspace //var ws = new dynWorkspace(this.elements, this.connectors, this.CurrentX, this.CurrentY); if (!this.ViewingHomespace) { //Step 2: Store function workspace in the function dictionary this.FunctionDict[this.CurrentSpace.Name] = this.CurrentSpace; //Step 3: Save function this.SaveFunction(this.CurrentSpace); } //Make old workspace invisible foreach (dynNode dynE in this.Nodes) { dynE.NodeUI.Visibility = System.Windows.Visibility.Collapsed; } foreach (dynConnector dynC in this.CurrentSpace.Connectors) { dynC.Visible = false; } foreach (dynNote note in this.CurrentSpace.Notes) { note.Visibility = System.Windows.Visibility.Hidden; } //this.currentFunctionName = name; ////Clear the bench for the new function //this.elements = newElements; //this.connectors = newConnectors; //this.CurrentX = CANVAS_OFFSET_X; //this.CurrentY = CANVAS_OFFSET_Y; this.CurrentSpace = workSpace; //this.saveFuncItem.IsEnabled = true; Bench.homeButton.IsEnabled = true; //this.varItem.IsEnabled = true; Bench.workspaceLabel.Content = this.CurrentSpace.Name; Bench.editNameButton.Visibility = System.Windows.Visibility.Visible; Bench.editNameButton.IsHitTestVisible = true; Bench.setFunctionBackground(); } return workSpace; }