Exemplo n.º 1
0
        protected void SelectNext()
        {
            Block     block     = target as Block;
            Flowchart flowchart = block.GetFlowchart();

            int lastSelectedIndex = -1;

            if (flowchart.selectedCommands.Count > 0)
            {
                for (int i = 0; i < flowchart.selectedBlock.commandList.Count; i++)
                {
                    Command commandInBlock = flowchart.selectedBlock.commandList[i];

                    foreach (Command selectedCommand in flowchart.selectedCommands)
                    {
                        if (commandInBlock == selectedCommand)
                        {
                            lastSelectedIndex = i;
                        }
                    }
                }
            }
            if (lastSelectedIndex < flowchart.selectedBlock.commandList.Count - 1)
            {
                flowchart.ClearSelectedCommands();
                flowchart.AddSelectedCommand(flowchart.selectedBlock.commandList[lastSelectedIndex + 1]);
            }

            Repaint();
        }
Exemplo n.º 2
0
        //MIKEHACK
        public void AddCommandHack(Block bl, Type type, int index)
        {
            if (bl == null)
            {
                return;
            }

            Flowchart flowchart = bl.GetFlowchart();

            flowchart.ClearSelectedCommands();

            Command newCommand = Undo.AddComponent(bl.gameObject, type) as Command;

            bl.GetFlowchart().AddSelectedCommand(newCommand);
            newCommand.parentBlock = bl;
            newCommand.itemId      = flowchart.NextItemId();

            // Let command know it has just been added to the block
            newCommand.OnCommandAdded(bl);

            Undo.RecordObject(bl, "Set command type");
            if (index < bl.commandList.Count - 1)
            {
                bl.commandList.Insert(index, newCommand);
            }
            else
            {
                bl.commandList.Add(newCommand);
            }

            // Because this is an async call, we need to force prefab instances to record changes
            PrefabUtility.RecordPrefabInstancePropertyModifications(bl);
        }
Exemplo n.º 3
0
        protected static void AddCommandCallback(object obj)
        {
            AddCommandOperation commandOperation = obj as AddCommandOperation;

            Block block = commandOperation.block;

            if (block == null)
            {
                return;
            }

            Flowchart flowchart = block.GetFlowchart();

            flowchart.ClearSelectedCommands();

            Command newCommand = Undo.AddComponent(block.gameObject, commandOperation.commandType) as Command;

            block.GetFlowchart().AddSelectedCommand(newCommand);
            newCommand.parentBlock = block;
            newCommand.itemId      = flowchart.NextItemId();

            // Let command know it has just been added to the block
            newCommand.OnCommandAdded(block);

            Undo.RecordObject(block, "Set command type");
            if (commandOperation.index < block.commandList.Count - 1)
            {
                block.commandList.Insert(commandOperation.index, newCommand);
            }
            else
            {
                block.commandList.Add(newCommand);
            }
        }
        protected virtual void DeleteBlock(Flowchart flowchart, Block block)
        {
            foreach (Command command in block.commandList)
            {
                Undo.DestroyObjectImmediate(command);
            }

            Undo.DestroyObjectImmediate(block);
            flowchart.ClearSelectedCommands();
        }
        public static Block CreateBlock(Flowchart flowchart, Vector2 position)
        {
            Block newBlock = flowchart.CreateBlock(position);

            Undo.RegisterCreatedObjectUndo(newBlock, "New Block");
            ShowBlockInspector(flowchart);
            flowchart.selectedBlock = newBlock;
            flowchart.ClearSelectedCommands();

            return(newBlock);
        }
 protected virtual void SelectBlock(Flowchart flowchart, Block block)
 {
     // Select the block and also select currently executing command
     ShowBlockInspector(flowchart);
     flowchart.selectedBlock = block;
     flowchart.ClearSelectedCommands();
     if (block.activeCommand != null)
     {
         flowchart.AddSelectedCommand(block.activeCommand);
     }
 }
Exemplo n.º 7
0
        protected void SelectNone()
        {
            Block     block     = target as Block;
            Flowchart flowchart = block.GetFlowchart();

            if (flowchart == null ||
                flowchart.selectedBlock == null)
            {
                return;
            }

            Undo.RecordObject(flowchart, "Select None");
            flowchart.ClearSelectedCommands();

            Repaint();
        }
Exemplo n.º 8
0
        protected void Delete()
        {
            Block     block     = target as Block;
            Flowchart flowchart = block.GetFlowchart();

            if (flowchart == null ||
                flowchart.selectedBlock == null)
            {
                return;
            }
            int lastSelectedIndex = 0;

            for (int i = flowchart.selectedBlock.commandList.Count - 1; i >= 0; --i)
            {
                Command command = flowchart.selectedBlock.commandList[i];
                foreach (Command selectedCommand in flowchart.selectedCommands)
                {
                    if (command == selectedCommand)
                    {
                        command.OnCommandRemoved(block);

                        // Order of destruction is important here for undo to work
                        Undo.DestroyObjectImmediate(command);

                        Undo.RecordObject(flowchart.selectedBlock, "Delete");
                        flowchart.selectedBlock.commandList.RemoveAt(i);

                        lastSelectedIndex = i;

                        break;
                    }
                }
            }

            Undo.RecordObject(flowchart, "Delete");
            flowchart.ClearSelectedCommands();

            if (lastSelectedIndex < flowchart.selectedBlock.commandList.Count)
            {
                Command nextCommand = flowchart.selectedBlock.commandList[lastSelectedIndex];
                block.GetFlowchart().AddSelectedCommand(nextCommand);
            }

            Repaint();
        }
Exemplo n.º 9
0
        protected void SelectAll()
        {
            Block     block     = target as Block;
            Flowchart flowchart = block.GetFlowchart();

            if (flowchart == null ||
                flowchart.selectedBlock == null)
            {
                return;
            }

            flowchart.ClearSelectedCommands();
            Undo.RecordObject(flowchart, "Select All");
            foreach (Command command in flowchart.selectedBlock.commandList)
            {
                flowchart.AddSelectedCommand(command);
            }

            Repaint();
        }
Exemplo n.º 10
0
        protected void SelectPrevious()
        {
            Block     block     = target as Block;
            Flowchart flowchart = block.GetFlowchart();

            int  firstSelectedIndex        = flowchart.selectedBlock.commandList.Count;
            bool firstSelectedCommandFound = false;

            if (flowchart.selectedCommands.Count > 0)
            {
                for (int i = 0; i < flowchart.selectedBlock.commandList.Count; i++)
                {
                    Command commandInBlock = flowchart.selectedBlock.commandList[i];

                    foreach (Command selectedCommand in flowchart.selectedCommands)
                    {
                        if (commandInBlock == selectedCommand)
                        {
                            if (!firstSelectedCommandFound)
                            {
                                firstSelectedIndex        = i;
                                firstSelectedCommandFound = true;
                                break;
                            }
                        }
                    }
                    if (firstSelectedCommandFound)
                    {
                        break;
                    }
                }
            }
            if (firstSelectedIndex > 0)
            {
                flowchart.ClearSelectedCommands();
                flowchart.AddSelectedCommand(flowchart.selectedBlock.commandList[firstSelectedIndex - 1]);
            }

            Repaint();
        }
        protected virtual void OnGUI()
        {
            Flowchart flowchart = GetFlowchart();

            if (flowchart == null)
            {
                GUILayout.Label("No Flowchart scene object selected");
                return;
            }

            // Delete any scheduled objects
            foreach (Block deleteBlock in deleteList)
            {
                bool isSelected = (flowchart.selectedBlock == deleteBlock);

                foreach (Command command in deleteBlock.commandList)
                {
                    Undo.DestroyObjectImmediate(command);
                }

                Undo.DestroyObjectImmediate(deleteBlock);
                flowchart.ClearSelectedCommands();

                if (isSelected)
                {
                    // Revert to showing properties for the Flowchart
                    Selection.activeGameObject = flowchart.gameObject;
                }
            }
            deleteList.Clear();

            DrawFlowchartView(flowchart);
            DrawOverlay(flowchart);

            if (forceRepaintCount > 0)
            {
                // Redraw on next frame to get crisp refresh rate
                Repaint();
            }
        }
Exemplo n.º 12
0
        protected static void AddCommandCallback(object obj)
        {
            AddCommandOperation commandOperation = obj as AddCommandOperation;

            Block block = commandOperation.block;

            if (block == null)
            {
                return;
            }

            Flowchart flowchart = block.GetFlowchart();

            flowchart.ClearSelectedCommands();

            Command newCommand = Undo.AddComponent(block.gameObject, commandOperation.commandType) as Command;

            block.GetFlowchart().AddSelectedCommand(newCommand);
            newCommand.parentBlock = block;
            newCommand.itemId      = flowchart.NextItemId();

            // Let command know it has just been added to the block
            newCommand.OnCommandAdded(block);

            Undo.RecordObject(block, "Set command type");
            if (commandOperation.index < block.commandList.Count - 1)
            {
                block.commandList.Insert(commandOperation.index, newCommand);
            }
            else
            {
                block.commandList.Add(newCommand);
            }

            // Because this is an async call, we need to force prefab instances to record changes
            PrefabUtility.RecordPrefabInstancePropertyModifications(block);
        }
Exemplo n.º 13
0
        Command AddNewCommand()
        {
            Flowchart flowchart = FlowchartWindow.GetFlowchart();

            if (flowchart == null)
            {
                return(null);
            }

            Block block = flowchart.selectedBlock;

            if (block == null)
            {
                return(null);
            }

            Command newCommand = Undo.AddComponent <Comment>(block.gameObject) as Command;

            newCommand.itemId = flowchart.NextItemId();
            flowchart.ClearSelectedCommands();
            flowchart.AddSelectedCommand(newCommand);

            return(newCommand);
        }
Exemplo n.º 14
0
        public void DrawItem(Rect position, int index)
        {
            Command command = this[index].objectReferenceValue as Command;

            if (command == null)
            {
                return;
            }

            CommandInfoAttribute commandInfoAttr = CommandEditor.GetCommandInfo(command.GetType());

            if (commandInfoAttr == null)
            {
                return;
            }

            Flowchart flowchart = command.GetFlowchart();

            if (flowchart == null)
            {
                return;
            }

            bool isComment = command.GetType() == typeof(Comment);
            bool isLabel   = (command.GetType() == typeof(Label));

            bool   error   = false;
            string summary = command.GetSummary();

            if (summary == null)
            {
                summary = "";
            }
            else
            {
                summary = summary.Replace("\n", "").Replace("\r", "");
            }
            if (summary.StartsWith("Error:"))
            {
                error = true;
            }

            if (isComment || isLabel)
            {
                summary = "<b> " + summary + "</b>";
            }
            else
            {
                summary = "<i>" + summary + "</i>";
            }

            bool commandIsSelected = false;

            foreach (Command selectedCommand in flowchart.selectedCommands)
            {
                if (selectedCommand == command)
                {
                    commandIsSelected = true;
                    break;
                }
            }

            string commandName = commandInfoAttr.CommandName;

            GUIStyle commandLabelStyle = new GUIStyle(GUI.skin.box);

            commandLabelStyle.normal.background = FungusEditorResources.texCommandBackground;
            int borderSize = 5;

            commandLabelStyle.border.top    = borderSize;
            commandLabelStyle.border.bottom = borderSize;
            commandLabelStyle.border.left   = borderSize;
            commandLabelStyle.border.right  = borderSize;
            commandLabelStyle.alignment     = TextAnchor.MiddleLeft;
            commandLabelStyle.richText      = true;
            commandLabelStyle.fontSize      = 11;
            commandLabelStyle.padding.top  -= 1;

            float indentSize = 20;

            for (int i = 0; i < command.indentLevel; ++i)
            {
                Rect indentRect = position;
                indentRect.x       += i * indentSize - 21;
                indentRect.width    = indentSize + 1;
                indentRect.y       -= 2;
                indentRect.height  += 5;
                GUI.backgroundColor = new Color(0.5f, 0.5f, 0.5f, 1f);
                GUI.Box(indentRect, "", commandLabelStyle);
            }

            float commandNameWidth = Mathf.Max(commandLabelStyle.CalcSize(new GUIContent(commandName)).x, 90f);
            float indentWidth      = command.indentLevel * indentSize;

            Rect commandLabelRect = position;

            commandLabelRect.x      += indentWidth - 21;
            commandLabelRect.y      -= 2;
            commandLabelRect.width  -= (indentSize * command.indentLevel - 22);
            commandLabelRect.height += 5;

            // There's a weird incompatibility between the Reorderable list control used for the command list and
            // the UnityEvent list control used in some commands. In play mode, if you click on the reordering grabber
            // for a command in the list it causes the UnityEvent list to spew null exception errors.
            // The workaround for now is to hide the reordering grabber from mouse clicks by extending the command
            // selection rectangle to cover it. We are planning to totally replace the command list display system.
            Rect clickRect = position;

            clickRect.x     -= 20;
            clickRect.width += 20;

            // Select command via left click
            if (Event.current.type == EventType.MouseDown &&
                Event.current.button == 0 &&
                clickRect.Contains(Event.current.mousePosition))
            {
                if (flowchart.selectedCommands.Contains(command) && Event.current.button == 0)
                {
                    // Left click on already selected command
                    // Command key and shift key is not pressed
                    if (!EditorGUI.actionKey && !Event.current.shift)
                    {
                        BlockEditor.actionList.Add(delegate {
                            flowchart.selectedCommands.Remove(command);
                            flowchart.ClearSelectedCommands();
                        });
                    }

                    // Command key pressed
                    if (EditorGUI.actionKey)
                    {
                        BlockEditor.actionList.Add(delegate {
                            flowchart.selectedCommands.Remove(command);
                        });
                        Event.current.Use();
                    }
                }
                else
                {
                    bool shift = Event.current.shift;

                    // Left click and no command key
                    if (!shift && !EditorGUI.actionKey && Event.current.button == 0)
                    {
                        BlockEditor.actionList.Add(delegate {
                            flowchart.ClearSelectedCommands();
                        });
                        Event.current.Use();
                    }

                    BlockEditor.actionList.Add(delegate {
                        flowchart.AddSelectedCommand(command);
                    });

                    // Find first and last selected commands
                    int firstSelectedIndex = -1;
                    int lastSelectedIndex  = -1;
                    if (flowchart.selectedCommands.Count > 0)
                    {
                        if (flowchart.selectedBlock != null)
                        {
                            for (int i = 0; i < flowchart.selectedBlock.commandList.Count; i++)
                            {
                                Command commandInBlock = flowchart.selectedBlock.commandList[i];
                                foreach (Command selectedCommand in flowchart.selectedCommands)
                                {
                                    if (commandInBlock == selectedCommand)
                                    {
                                        firstSelectedIndex = i;
                                        break;
                                    }
                                }
                            }
                            for (int i = flowchart.selectedBlock.commandList.Count - 1; i >= 0; i--)
                            {
                                Command commandInBlock = flowchart.selectedBlock.commandList[i];
                                foreach (Command selectedCommand in flowchart.selectedCommands)
                                {
                                    if (commandInBlock == selectedCommand)
                                    {
                                        lastSelectedIndex = i;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    if (shift)
                    {
                        int currentIndex = command.commandIndex;
                        if (firstSelectedIndex == -1 ||
                            lastSelectedIndex == -1)
                        {
                            // No selected command found - select entire list
                            firstSelectedIndex = 0;
                            lastSelectedIndex  = currentIndex;
                        }
                        else
                        {
                            if (currentIndex < firstSelectedIndex)
                            {
                                firstSelectedIndex = currentIndex;
                            }
                            if (currentIndex > lastSelectedIndex)
                            {
                                lastSelectedIndex = currentIndex;
                            }
                        }

                        for (int i = Math.Min(firstSelectedIndex, lastSelectedIndex); i < Math.Max(firstSelectedIndex, lastSelectedIndex); ++i)
                        {
                            Command selectedCommand = flowchart.selectedBlock.commandList[i];
                            BlockEditor.actionList.Add(delegate {
                                flowchart.AddSelectedCommand(selectedCommand);
                            });
                        }
                    }

                    Event.current.Use();
                }
                GUIUtility.keyboardControl = 0;                 // Fix for textarea not refeshing (change focus)
            }

            Color commandLabelColor = Color.white;

            if (flowchart.colorCommands)
            {
                commandLabelColor = command.GetButtonColor();
            }

            if (commandIsSelected)
            {
                commandLabelColor = Color.green;
            }
            else if (!command.enabled)
            {
                commandLabelColor = Color.grey;
            }
            else if (error)
            {
                // TODO: Show warning icon
            }

            GUI.backgroundColor = commandLabelColor;

            if (isComment)
            {
                GUI.Label(commandLabelRect, "", commandLabelStyle);
            }
            else
            {
                string commandNameLabel;
                if (flowchart.showLineNumbers)
                {
                    commandNameLabel = command.commandIndex.ToString() + ": " + commandName;
                }
                else
                {
                    commandNameLabel = commandName;
                }

                GUI.Label(commandLabelRect, commandNameLabel, commandLabelStyle);
            }

            if (command.executingIconTimer > Time.realtimeSinceStartup)
            {
                Rect iconRect = new Rect(commandLabelRect);
                iconRect.x     += iconRect.width - commandLabelRect.width - 20;
                iconRect.width  = 20;
                iconRect.height = 20;

                Color storeColor = GUI.color;

                float alpha = (command.executingIconTimer - Time.realtimeSinceStartup) / Block.executingIconFadeTime;
                alpha = Mathf.Clamp01(alpha);

                GUI.color = new Color(1f, 1f, 1f, alpha);
                GUI.Label(iconRect, FungusEditorResources.texPlaySmall, new GUIStyle());

                GUI.color = storeColor;
            }

            Rect summaryRect = new Rect(commandLabelRect);

            if (isComment)
            {
                summaryRect.x += 5;
            }
            else
            {
                summaryRect.x     += commandNameWidth + 5;
                summaryRect.width -= commandNameWidth + 5;
            }

            GUIStyle summaryStyle = new GUIStyle();

            summaryStyle.fontSize       = 10;
            summaryStyle.padding.top   += 5;
            summaryStyle.richText       = true;
            summaryStyle.wordWrap       = false;
            summaryStyle.clipping       = TextClipping.Clip;
            commandLabelStyle.alignment = TextAnchor.MiddleLeft;
            GUI.Label(summaryRect, summary, summaryStyle);

            if (error)
            {
                GUISkin editorSkin = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector);
                Rect    errorRect  = new Rect(summaryRect);
                errorRect.x    += errorRect.width - 20;
                errorRect.y    += 2;
                errorRect.width = 20;
                GUI.Label(errorRect, editorSkin.GetStyle("CN EntryError").normal.background);
                summaryRect.width -= 20;
            }

            GUI.backgroundColor = Color.white;
        }
Exemplo n.º 15
0
        protected virtual IEnumerator ExecuteBlock(Action onComplete = null)
        {
            Flowchart flowchart = GetFlowchart();

            executionState = ExecutionState.Executing;

                        #if UNITY_EDITOR
            // Select the executing block & the first command
            flowchart.selectedBlock = this;
            if (commandList.Count > 0)
            {
                flowchart.ClearSelectedCommands();
                flowchart.AddSelectedCommand(commandList[0]);
            }
                        #endif

            int i = 0;
            while (true)
            {
                // Executing commands specify the next command to skip to by setting jumpToCommandIndex using Command.Continue()
                if (jumpToCommandIndex > -1)
                {
                    i = jumpToCommandIndex;
                    jumpToCommandIndex = -1;
                }

                // Skip disabled commands, comments and labels
                while (i < commandList.Count &&
                       (!commandList[i].enabled ||
                        commandList[i].GetType() == typeof(Comment) ||
                        commandList[i].GetType() == typeof(Label)))
                {
                    i = commandList[i].commandIndex + 1;
                }

                if (i >= commandList.Count)
                {
                    break;
                }

                // The previous active command is needed for if / else / else if commands
                if (activeCommand == null)
                {
                    previousActiveCommandIndex = -1;
                }
                else
                {
                    previousActiveCommandIndex = activeCommand.commandIndex;
                }

                Command command = commandList[i];
                activeCommand = command;

                if (flowchart.gameObject.activeInHierarchy)
                {
                    // Auto select a command in some situations
                    if ((flowchart.selectedCommands.Count == 0 && i == 0) ||
                        (flowchart.selectedCommands.Count == 1 && flowchart.selectedCommands[0].commandIndex == previousActiveCommandIndex))
                    {
                        flowchart.ClearSelectedCommands();
                        flowchart.AddSelectedCommand(commandList[i]);
                    }
                }

                command.isExecuting = true;
                // This icon timer is managed by the FlowchartWindow class, but we also need to
                // set it here in case a command starts and finishes execution before the next window update.
                command.executingIconTimer = Time.realtimeSinceStartup + executingIconFadeTime;
                command.Execute();

                // Wait until the executing command sets another command to jump to via Command.Continue()
                while (jumpToCommandIndex == -1)
                {
                    yield return(null);
                }

                                #if UNITY_EDITOR
                if (flowchart.stepPause > 0f)
                {
                    yield return(new WaitForSeconds(flowchart.stepPause));
                }
                                #endif

                command.isExecuting = false;
            }

            executionState = ExecutionState.Idle;
            activeCommand  = null;

            if (onComplete != null)
            {
                onComplete();
            }
        }
        public void DrawItem(Rect position, int index)
        {
            Command command = this[index].objectReferenceValue as Command;

            if (command == null)
            {
                return;
            }

            CommandInfoAttribute commandInfoAttr = CommandEditor.GetCommandInfo(command.GetType());

            if (commandInfoAttr == null)
            {
                return;
            }

            Flowchart flowchart = command.GetFlowchart();

            if (flowchart == null)
            {
                return;
            }

            bool isComment = command.GetType() == typeof(Comment);
            bool isLabel   = (command.GetType() == typeof(Label));

            bool   error   = false;
            string summary = command.GetSummary();

            if (summary == null)
            {
                summary = "";
            }
            else
            {
                summary = summary.Replace("\n", "").Replace("\r", "");
            }
            if (summary.StartsWith("Error:"))
            {
                error = true;
            }

            if (isComment || isLabel)
            {
                summary = "<b> " + summary + "</b>";
            }
            else
            {
                summary = "<i>" + summary + "</i>";
            }

            bool commandIsSelected = false;

            foreach (Command selectedCommand in flowchart.selectedCommands)
            {
                if (selectedCommand == command)
                {
                    commandIsSelected = true;
                    break;
                }
            }

            string commandName = commandInfoAttr.CommandName;

            GUIStyle commandLabelStyle = new GUIStyle(GUI.skin.box);

            commandLabelStyle.normal.background = FungusEditorResources.texCommandBackground;
            int borderSize = 5;

            commandLabelStyle.border.top    = borderSize;
            commandLabelStyle.border.bottom = borderSize;
            commandLabelStyle.border.left   = borderSize;
            commandLabelStyle.border.right  = borderSize;
            commandLabelStyle.alignment     = TextAnchor.MiddleLeft;
            commandLabelStyle.richText      = true;
            commandLabelStyle.fontSize      = 11;
            commandLabelStyle.padding.top  -= 1;

            float indentSize = 20;

            for (int i = 0; i < command.indentLevel; ++i)
            {
                Rect indentRect = position;
                indentRect.x       += i * indentSize - 21;
                indentRect.width    = indentSize + 1;
                indentRect.y       -= 2;
                indentRect.height  += 5;
                GUI.backgroundColor = new Color(0.5f, 0.5f, 0.5f, 1f);
                GUI.Box(indentRect, "", commandLabelStyle);
            }

            float commandNameWidth = Mathf.Max(commandLabelStyle.CalcSize(new GUIContent(commandName)).x, 90f);
            float indentWidth      = command.indentLevel * indentSize;

            Rect commandLabelRect = position;

            commandLabelRect.x      += indentWidth - 21;
            commandLabelRect.y      -= 2;
            commandLabelRect.width  -= (indentSize * command.indentLevel - 22);
            commandLabelRect.height += 5;

            // Select command via left click
            if (Event.current.type == EventType.MouseDown &&
                Event.current.button == 0 &&
                position.Contains(Event.current.mousePosition))
            {
                if (flowchart.selectedCommands.Contains(command) && Event.current.button == 0)
                {
                    // Left click on already selected command
                    // Command key and shift key is not pressed
                    if (!EditorGUI.actionKey && !Event.current.shift)
                    {
                        flowchart.selectedCommands.Remove(command);
                        flowchart.ClearSelectedCommands();
                    }

                    // Command key pressed
                    if (EditorGUI.actionKey)
                    {
                        flowchart.selectedCommands.Remove(command);
                    }
                    // Shift key pressed
                    if (Event.current.shift)
                    {
                        flowchart.ClearSelectedCommands();
                        if (pinShiftToTop)
                        {
                            for (int i = firstSelectedIndex; i < index + 1; ++i)
                            {
                                flowchart.AddSelectedCommand(flowchart.selectedBlock.commandList[i]);
                            }
                        }
                        else
                        {
                            for (int i = index; i < lastSelectedIndex + 1; ++i)
                            {
                                flowchart.AddSelectedCommand(flowchart.selectedBlock.commandList[i]);
                            }
                        }
                    }
                }
                else
                {
                    // Left click and no command key
                    if (!Event.current.shift && !EditorGUI.actionKey && Event.current.button == 0)
                    {
                        flowchart.ClearSelectedCommands();
                    }
                    flowchart.AddSelectedCommand(command);

                    bool firstSelectedCommandFound = false;
                    if (flowchart.selectedCommands.Count > 0)
                    {
                        if (flowchart.selectedBlock != null)
                        {
                            for (int i = 0; i < flowchart.selectedBlock.commandList.Count; i++)
                            {
                                Command commandInBlock = flowchart.selectedBlock.commandList[i];

                                foreach (Command selectedCommand in flowchart.selectedCommands)
                                {
                                    if (commandInBlock == selectedCommand)
                                    {
                                        if (!firstSelectedCommandFound)
                                        {
                                            firstSelectedIndex        = i;
                                            firstSelectedCommandFound = true;
                                        }
                                        lastSelectedIndex = i;
                                    }
                                }
                            }
                        }
                    }

                    if (Event.current.shift)
                    {
                        for (int i = firstSelectedIndex; i < lastSelectedIndex; ++i)
                        {
                            flowchart.AddSelectedCommand(flowchart.selectedBlock.commandList[i]);
                        }
                    }
                    if (index == firstSelectedIndex)
                    {
                        pinShiftToTop = false;
                    }
                    else if (index == lastSelectedIndex)
                    {
                        pinShiftToTop = true;
                    }
                }
                GUIUtility.keyboardControl = 0;                 // Fix for textarea not refeshing (change focus)
            }

            Color commandLabelColor = Color.white;

            if (flowchart.colorCommands)
            {
                commandLabelColor = command.GetButtonColor();
            }

            if (commandIsSelected)
            {
                commandLabelColor = Color.green;
            }
            else if (!command.enabled)
            {
                commandLabelColor = Color.grey;
            }
            else if (error)
            {
                // TODO: Show warning icon
            }

            GUI.backgroundColor = commandLabelColor;

            if (isComment)
            {
                GUI.Label(commandLabelRect, "", commandLabelStyle);
            }
            else
            {
                GUI.Label(commandLabelRect, commandName, commandLabelStyle);
            }

            if (command.executingIconTimer > Time.realtimeSinceStartup)
            {
                Rect iconRect = new Rect(commandLabelRect);
                iconRect.x     += iconRect.width - commandLabelRect.width - 20;
                iconRect.width  = 20;
                iconRect.height = 20;

                Color storeColor = GUI.color;

                float alpha = (command.executingIconTimer - Time.realtimeSinceStartup) / Block.executingIconFadeTime;
                alpha = Mathf.Clamp01(alpha);

                GUI.color = new Color(1f, 1f, 1f, alpha);
                GUI.Label(iconRect, FungusEditorResources.texPlaySmall, new GUIStyle());

                GUI.color = storeColor;
            }

            Rect summaryRect = new Rect(commandLabelRect);

            if (isComment)
            {
                summaryRect.x += 5;
            }
            else
            {
                summaryRect.x     += commandNameWidth;
                summaryRect.width -= commandNameWidth;
                summaryRect.width -= 5;
            }

            GUIStyle summaryStyle = new GUIStyle();

            summaryStyle.fontSize       = 10;
            summaryStyle.padding.top   += 5;
            summaryStyle.richText       = true;
            summaryStyle.wordWrap       = false;
            summaryStyle.clipping       = TextClipping.Clip;
            commandLabelStyle.alignment = TextAnchor.MiddleLeft;
            GUI.Label(summaryRect, summary, summaryStyle);

            if (error)
            {
                GUISkin editorSkin = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector);
                Rect    errorRect  = new Rect(summaryRect);
                errorRect.x    += errorRect.width - 20;
                errorRect.y    += 2;
                errorRect.width = 20;
                GUI.Label(errorRect, editorSkin.GetStyle("CN EntryError").normal.background);
                summaryRect.width -= 20;
            }

            GUI.backgroundColor = Color.white;
        }
        protected virtual void DrawFlowchartView(Flowchart flowchart)
        {
            Block[] blocks = flowchart.GetComponentsInChildren <Block>(true);

            foreach (Block block in blocks)
            {
                flowchart.scrollViewRect.xMin = Mathf.Min(flowchart.scrollViewRect.xMin, block.nodeRect.xMin - 400);
                flowchart.scrollViewRect.xMax = Mathf.Max(flowchart.scrollViewRect.xMax, block.nodeRect.xMax + 400);
                flowchart.scrollViewRect.yMin = Mathf.Min(flowchart.scrollViewRect.yMin, block.nodeRect.yMin - 400);
                flowchart.scrollViewRect.yMax = Mathf.Max(flowchart.scrollViewRect.yMax, block.nodeRect.yMax + 400);
            }

            // Calc rect for script view
            Rect scriptViewRect = new Rect(0, 0, this.position.width / flowchart.zoom, this.position.height / flowchart.zoom);

            EditorZoomArea.Begin(flowchart.zoom, scriptViewRect);

            DrawGrid(flowchart);

            GLDraw.BeginGroup(scriptViewRect);

            if (Event.current.button == 0 &&
                Event.current.type == EventType.MouseDown &&
                !mouseOverVariables)
            {
                flowchart.selectedBlock = null;
                if (!EditorGUI.actionKey)
                {
                    flowchart.ClearSelectedCommands();
                }
                Selection.activeGameObject = flowchart.gameObject;
            }

            // Draw connections
            foreach (Block block in blocks)
            {
                DrawConnections(flowchart, block, false);
            }
            foreach (Block block in blocks)
            {
                DrawConnections(flowchart, block, true);
            }

            GUIStyle windowStyle = new GUIStyle();

            windowStyle.stretchHeight = true;

            BeginWindows();

            windowBlockMap.Clear();
            for (int i = 0; i < blocks.Length; ++i)
            {
                Block block = blocks[i];

                float nodeWidthA = nodeStyle.CalcSize(new GUIContent(block.blockName)).x + 10;
                float nodeWidthB = 0f;
                if (block.eventHandler != null)
                {
                    nodeWidthB = nodeStyle.CalcSize(new GUIContent(block.eventHandler.GetSummary())).x + 10;
                }

                block.nodeRect.width  = Mathf.Max(Mathf.Max(nodeWidthA, nodeWidthB), 120);
                block.nodeRect.height = 40;

                if (Event.current.button == 0)
                {
                    if (Event.current.type == EventType.MouseDrag && dragWindowId == i)
                    {
                        block.nodeRect.x += Event.current.delta.x;
                        block.nodeRect.y += Event.current.delta.y;

                        forceRepaintCount = 6;
                    }
                    else if (Event.current.type == EventType.MouseUp &&
                             dragWindowId == i)
                    {
                        Vector2 newPos = new Vector2(block.nodeRect.x, block.nodeRect.y);

                        block.nodeRect.x = startDragPosition.x;
                        block.nodeRect.y = startDragPosition.y;

                        Undo.RecordObject(block, "Node Position");

                        block.nodeRect.x = newPos.x;
                        block.nodeRect.y = newPos.y;

                        dragWindowId      = -1;
                        forceRepaintCount = 6;
                    }
                }

                Rect windowRect = new Rect(block.nodeRect);
                windowRect.x += flowchart.scrollPos.x;
                windowRect.y += flowchart.scrollPos.y;

                GUILayout.Window(i, windowRect, DrawWindow, "", windowStyle);

                GUI.backgroundColor = Color.white;

                windowBlockMap.Add(block);
            }

            EndWindows();

            // Draw play icons beside all executing blocks
            if (Application.isPlaying)
            {
                foreach (Block b in blocks)
                {
                    if (b.IsExecuting())
                    {
                        b.executingIconTimer = Time.realtimeSinceStartup + Block.executingIconFadeTime;
                        b.activeCommand.executingIconTimer = Time.realtimeSinceStartup + Block.executingIconFadeTime;
                        forceRepaintCount = 6;
                    }

                    if (b.executingIconTimer > Time.realtimeSinceStartup)
                    {
                        Rect rect = new Rect(b.nodeRect);

                        rect.x     += flowchart.scrollPos.x - 37;
                        rect.y     += flowchart.scrollPos.y + 3;
                        rect.width  = 34;
                        rect.height = 34;

                        if (!b.IsExecuting())
                        {
                            float alpha = (b.executingIconTimer - Time.realtimeSinceStartup) / Block.executingIconFadeTime;
                            alpha     = Mathf.Clamp01(alpha);
                            GUI.color = new Color(1f, 1f, 1f, alpha);
                        }

                        if (GUI.Button(rect, FungusEditorResources.texPlayBig as Texture, new GUIStyle()))
                        {
                            SelectBlock(flowchart, b);
                        }

                        GUI.color = Color.white;
                    }
                }
            }

            PanAndZoom(flowchart);

            GLDraw.EndGroup();

            EditorZoomArea.End();
        }