private bool ReopenCurrentGraph()
        {
            if (GraphTabs.Count == 0)
            {
                return(false);
            }
            GraphTab activeTab = GraphTabs[GraphTabs.Count - 1];
            Graph    graph     = activeTab.IsRootTab ? activeTab.Graph : activeTab.SubGraphNode.SubGraph;

            if (graph == null)
            {
                GraphTabs.Clear();
                return(false);
            }

            OpenGraph(graph, false, false, false, false);

            //remove any node, that has been soft deleted, from the graph's Nodes list
            foreach (Node deletedNode in DeletedNodes)
            {
                if (!CurrentGraph.Nodes.Contains(deletedNode))
                {
                    continue;
                }
                CurrentGraph.Nodes.Remove(deletedNode);
                CurrentGraph.SetDirty(false);
            }

            GraphEvent.Send(GraphEvent.EventType.EVENT_GRAPH_OPENED);

            m_graphAssetPath = AssetDatabase.GetAssetPath(CurrentGraph);

            return(true);
        }
Exemple #2
0
        private void UpdateSwitchBackModeState(bool value)
        {
            if (value)
            {
                if (TargetNode.InputSockets == null ||
                    TargetNode.InputSockets.Count == 0)
                {
                    TargetNode.AddInputSocket(ConnectionMode.Multiple, typeof(PassthroughConnection), false, false);
                }
            }
            else
            {
                if (TargetNode.InputSockets != null &&
                    TargetNode.InputSockets.Count > 0)
                {
                    if (TargetNode.FirstInputSocket != null &&
                        TargetNode.FirstInputSocket.IsConnected)
                    {
                        GraphEvent.DisconnectSocket(TargetNode.FirstInputSocket);
                    }

                    TargetNode.InputSockets.Clear();
                }

                NodeUpdated = true;
            }
        }
 private void OpenGraph(Graph graph, bool closeCurrentlyOpenedGraph, bool clearGraphTabs, bool centerAllNodesInWindow, bool recordUndo = true)
 {
     if (graph == null)
     {
         return;
     }
     if (CurrentGraph == graph)
     {
         return;
     }
     if (closeCurrentlyOpenedGraph)
     {
         CloseCurrentGraph(clearGraphTabs);
     }
     if (recordUndo)
     {
         RecordUndo("Open Graph");
     }
     WindowSettings.AddGraphToRecentlyOpenedGraphs(graph);
     CurrentGraph = graph;
     GraphUtils.CheckAndCreateAnyMissingSystemNodes(graph);
     ConstructGraphGUI();
     if (centerAllNodesInWindow)
     {
         CenterAllNodesInWindow();
     }
     //            Undo.IncrementCurrentGroup();
     //            Undo.SetCurrentGroupName(m_graphAssetName);
     SetView(View.Graph);
     Repaint();
     GraphEvent.Send(GraphEvent.EventType.EVENT_GRAPH_OPENED);
     m_graphAssetPath = AssetDatabase.GetAssetPath(CurrentGraph);
 }
Exemple #4
0
        public void RemoveSocket(Socket socket, bool recordUndo, bool saveAssets = false, bool ignoreCanDeleteSocketFlag = false)
        {
            if (!ignoreCanDeleteSocketFlag && !NodesDatabase[socket.NodeId].CanDeleteSocket(socket))
            {
                return;
            }
            if (recordUndo)
            {
                RecordUndo(UILabels.Delete + " " + UILabels.Socket);
            }
            DisconnectSocket(socket, false);
            PointsDatabase.Remove(socket.Id);
            SocketsDatabase.Remove(socket.Id);
            Node node = NodesDatabase[socket.NodeId];

            if (node == null)
            {
                return;               //sanity check
            }
            if (socket.IsInput)
            {
                node.InputSockets.Remove(socket);
            }
            if (socket.IsOutput)
            {
                node.OutputSockets.Remove(socket);
            }
            EditorUtility.SetDirty(node);
            CurrentGraph.SetDirty(saveAssets);
            GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_UPDATED, socket.NodeId);
        }
Exemple #5
0
        public void DisconnectSocket(Socket socket, bool recordUndo, bool saveAssets = false)
        {
            if (!socket.IsConnected)
            {
                return;
            }

            if (recordUndo)
            {
                RecordUndo(GraphAction.Disconnect.ToString());
            }
            List <string> socketConnectionIds = socket.GetConnectionIds();

            foreach (string connectionId in socketConnectionIds)
            {
                if (!ConnectionsDatabase.ContainsKey(connectionId))
                {
                    continue;
                }
                VirtualConnection vc = ConnectionsDatabase[connectionId];
                vc.OutputSocket.RemoveConnection(connectionId);
                vc.InputSocket.RemoveConnection(connectionId);
                EditorUtility.SetDirty(vc.OutputNode);
                EditorUtility.SetDirty(vc.InputNode);
                ConnectionsDatabase.Remove(connectionId);
            }

            CurrentGraph.SetDirty(saveAssets);
            GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_DISCONNECTED, socket.NodeId);
        }
    Node NodeLifecycle(Node node, GraphEvent ev)
    {
        return(ev.Match <Node>()
               .Case <CreateVertex, Node>(cv => {
            var newObj = Object.Instantiate(vertexModel);
            newObj.transform.SetParent(vertexModel.transform.parent);

            // Name changes
            var labels = new Subject <string>();
            labels.Subscribe(label => {
                node.gameObject.GetComponentsInChildren <TextMesh>().ToList().ForEach(text => text.text = label);
            });

            // When edges come
            var edges = new Subject <EdgeController>();
            edges.Take(1).Subscribe(edge =>
            {
                var other = edge.vertexA == newObj ? edge.vertexB : edge.vertexA;
                newObj.transform.position = other.transform.position + (other.transform.position + new Vector3(Random.value - 0.5f, Random.value - 0.5f, Random.value - 0.5f)).normalized;
                newObj.SetActive(true);
            });

            return nodes[cv.id] = new Node(
                id: cv.id,
                gameObject: newObj,
                labels: labels,
                edges: edges
                );
        })
               .Case <CreateEdge, Node>(ce => {
            var newObj = Object.Instantiate(edgeModel);
            newObj.SetActive(true);
            newObj.transform.SetParent(edgeModel.transform.parent);
            var edge = newObj.GetComponent <EdgeController>();

            var nodeA = nodes[ce.sourceId];
            var nodeB = nodes[ce.targetId];

            edge.vertexA = nodeA.gameObject;
            edge.vertexB = nodeB.gameObject;

            nodeA.edges.OnNext(edge);
            nodeB.edges.OnNext(edge);

            return nodes[ce.id] = new Node(
                id: ce.id,
                gameObject: newObj
                );
        })
               .Case <UpdateValue, Node>(uv => {
            if (uv.name == "name")
            {
                node.gameObject.GetComponentsInChildren <TextMesh>().ToList().ForEach(text => text.text = (string)uv.value);
            }
            return node;
        })
               .Default(node)
               .result);
    }
 protected void SendGraphEventNodeUpdated()
 {
     if (!NodeUpdated)
     {
         return;
     }
     GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_UPDATED, GetProperty(PropertyName.m_id).stringValue);
     NodeUpdated = false;
 }
 private static void SaveGraph()
 {
     AssetDatabase.SaveAssets();
     GraphEvent.Send(GraphEvent.EventType.EVENT_SAVED_ASSETS);
     if (CurrentGraph == null)
     {
         return;
     }
     CurrentGraph.IsDirty = false;
 }
        private async Task LoadScheduleAsync()
        {
            IsBusy = true;

            _events = PopulateScheduleCalendar();
            try
            {
                var startDateTime = DateTime.Today;
                var endDateTime   = startDateTime.AddMonths(AppSettings.ScheduleMonths);
                var result        = await _calendarService.GetCarpoolEventsAsync(startDateTime, endDateTime);

                HasEvents = result.Any();

                if (result != null)
                {
                    foreach (var ev in result.CurrentPage
                             .Where(e => e.Body.Content.Contains(AppSettings.CarpoolEventBody)))
                    {
                        var graphEvent         = new GraphEvent(ev);
                        var scheduleGraphEvent = _events.FirstOrDefault(e => e.Key.Date.Equals(graphEvent.StartDate.Date))?.FirstOrDefault();
                        if (scheduleGraphEvent != null)
                        {
                            if (graphEvent.BodyPreview.Contains("Pickup"))
                            {
                                scheduleGraphEvent.To = graphEvent;
                            }
                            else
                            {
                                scheduleGraphEvent.From = graphEvent;
                            }
                        }
                    }
                }
            }
            catch (ServiceException)
            {
                await _dialogService.ShowAlertAsync("Calendar unavailable, please check your office365 subscription.", "Service error", "Ok");
            }
            catch
            {
                if (!IsConnected)
                {
                    await _dialogService.ShowAlertAsync("No network connection, please check your internet.", "Service unavailable", "Ok");
                }
                else
                {
                    await _dialogService.ShowAlertAsync("An error occured", "Unexpected error", "Try again");
                }
            }
            finally
            {
                Events = _events;
                IsBusy = false;
            }
        }
Exemple #10
0
        protected void DrawAddSocketButton(SocketDirection direction, ConnectionMode connectionMode, Type valueType)
        {
            var area = new Rect(6, DynamicHeight, Node.GetWidth() - 12, NodySettings.Instance.SocketHeight);

            DynamicHeight += area.height; //Update HEIGHT

            if (ZoomedBeyondSocketDrawThreshold)
            {
                return;
            }

            bool  isInput   = direction == SocketDirection.Input;
            Color iconColor = DGUI.Colors.IconColor(isInput ? DGUI.Colors.GetDColor(DGUI.Colors.NodyInputColorName) : DGUI.Colors.GetDColor(DGUI.Colors.NodyOutputColorName)).WithAlpha(NodySettings.Instance.NormalOpacity);


            var iconRect = new Rect(area.x + area.width / 2 - NodySettings.Instance.NodeAddSocketButtonSize / 2,
                                    area.y + area.height / 2 - NodySettings.Instance.NodeAddSocketButtonSize / 2,
                                    NodySettings.Instance.NodeAddSocketButtonSize,
                                    NodySettings.Instance.NodeAddSocketButtonSize);
            var hoveredIconRect = new Rect(iconRect.x - iconRect.width * 0.4f / 2,
                                           iconRect.y - iconRect.height * 0.4f / 2,
                                           iconRect.width * 1.4f,
                                           iconRect.height * 1.4f);

            bool mouseIsOverButton = hoveredIconRect.Contains(Event.current.mousePosition);

            if (mouseIsOverButton)
            {
                iconColor.a = NodySettings.Instance.HoverOpacity;
            }


            Color color = GUI.color;

            GUI.color = iconColor;
            if (GUI.Button(mouseIsOverButton ? hoveredIconRect : iconRect, GUIContent.none, NodeIconPlus))
            {
                Undo.RecordObject(Node, "Add " + direction + " Socket");
                if (isInput)
                {
                    Node.AddInputSocket(connectionMode, valueType, true, true);
                }
                else
                {
                    Node.AddOutputSocket(connectionMode, valueType, true, true);
                }
                GraphEvent.Send(GraphEvent.EventType.EVENT_SOCKET_CREATED, Node.Id);
            }

            GUI.color = color;
        }
Exemple #11
0
        private void ReorderSocketMove(Socket socket, bool moveUp, bool recordUndo, bool saveAssets = false)
        {
            if (socket == null)
            {
                return;
            }
            if (!socket.CanBeReordered)
            {
                return;
            }
            Node node = NodesDatabase[socket.NodeId];

            if (node == null)
            {
                return;
            }
            List <Socket> sockets     = socket.IsInput ? node.InputSockets : node.OutputSockets;
            int           socketIndex = sockets.IndexOf(socket);

            if (moveUp && socketIndex == 0)
            {
                return;                                              //moving up and this is the first socket - it cannot go up in the sockets order
            }
            if (!moveUp && socketIndex == sockets.Count - 1)
            {
                return;                                              //moving down and this is the last socket - it cannot go down in the sockets order
            }
            if (recordUndo)
            {
                RecordUndo(moveUp ? UILabels.MoveUp : UILabels.MoveDown);
            }
            if (moveUp) //MOVE UP
            {
                Socket previousSocket = sockets[socketIndex - 1];
                sockets[socketIndex - 1] = new Socket(socket);
                sockets[socketIndex]     = new Socket(previousSocket);
            }
            else //MOVE DOWN
            {
                Socket nextSocket = sockets[socketIndex + 1];
                sockets[socketIndex + 1] = new Socket(socket);
                sockets[socketIndex]     = new Socket(nextSocket);
            }

            EditorUtility.SetDirty(node);
            CurrentGraph.SetDirty(saveAssets);
            ConstructGraphGUI();
            RecalculateAllPointRects();
            GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_UPDATED, socket.NodeId);
        }
Exemple #12
0
 private void ClearNodeConnections(Node node, bool recordUndo, bool saveAssets = false)
 {
     if (recordUndo)
     {
         RecordUndo(GraphAction.Disconnect.ToString());
     }
     foreach (Socket inputSocket in node.InputSockets)
     {
         DisconnectSocket(inputSocket, false);
     }
     foreach (Socket outputSocket in node.OutputSockets)
     {
         DisconnectSocket(outputSocket, false);
     }
     EditorUtility.SetDirty(node);
     CurrentGraph.SetDirty(saveAssets);
     GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_DISCONNECTED, node.Id);
 }
Exemple #13
0
        private void CreateNodeInTheOpenedGraph(Type type, Vector2 worldPosition, bool recordUndo, bool saveAssets = false)
        {
            Node node = GraphUtils.CreateNode(CurrentGraph, type, worldPosition);

            if (recordUndo)
            {
                RecordUndo("Create " + type.Name);                                                     //record undo for the creation of this node
            }
            CurrentGraph.Nodes.Add(node);                                                              //add the new node reference to the graph's nodes list
            if (!EditorUtility.IsPersistent(node))
            {
                AssetDatabase.AddObjectToAsset(node, CurrentGraph);                                    //if the node does not have an asset file -> crete it and nest it under the graph asset file
            }
            switch (node.NodeType)
            {
            case NodeType.General:
            case NodeType.SubGraph:
                //AUTO CONNECT the new node TO either the START or ENTER node - if the start or enter nodes are not connected
                Node startOrEnterNode = CurrentGraph.GetStartOrEnterNode();
                if (startOrEnterNode != null &&                                                  //if we have a start or enter node
                    !startOrEnterNode.OutputSockets[0].IsConnected &&                            //that is NOT connected
                    node.InputSockets != null &&                                                 //and its inputSockets list is NOT null (sanity check)
                    node.InputSockets.Count > 0)                                                 //and it has at least one input socket (again... sanity check)
                {
                    ConnectSockets(startOrEnterNode.OutputSockets[0], node.InputSockets[0]);     //connect the new created node with the Start or Enter node
                }
                break;
            }

            EditorUtility.SetDirty(node);                                             //mark the new node as dirty
            CurrentGraph.SetDirty(saveAssets);                                        //set the graph dirty
            if (recordUndo)
            {
                GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_CREATED);             //notify the system the a node has been created
            }
            SelectNodes(new List <Node> {
                node
            }, false, false);                                                           //select the newly created node
            WindowSettings.SetDirty(false);
        }
        /// <summary> Triggered when an UndoRedo action has been performed </summary>
        private void UndoRedoPerformed()
        {
//            if (CurrentGraph != null)
//            {
//                //if any node that has been soft deleted has been bought back via the undo / redo operation -> we need to remove it from the soft delete database
//                foreach (Node node in CurrentGraph.Nodes) //look through the node references list that the graph has
//                    if (EditorSettings.DeletedNodes.Contains(node)) //check if any node id, that is currently referenced, if it's also in the soft delete list (the one recovered from editor prefs)
//                    {
//                        EditorSettings.DeletedNodes.Remove(node); //if a nose was found -> remove it from the soft delete nodes list in order to prevent the node deletion when entering play mode, or closing the graph
//                        EditorSettings.SetDirty(false);
//                    }
//
//                CurrentGraph.SetGraphDirty(); //mark graph dirty
//            }

            ValidateDatabases();                                    //makes sure there are no invalid entries in the databases
            ConstructGraphGUI();                                    //recalculates the GUI
            m_initialDragNodePositions.Clear();                     //clears any currently dragged nodes
            UpdateNodesSelectedState(WindowSettings.SelectedNodes); //updates all the nodes selected state
            GraphEvent.Send(GraphEvent.EventType.EVENT_UNDO_REDO_PERFORMED);
            Repaint();                                              //does a quick repaint
        }
Exemple #15
0
        private void DisconnectVirtualPoint(VirtualPoint virtualPoint, bool recordUndo, bool saveAssets = false)
        {
            if (!virtualPoint.Socket.IsConnected)
            {
                return;
            }
            if (!virtualPoint.IsConnected)
            {
                return;
            }

            if (recordUndo)
            {
                RecordUndo(GraphAction.Disconnect.ToString());
            }

            var connections = new List <VirtualConnection>();

            foreach (VirtualConnection connection in ConnectionsDatabase.Values)
            {
                if (connection.InputVirtualPoint == virtualPoint || connection.OutputVirtualPoint == virtualPoint)
                {
                    connections.Add(connection);
                }
            }

            foreach (VirtualConnection vc in connections)
            {
                vc.OutputSocket.RemoveConnection(vc.ConnectionId);
                vc.InputSocket.RemoveConnection(vc.ConnectionId);
                EditorUtility.SetDirty(vc.OutputNode);
                EditorUtility.SetDirty(vc.InputNode);
                ConnectionsDatabase.Remove(vc.ConnectionId);
            }

            CurrentGraph.SetDirty(saveAssets);
            GraphEvent.Send(GraphEvent.EventType.EVENT_CONNECTION_DELETED);
        }
        /// <summary> Connect two sockets </summary>
        /// <param name="graph"> Parent graph </param>
        /// <param name="outputSocket"> Output Socket</param>
        /// <param name="inputSocket"> Input Socket </param>
        /// <param name="saveAssets"> Perform AssetDatabase.Save </param>
        public static void ConnectSockets(Graph graph, Socket outputSocket, Socket inputSocket, bool saveAssets = false)
        {
//            if (outputSocket.OverrideConnection) DisconnectSocket(outputSocket, false);
//            if (inputSocket.OverrideConnection) DisconnectSocket(inputSocket, false);
            if (outputSocket.OverrideConnection)
            {
                outputSocket.Disconnect();
                GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_DISCONNECTED, outputSocket.NodeId);
            }

            if (inputSocket.OverrideConnection)
            {
                inputSocket.Disconnect();
                GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_DISCONNECTED, inputSocket.NodeId);
            }

            var connection = new Connection(outputSocket, inputSocket);

            outputSocket.Connections.Add(connection);
            inputSocket.Connections.Add(connection);
            graph.SetDirty(saveAssets);
            GraphEvent.Send(GraphEvent.EventType.EVENT_CONNECTION_ESTABLISHED);
        }
Exemple #17
0
        protected override void OnNodeGUI()
        {
            DrawNodeBody();

            if (TargetNode.SwitchBackMode)
            {
                if (TargetNode.InputSockets == null ||
                    TargetNode.InputSockets.Count == 0)
                {
                    TargetNode.AddInputSocket(ConnectionMode.Multiple, typeof(PassthroughConnection), false, false);
                    GraphEvent.ConstructGraph();
                    GraphEvent.RecalculateAllPoints();
                }

                DrawSocketsList(Node.InputSockets);
            }
            else
            {
                if (TargetNode.InputSockets != null &&
                    TargetNode.InputSockets.Count > 0)
                {
                    if (TargetNode.FirstInputSocket != null &&
                        TargetNode.FirstInputSocket.IsConnected)
                    {
                        GraphEvent.DisconnectSocket(TargetNode.FirstInputSocket);
                    }

                    TargetNode.InputSockets.Clear();
                    GraphEvent.ConstructGraph();
                    GraphEvent.RecalculateAllPoints();
                }
            }

            DrawSocketsList(Node.OutputSockets);
            DrawActionDescription();
        }
 protected override void OnGraphEvent(GraphEvent graphEvent)
 {
     UpdateNodeData();
 }
 private void UpdateSocketValue(Socket socket, UIConnection value)
 {
     UIConnection.SetValue(socket, value);
     GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_UPDATED, TargetNode.Id);
 }
Exemple #20
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="engine"></param>
        /// <returns></returns>
        Workflow Load(CWFEngine engine)
        {
            using (var xmlReader = XmlReader.Create(_workflowMemento.WorkflowFilePath))
            {
                var xmlNameTable = xmlReader.NameTable;
                if (xmlNameTable != null)
                {
                    _workflowMemento.XmlNamespaceManager = new XmlNamespaceManager(xmlNameTable);
                    _workflowMemento.XmlNamespaceManager.AddNamespace("wf", "urn:cwf-schema");
                }
                else
                {
                    throw new Exception("xmlNameTable of " + _workflowMemento.WorkflowFilePath + " is null");
                }

                // Loading settings
                var       xdoc = XDocument.Load(_workflowMemento.WorkflowFilePath);
                XDocument XDoc = xdoc;
                XNamespaceWf = "urn:cwf-schema";

                _workflowMemento.Id          = int.Parse(GetWorkflowAttribute(xdoc, "id"));
                _workflowMemento.Name        = GetWorkflowAttribute(xdoc, "name");
                _workflowMemento.Description = GetWorkflowAttribute(xdoc, "description");

                _workflowMemento.LaunchType = (LaunchType)Enum.Parse(typeof(LaunchType), GetWorkflowSetting(xdoc, "launchType"), true);
                if (_workflowMemento.LaunchType == LaunchType.Periodic)
                {
                    _workflowMemento.Period = TimeSpan.Parse(GetWorkflowSetting(xdoc, "period"));
                }
                _workflowMemento.IsEnabled = bool.Parse(GetWorkflowSetting(xdoc, "enabled"));

                //create state token
                try
                {
                    var typename = GetWorkflowSetting(xdoc, "statemachinetype");
                    _workflowMemento.StateToken = CreateStateToken(typename);
                    InitializeTransitionDefinitionBuilder(xdoc);

                    Logger.Info($"Instantiated State token");
                }
                catch (FileNotFoundException fnfe)
                {
                    Logger.Error($"A required library was not found: {fnfe.FileName}");
                }
                catch (Exception e)
                {
                    Logger.Error($"Exception on creating state machine token: {e.ToString()}");
                    return(null);
                }

                if (xdoc.Root != null)
                {
                    var xExecutionGraph = xdoc.Root.Element(XNamespaceWf + Sym.ACTIVITY_SETUP);
                    IsExecutionGraphEmpty = xExecutionGraph == null || !xExecutionGraph.Elements().Any();
                }
                var wf = new Workflow(engine, _workflowMemento);
                // Loading tasks
                var activities = new List <Activity>();
                foreach (var xTaskElement in xdoc.XPathSelectElements("/wf:Workflow/wf:Activities/wf:Activity", _workflowMemento.XmlNamespaceManager))
                {
                    var xAttribute = xTaskElement.Attribute("name");
                    if (xAttribute != null)
                    {
                        var name = xAttribute.Value;

                        ActivityMemento activityMemento = ParseActivity(xTaskElement, wf);
                        Activity        activity        = LoadActivityInstance(name, activityMemento);

                        activities.Add(activity);
                    }
                    else
                    {
                        throw new Exception("Name attribute of the task " + xTaskElement + " does not exist.");
                    }
                }

                wf.Activities = activities.ToArray();

                //read all transition definitions
                var transitionList = new List <Transition>();
                foreach (var xTaskElement in xdoc.XPathSelectElements("/wf:Workflow/wf:Transitions/wf:Transition", _workflowMemento.XmlNamespaceManager))
                {
                    var xAttributeId        = xTaskElement.Attribute("id");
                    var xAttributeFrom      = xTaskElement.Attribute("from");
                    var xAttributeTo        = xTaskElement.Attribute("to");
                    var xAttributeCondition = xTaskElement.Attribute("condition");

                    int    id          = int.Parse(xAttributeId.Value);
                    int    from        = int.Parse(xAttributeFrom.Value);
                    int    to          = int.Parse(xAttributeTo.Value);
                    string condition   = xAttributeCondition?.Value;
                    var    genericType = typeof(Transition <>).MakeGenericType(_stateType);
                    var    transition  = (Transition)Activator.CreateInstance(genericType, new object[] { id, from, to, condition });
                    OnTransitionDefinitionInXml(transition);
                    transitionList.Add(transition);
                    Logger.Info(transition.ToString());
                }
                wf.Transitions = transitionList.ToArray();
                var d = CompileAndGetMethodInfos();
                LinkTransitionsToCompiledConditions(wf.Transitions, d);

                // Loading execution graph
                var xExectionGraph = xdoc.XPathSelectElement("/wf:Workflow/wf:ActivitySetup", _workflowMemento.XmlNamespaceManager);
                if (xExectionGraph != null)
                {
                    var taskNodes = GetTaskNodes(xExectionGraph);

                    // Check startup node, parallel tasks and infinite loops
                    if (taskNodes.Any())
                    {
                        if (CheckStartupNode(taskNodes) == false)
                        {
                            Logger.Trace("Startup node with parentId=-1 not found in ExecutionGraph execution graph.");
                            throw new Exception();
                        }
                    }

                    if (CheckParallelTasks(taskNodes))
                    {
                        Logger.Trace("Parallel tasks execution detected in ExecutionGraph execution graph.");
                    }

                    CheckInfiniteLoop(taskNodes, "Infinite loop detected in ExecutionGraph execution graph.");

                    // OnSuccess
                    GraphEvent onSuccess  = null;
                    var        xOnSuccess = xExectionGraph.XPathSelectElement("wf:OnSuccess", _workflowMemento.XmlNamespaceManager);
                    if (xOnSuccess != null)
                    {
                        var onSuccessNodes = GetTaskNodes(xOnSuccess);

                        if (CheckStartupNode(onSuccessNodes) == false)
                        {
                            Logger.Trace("Startup node with parentId=-1 not found in OnSuccess execution graph.");
                            throw new Exception();
                        }

                        if (CheckParallelTasks(onSuccessNodes))
                        {
                            Logger.Trace("Parallel tasks execution detected in OnSuccess execution graph.");
                        }

                        CheckInfiniteLoop(onSuccessNodes, "Infinite loop detected in OnSuccess execution graph.");
                        onSuccess = new GraphEvent(onSuccessNodes);
                    }

                    // OnWarning
                    GraphEvent onWarning  = null;
                    var        xOnWarning = xExectionGraph.XPathSelectElement("wf:OnWarning", _workflowMemento.XmlNamespaceManager);
                    if (xOnWarning != null)
                    {
                        var onWarningNodes = GetTaskNodes(xOnWarning);

                        if (CheckStartupNode(onWarningNodes) == false)
                        {
                            Logger.Trace("Startup node with parentId=-1 not found in OnWarning execution graph.");
                            throw new Exception();
                        }

                        if (CheckParallelTasks(onWarningNodes))
                        {
                            Logger.Trace("Parallel tasks execution detected in OnSuccess execution graph.");
                        }

                        CheckInfiniteLoop(onWarningNodes, "Infinite loop detected in OnWarning execution graph.");
                        onWarning = new GraphEvent(onWarningNodes);
                    }

                    // OnError
                    GraphEvent onError  = null;
                    var        xOnError = xExectionGraph.XPathSelectElement("wf:OnError", _workflowMemento.XmlNamespaceManager);
                    if (xOnError != null)
                    {
                        var onErrorNodes = GetTaskNodes(xOnError);

                        if (CheckStartupNode(onErrorNodes) == false)
                        {
                            Logger.Trace("Startup node with parentId=-1 not found in OnError execution graph.");
                            return(null);
                        }

                        if (CheckParallelTasks(onErrorNodes))
                        {
                            Logger.Trace("Parallel tasks execution detected in OnError execution graph.");
                        }

                        CheckInfiniteLoop(onErrorNodes, "Infinite loop detected in OnError execution graph.");
                        onError = new GraphEvent(onErrorNodes);
                    }

                    wf.ActivitySetup = new Graph(taskNodes, onSuccess, onWarning, onError);
                }
                return(wf);
            }
        }
 protected virtual void OnGraphEvent(GraphEvent graphEvent)
 {
     UpdateNodeData();
 }
 /// <summary> Called when object becomes enabled and active </summary>
 protected virtual void OnEnable()
 {
     LoadSerializedProperty();
     InitAnimBool();
     GraphEvent.AddReceiver(OnGraphEvent);
 }
 /// <summary> Called when object becomes disabled and inactive </summary>
 protected virtual void OnDisable()
 {
     GraphEvent.RemoveReceiver(OnGraphEvent);
 }
        private void HandleMouseLeftClicks()
        {
            Event current = Event.current;

            if (!current.isMouse)
            {
                return;
            }
            if (current.button != 0)
            {
                return;
            }

            if (current.type == EventType.MouseDown)
            {
                //left mouse button is down and the space key is down as well -> enter panning mode
                if (m_spaceKeyDown)
                {
                    m_mode = GraphMode.Pan;
                    current.Use();
                    return;
                }

                if (m_altKeyPressed) //delete mode
                {
                    BaseNodeGUI nodeGUI = GetNodeGUIOfDeleteButtonAtWorldPosition(CurrentMousePosition);
                    if (nodeGUI != null)
                    {
                        SoftDeleteNode(nodeGUI.Node, true, false);
                        current.Use();
                        return;
                    }
                }

                //pressed left mouse button over a socket point -> but we have at least two nodes selected -> do not allow starting any connections
                if (WindowSettings.SelectedNodes.Count < 2)
                {
                    if (m_currentHoveredVirtualPoint != null)
                    {
//                        if (current.alt)
                        if (m_altKeyPressed)
                        {
                            //pressed left mouse button over a socket virtual point while holding down Alt -> Disconnect Virtual Point
                            DisconnectVirtualPoint(m_currentHoveredVirtualPoint, true);
                        }
                        else
                        {
                            //pressed left mouse button over a socket connection point -> it's a possible start of a connection
                            m_activeSocket = m_currentHoveredVirtualPoint.Socket; //set the socket as the active socket
                            m_mode         = GraphMode.Connect;                   //set the graph in connection mode
                        }

                        current.Use();
                        return;
                    }

                    Socket socket = GetSocketAtWorldPositionFromHoverRect(CurrentMousePosition);
                    if (socket != null)
                    {
//                        if (current.alt)
                        if (m_altKeyPressed)
                        {
                            //pressed left mouse button over a socket while holding down Alt -> Remove Socket
                            RemoveSocket(socket, true);
                        }
                        else
                        {
                            //pressed left mouse button over a socket -> it's a possible start of a connection
                            m_activeSocket = socket;            //set the socket as the active socket
                            m_mode         = GraphMode.Connect; //set the graph in connection mode
                        }

                        current.Use();
                        return;
                    }
                }

                //pressed left mouse button over a node -> check to see if it's inside the header (if no node is currently selected) or it just over a node (if at least 2 nodes are selected)
                if (m_currentHoveredNode != null)
                {
                    if (GetNodeGridRect(m_currentHoveredNode).Contains(CurrentMousePosition) || //if mouse is inside node -> allow dragging
                        WindowSettings.SelectedNodes.Count > 1)                                 //OR if there are at least 2 nodes selected -> allow dragging from any point on the node
                    {
                        //pressed left mouse button over a node -> select/deselect it
                        if (current.shift || current.control || current.command)               //if using modifiers -> create custom selection
                        {
                            SelectNodes(new List <Node> {
                                m_currentHoveredNode
                            }, true, true);                                                    //add/remove the node to/from selection
                        }
                        else if (!WindowSettings.SelectedNodes.Contains(m_currentHoveredNode)) //we may have a selection and we do not want to override it in order to be able to start dragging
                        {
                            SelectNodes(new List <Node> {
                                m_currentHoveredNode
                            }, false, true);                                                   //select this node only
                        }
                        //allow dragging ONLY IF the mouse is over a selected node
                        //in the previous lines we only checked if it's over a node, but not if the node we are hovering over is currently selected
                        if (WindowSettings.SelectedNodes.Contains(m_currentHoveredNode))
                        {
                            if (Selection.activeObject != m_currentHoveredNode)
                            {
                                Selection.activeObject = m_currentHoveredNode; //select the node
                            }
                            //pressed left mouse button over a node -> it's a possible start drag
                            PrepareToDragSelectedNodes(CurrentMousePosition);
                            m_mode = GraphMode.Drag;
                        }
                    }

                    current.Use();
                    return;
                }

                //pressed left mouse button over nothing -> it's a possible start selection
                PrepareToCreateSelectionBox(CurrentMousePosition);
                current.Use();
                return;
            }

            if (current.type == EventType.MouseDrag)
            {
                //left mouse click is dragging and the graph is in panning mode
                if (m_mode == GraphMode.Pan)
                {
                    //check that the space key is held down -> otherwise exit pan mode
                    if (!m_spaceKeyDown)
                    {
                        m_mode = GraphMode.None;
                    }
                    else
                    {
                        DoPanning(current);
                    }

                    current.Use();
                    return;
                }

                //mouse left click is dragging a connection
                if (m_mode == GraphMode.Connect)
                {
                    if (m_currentHoveredSocket != null) //mouse is over a socket -> color the line to green if connection is possible or red otherwise
                    {
                        m_createConnectionLineColor = m_activeSocket.CanConnect(m_currentHoveredSocket) ? Color.green : Color.red;
                    }
                    else if (m_currentHoveredVirtualPoint != null) //mouse is over a socket connection point -> color the line to green if connection is possible or red otherwise
                    {
                        m_createConnectionLineColor = m_activeSocket.CanConnect(m_currentHoveredVirtualPoint.Socket) ? Color.green : Color.red;
                    }
                    else //mouse is not over anything connectable -> show the connection point color to look for
                    {
                        m_createConnectionLineColor =
                            m_activeSocket.IsInput
                                ? DGUI.Colors.GetDColor(DGUI.Colors.NodyOutputColorName).Normal //source socket is input -> looking for an output socket -> color the line to the output color
                                : DGUI.Colors.GetDColor(DGUI.Colors.NodyInputColorName).Normal; //source socket is output -> looking for an input socket -> color the line to the input color
                    }
                    current.Use();
                    return;
                }

                //mouse left click is dragging one or more nodes
                if (m_mode == GraphMode.Drag) // && GUIUtility.hotControl == dragNodesControlId)
                {
                    m_isDraggingAnimBool.target = false;
                    RecordUndo("Move Nodes");
                    UpdateSelectedNodesWhileDragging();
                    current.Use();
                    return;
                }

                //mouse left click is dragging and creating a selection box <- we know this because the the mouse is not over a point nor a node
                if (m_startSelectPoint != null)
                {
                    m_mode = GraphMode.Select;
                }
                if (m_mode == GraphMode.Select)
                {
                    UpdateSelectionBox(CurrentMousePosition);
                    UpdateSelectBoxSelectedNodesWhileSelecting(current);
                    UpdateNodesSelectedState(m_selectedNodesWhileSelecting);
                    current.Use();
                    return;
                }
            }

            if (current.type == EventType.MouseUp)
            {
                if (RegisteredDoubleClick)
                {
                    if (m_previousHoveredNode != null)
                    {
                        NodesGUIsDatabase[m_previousHoveredNode.Id].OnDoubleClick(this);
                    }
                }

                //lifted left mouse button and was panning (space key was/is down) -> reset graph to idle
                if (m_mode == GraphMode.Pan)
                {
                    m_mode = GraphMode.None;
                    current.Use();
                    return;
                }

                //lifted left mouse button and was dragging -> reset graph to idle
                if (m_mode == GraphMode.Drag)
                {
                    m_initialDragNodePositions.Clear();
                    m_isDraggingAnimBool.target = true;
                    m_mode = GraphMode.None;
                    current.Use();
                    return;
                }

                //lifted left mouse button and was selecting via selection box -> end selections and reset graph to idle mode
                if (m_mode == GraphMode.Select)
                {
                    EndDragSelectedNodes();
                    m_mode = GraphMode.None;
                    current.Use();
                    return;
                }


                //check if this happened over another socket or connection point
                if (m_currentHoveredSocket != null)
                {
                    //lifted left mouse button over a socket
                    if (m_activeSocket != null &&                                   //if there is an active socket
                        m_activeSocket != m_currentHoveredSocket &&                 //and it's not this one
                        m_activeSocket.CanConnect(m_currentHoveredSocket))          //and the two sockets can get connected
                    {
                        ConnectSockets(m_activeSocket, m_currentHoveredSocket);     //connect the two sockets
                    }
                    else                                                            //this was a failed connection attempt
                    {
                        GraphEvent.Send(GraphEvent.EventType.EVENT_CONNECTING_END); //send a graph event
                    }
                    m_activeSocket = null;                                          //clear the active socket
                    m_mode         = GraphMode.None;                                //set the graph in idle mode
                    current.Use();
                    return;
                }

                if (m_currentHoveredVirtualPoint != null)
                {
                    //lifted left mouse button over a socket connection point
                    if (m_activeSocket != null &&                                            //if there is an active socket
                        m_activeSocket != m_currentHoveredVirtualPoint.Socket &&             //and it's not this one
                        m_activeSocket.CanConnect(m_currentHoveredVirtualPoint.Socket))      //and the two sockets can get connected
                    {
                        ConnectSockets(m_activeSocket, m_currentHoveredVirtualPoint.Socket); //connect the two sockets
                    }
                    else                                                                     //this was a failed connection attempt
                    {
                        GraphEvent.Send(GraphEvent.EventType.EVENT_CONNECTING_END);          //send a graph event
                    }
                    m_activeSocket = null;                                                   //clear the active socket
                    m_mode         = GraphMode.None;                                         //set the graph in idle mode
                    current.Use();
                    return;
                }

                //it a connecting process was under way -> clear it
                //lifted left mouse button, but no virtual point was under the mouse position
                if (m_mode == GraphMode.Connect)
                {
                    m_activeSocket = null;           //clear the active socket
                    m_mode         = GraphMode.None; //set the graph in idle mode
                }

                Node node = GetNodeAtWorldPosition(CurrentMousePosition);
                if (node != null)
                {
                    m_mode = GraphMode.None; //set the graph in idle mode
                    current.Use();
                    return;
                }

                //lifted mouse left button over nothing -> deselect all and select the graph itself
                ExecuteGraphAction(GraphAction.DeselectAll); //deselect all nodes and select the graph itself
                m_mode = GraphMode.None;                     //set the graph in idle mode
                current.Use();
                return;
            }

            //check if the developer released the left mouse button outside of the graph window
            if (current.rawType == EventType.MouseUp || current.rawType == EventType.MouseLeaveWindow)
            {
                switch (m_mode)
                {
                case GraphMode.Select:
                    EndDragSelectedNodes();
                    m_mode = GraphMode.None;
                    current.Use();
                    break;
                }
            }
        }
        private void HandleOnGraphEvent(GraphEvent graphEvent)
        {
//            DDebug.Log("GraphEvent: " + graphEvent.eventType);

            switch (graphEvent.eventType)
            {
            case GraphEvent.EventType.EVENT_NONE:             break;

            case GraphEvent.EventType.EVENT_CONNECTING_BEGIN: break;

            case GraphEvent.EventType.EVENT_CONNECTING_END:
                ConstructGraphGUI();
                break;

            case GraphEvent.EventType.EVENT_CONNECTION_ESTABLISHED:
                ConstructGraphGUI();
                break;

            case GraphEvent.EventType.EVENT_NODE_CREATED:
                ConstructGraphGUI();
                RecalculateAllPointRects();
                break;

            case GraphEvent.EventType.EVENT_NODE_DELETED:
                ConstructGraphGUI();
                break;

            case GraphEvent.EventType.EVENT_NODE_UPDATED:
                ConstructGraphGUI();
                RecalculateAllPointRects();
                break;

            case GraphEvent.EventType.EVENT_NODE_CLICKED: break;

            case GraphEvent.EventType.EVENT_SOCKET_CREATED:
                ConstructGraphGUI();
                RecalculateAllPointRects();
                break;

            case GraphEvent.EventType.EVENT_SOCKET_ADDED:   break;

            case GraphEvent.EventType.EVENT_SOCKET_REMOVED: break;

            case GraphEvent.EventType.EVENT_SOCKET_CLEARED_CONNECTIONS:
                ConstructGraphGUI();
                break;

            case GraphEvent.EventType.EVENT_CONNECTION_CREATED: break;

            case GraphEvent.EventType.EVENT_CONNECTION_TAPPED:  break;

            case GraphEvent.EventType.EVENT_CONNECTION_DELETED:
                ConstructGraphGUI();
                break;

            case GraphEvent.EventType.EVENT_RECORD_UNDO:  break;

            case GraphEvent.EventType.EVENT_SAVED_ASSETS: break;

            case GraphEvent.EventType.EVENT_NODE_DISCONNECTED:
                ConstructGraphGUI();
                break;

            case GraphEvent.EventType.EVENT_GRAPH_OPENED:
                ConstructGraphGUI();
                RecalculateAllPointRects();
                break;

            case GraphEvent.EventType.EVENT_UNDO_REDO_PERFORMED:
                RecalculateAllPointRects();
                break;

            default: throw new ArgumentOutOfRangeException();
            }

            switch (graphEvent.commandType)
            {
            case GraphEvent.CommandType.NONE: break;

            case GraphEvent.CommandType.CONSTRUCT_GRAPH:
                ConstructGraphGUI();
                break;

            case GraphEvent.CommandType.RECALCULATE_ALL_POINTS:
                RecalculateAllPointRects();
                break;

            case GraphEvent.CommandType.DISCONNECT_SOCKET:
                DisconnectSocket(graphEvent.sourceSocket, true);
                break;
            }

            Repaint();
        }
        /// <summary> Returns TRUE if it creates a StartNode in the given target graph. Note that if the graph is a sub-graph or if it already has a StartNode, it will return FALSE </summary>
        /// <param name="graph"> Target graph </param>
        public static void CreateStartNode(Graph graph)
        {
            //Check the graph for system nodes
            Node startNode = graph.GetStartNode();
            Node enterNode = graph.GetEnterNode();
            Node exitNode  = graph.GetExitNode();

            bool startNodeWasCreated = false;

            if (startNode == null)
            {
                startNode = CreateNode(graph, typeof(StartNode), Vector2.zero);                               //create start node
                graph.Nodes.Add(startNode);                                                                   //add start node to Nodes list
                if (!EditorUtility.IsPersistent(startNode))
                {
                    AssetDatabase.AddObjectToAsset(startNode, graph);                                         //create the asset file for the node and attach it to the graph asset file
                }
                startNodeWasCreated = true;
            }

            if (enterNode != null) //this graph has an enter node -> it needs to be deleted
            {
                //because start node was created and enter node is not null -> set start node position as the enter node position
                if (startNodeWasCreated)
                {
                    startNode.SetPosition(enterNode.GetPosition());
                }

                if (enterNode.IsConnected()) //disconnect enter node
                {
                    string targetSocketId = enterNode.OutputSockets[0].Connections[0].InputSocketId;
                    Node   targetNode     = graph.GetNodeById(enterNode.OutputSockets[0].Connections[0].InputNodeId);
                    if (targetNode != null) //make sure a node connected to the EnterNode is not null (sanity check)
                    {
                        targetNode.GetSocketFromId(targetSocketId).DisconnectFromNode(enterNode.Id);
                        if (startNodeWasCreated) //because start node was created -> connect it to the same node enter node was connected
                        {
                            ConnectSockets(graph, startNode.OutputSockets[0], targetNode.GetSocketFromId(targetSocketId));
                        }
                    }
                }

                if (graph.Nodes.Contains(enterNode))
                {
                    graph.Nodes.Remove(enterNode);                                  //remove enter node from Nodes list
                }
                Object.DestroyImmediate(enterNode, true);                           //destroy enter node asset
            }


            if (exitNode != null)           //this graph has an exit node -> it needs to be deleted
            {
                if (exitNode.IsConnected()) //disconnect exit node
                {
                    for (int i = exitNode.InputSockets[0].Connections.Count - 1; i >= 0; i--)
                    {
                        Connection connection    = exitNode.InputSockets[0].Connections[i];
                        Node       connectedNode = graph.GetNodeById(connection.OutputNodeId);
                        exitNode.InputSockets[0].DisconnectFromNode(connection.OutputNodeId);
                        if (connectedNode != null)
                        {
                            connectedNode.GetSocketFromId(connection.OutputSocketId).DisconnectFromNode(exitNode.Id);
                        }
                    }
                }

                if (graph.Nodes.Contains(exitNode))
                {
                    graph.Nodes.Remove(exitNode);                                 //remove exit node from Nodes list
                }
                Object.DestroyImmediate(exitNode, true);                          //destroy exit node asset
            }

            graph.IsSubGraph = false;                                 //update graph type
            graph.SetDirty(false);                                    //set the graph as dirty
            GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_CREATED); //StartNode has been created
        }
        /// <summary> Returns TRUE if it creates an Enter and/or an Exit node in the given target graph. Note that if the graph is a graph or if it already has an Enter and an Exit nodes, it will return FALSE </summary>
        /// <param name="graph"> Target Graph </param>
        public static void CreateEnterAndExitNodes(Graph graph)
        {
            const float spaceBetweenNodes = 24f;

            //Check the graph for system nodes
            Node startNode = graph.GetStartNode();
            Node enterNode = graph.GetEnterNode();
            Node exitNode  = graph.GetExitNode();

            bool enterNodeWasCreated = false;

            if (enterNode == null)
            {
                enterNode = CreateNode(graph, typeof(EnterNode), Vector2.zero);                               //create enter node
                graph.Nodes.Add(enterNode);                                                                   //add start node to Nodes list
                if (!EditorUtility.IsPersistent(enterNode))
                {
                    AssetDatabase.AddObjectToAsset(enterNode, graph);                                         //create the asset file for the node and attach it to the graph asset file
                }
                enterNodeWasCreated = true;
            }

            if (startNode != null)
            {
                //because enter node was created and start node is not null -> set enter node position as the start node position
                if (enterNodeWasCreated)
                {
                    enterNode.SetPosition(startNode.GetPosition());
                }

                if (startNode.IsConnected()) //disconnect start node
                {
                    string targetSocketId = startNode.OutputSockets[0].Connections[0].InputSocketId;
                    Node   targetNode     = graph.GetNodeById(startNode.OutputSockets[0].Connections[0].InputNodeId);
                    if (targetNode != null) //make sure a node connected to the StartNode is not null (sanity check)
                    {
                        targetNode.GetSocketFromId(targetSocketId).DisconnectFromNode(startNode.Id);
                        ConnectSockets(graph, enterNode.OutputSockets[0], targetNode.GetSocketFromId(targetSocketId));
                    }
                }

                if (graph.Nodes.Contains(startNode))
                {
                    graph.Nodes.Remove(startNode);                                  //remove start node from Nodes list
                }
                Object.DestroyImmediate(startNode, true);                           //destroy enter node asset
            }

            if (exitNode == null)
            {
                exitNode = CreateNode(graph, typeof(ExitNode), new Vector2(enterNode.GetX() + NodySettings.Instance.ExitNodeWidth * 2 + spaceBetweenNodes,
                                                                           enterNode.GetY() + NodySettings.Instance.NodeHeaderHeight / 2));
                graph.Nodes.Add(exitNode);                                                                  //add exit node to Nodes kist
                if (!EditorUtility.IsPersistent(exitNode))
                {
                    AssetDatabase.AddObjectToAsset(exitNode, graph);                                        //create the asset file for the node and attach it to the graph asset file
                }
            }

            graph.IsSubGraph = true;                                  //update graph type
            graph.SetDirty(false);                                    //set the graph as dirty
            GraphEvent.Send(GraphEvent.EventType.EVENT_NODE_CREATED); //EnterNode and/or ExitNode has/have been created
        }
 private async Task ItemSelectedAsync(GraphEvent graphEvent)
 {
     await NavigationService.NavigateToAsync <ScheduleDetailViewModel>(graphEvent);
 }
Exemple #29
0
 public EffectGraphEventArgs(GraphEvent what)
 {
     What = what;
 }
Exemple #30
0
        private void DrawGraphTabs()
        {
            if (GraphTabs.Count == 0)
            {
                return;                                                          //if no tabs have been opened stop here -> do not draw anything
            }
            int   clickedTabIndex  = -1;                                         //index of the clicked tab
            float tabWidth         = NodySettings.Instance.GraphTabMaximumWidth; //get the tab max width
            float tabsCount        = GraphTabs.Count;                            //count the tabs
            bool  calculateTabWith = true;                                       //start dynamic tab width calculations

            while (calculateTabWith)
            {
                float totalSpaceWidth         = tabsCount * 2 * NodySettings.Instance.GraphTabElementSpacing;
                float totalDividersWidth      = (tabsCount - 1) * NodySettings.Instance.GraphTabDividerWidth;
                float totalTabsAvailableWidth = GraphTabsRect.width - totalSpaceWidth - totalDividersWidth;
                float calculatedTabWidth      = totalTabsAvailableWidth / tabsCount;

                if (calculatedTabWidth > NodySettings.Instance.GraphTabMaximumWidth)
                {
                    calculateTabWith = false;
                    tabWidth         = NodySettings.Instance.GraphTabMaximumWidth;
                }
                else if (calculatedTabWidth >= NodySettings.Instance.GraphTabMinimumWidth)
                {
                    calculateTabWith = false;
                    tabWidth         = calculatedTabWidth;
                }
                else
                {
                    tabsCount--;
                }
            }

            float x = GraphTabsRect.x;

            //Start drawing the tabs
            GUILayout.Space(DGUI.Properties.Space());
            GUILayout.BeginHorizontal();
            {
                GUILayout.Space(NodySettings.Instance.GraphTabElementSpacing);
                x += NodySettings.Instance.GraphTabElementSpacing;
                for (int index = 0; index < tabsCount; index++)
                {
                    if (index > 0)
                    {
                        float dividerHeight = NodySettings.Instance.GraphTabsAreaHeight - NodySettings.Instance.GraphTabElementSpacing * 3;
                        GUILayout.BeginVertical(GUILayout.Height(GraphTabsRect.height));
                        {
                            GUILayout.Space((GraphTabsRect.height - dividerHeight) / 2 - DGUI.Properties.Space());
                            Color color = GUI.color;
                            GUI.color = DGUI.Colors.TextColor(DGUI.Colors.DisabledTextColorName).WithAlpha(color.a * 0.4f);
                            GUILayout.Label(GUIContent.none, DGUI.Properties.White,
                                            GUILayout.Width(NodySettings.Instance.GraphTabDividerWidth),
                                            GUILayout.Height(dividerHeight));
                            GUI.color = color;
                        }
                        GUILayout.EndVertical();
                        GUILayout.Space(NodySettings.Instance.GraphTabElementSpacing);
                        x += NodySettings.Instance.GraphTabElementSpacing;
                        x += NodySettings.Instance.GraphTabDividerWidth;
                        x += NodySettings.Instance.GraphTabElementSpacing;
                    }

                    GraphTab graphTab   = GraphTabs[index];
                    var      buttonRect = new Rect(x, GraphTabsRect.y + NodySettings.Instance.GraphTabElementSpacing, tabWidth, GraphTabsRect.height - 2 * NodySettings.Instance.GraphTabElementSpacing);

                    GUI.color = InitialGUIColor;
                    if (index < tabsCount - 1)
                    {
                        GUI.color = GUI.color.WithAlpha(DGUI.Utility.IsProSkin ? 0.6f : 0.8f);
                    }
                    if (graphTab.DrawButton(buttonRect))
                    {
                        if (graphTab.IsRootTab && graphTab.Graph != null && CurrentGraph != graphTab.Graph)
                        {
                            OpenGraph(graphTab.Graph, true, false, false);
                        }
                        else if (!graphTab.IsRootTab && graphTab.SubGraphNode != null && graphTab.SubGraphNode.SubGraph != null && CurrentGraph != graphTab.SubGraphNode.SubGraph)
                        {
                            OpenGraph(graphTab.SubGraphNode.SubGraph, true, false, false);
                        }

                        CurrentZoom      = graphTab.Zoom;
                        CurrentPanOffset = graphTab.PanOffset;
                        SelectedNodes    = new List <Node>(graphTab.SelectedNodes);
                        clickedTabIndex  = index;

                        GraphEvent.Send(GraphEvent.EventType.EVENT_GRAPH_OPENED);

                        break;
                    }

                    GUILayout.Space(tabWidth);
                    x += tabWidth;
                }

                GUILayout.FlexibleSpace();
            }
            GUILayout.EndHorizontal();

            if (clickedTabIndex == -1)
            {
                return;
            }
            for (int i = GraphTabs.Count - 1; i >= 0; i--)
            {
                if (i > clickedTabIndex)
                {
                    GraphTabs.RemoveAt(i);
                }
            }
        }