public void CreateNewSpeech(UINode node)
        {
            // Create new speech, the argument option is the speechs parent
            EditableSpeechNode newSpeech = new EditableSpeechNode();

            newSpeech.ID = CurrentAsset.CurrentIDCounter++;

            // Give the speech it's default values
            newSpeech.Name    = CurrentAsset.DefaultName;
            newSpeech.Icon    = CurrentAsset.DefaultSprite;
            newSpeech.TMPFont = CurrentAsset.DefaultFont;

            // Set this new speech as the options child
            if (node is UIOptionNode)
            {
                (node as UIOptionNode).OptionNode.SetSpeech(newSpeech);
            }
            else if (node is UISpeechNode)
            {
                (node as UISpeechNode).SpeechNode.SetSpeech(newSpeech);
            }

            // This new speech doesn't have any children yet
            newSpeech.Options = null;

            // Create a new UI object to represent the new speech
            UISpeechNode ui = new UISpeechNode(newSpeech, Vector2.zero);

            uiNodes.Add(ui);

            // Set the input state appropriately
            m_inputState         = eInputState.PlacingSpeech;
            m_currentPlacingNode = ui;
        }
        //--------------------------------------
        // Event listeners
        //--------------------------------------

        /* -- Creating Nodes -- */

        public void CreateNewOption(UISpeechNode speechUI)
        {
            // Create new option, the argument speech is the options parent
            EditableOptionNode newOption = new EditableOptionNode();

            newOption.ID = CurrentAsset.CurrentIDCounter++;

            // Give the speech it's default values
            newOption.TMPFont = CurrentAsset.DefaultFont;

            // Add the option to the speechs' list of options
            speechUI.SpeechNode.AddOption(newOption);

            // The option doesn't point to an speech yet
            newOption.Speech = null;

            // Create a new UI object to represent the new option
            UIOptionNode ui = new UIOptionNode(newOption, Vector2.zero);

            uiNodes.Add(ui);

            // Set the input state appropriately
            m_inputState         = eInputState.PlacingOption;
            m_currentPlacingNode = ui;
        }
        //--------------------------------------
        // Input
        //--------------------------------------

        private void ProcessInput()
        {
            Event e = Event.current;

            switch (m_inputState)
            {
            case eInputState.Regular:
                bool inPanel = panelRect.Contains(e.mousePosition) || e.mousePosition.y < TOOLBAR_HEIGHT;
                ProcessNodeEvents(e, inPanel);
                ProcessEvents(e);
                break;

            case eInputState.draggingPanel:
                panelWidth = (position.width - e.mousePosition.x);
                if (panelWidth < 100)
                {
                    panelWidth = 100;
                }

                if (e.type == UnityEngine.EventType.MouseUp && e.button == 0)
                {
                    m_inputState = eInputState.Regular;
                    e.Use();
                }
                Repaint();
                break;

            case eInputState.PlacingOption:
                m_currentPlacingNode.SetPosition(e.mousePosition);

                // Left click
                if (e.type == UnityEngine.EventType.MouseDown && e.button == 0)
                {
                    // Place the option
                    SelectNode(m_currentPlacingNode, true);
                    m_inputState = eInputState.Regular;
                    Repaint();
                    e.Use();
                }
                break;

            case eInputState.PlacingSpeech:
                m_currentPlacingNode.SetPosition(e.mousePosition);

                // Left click
                if (e.type == UnityEngine.EventType.MouseDown && e.button == 0)
                {
                    // Place the option
                    SelectNode(m_currentPlacingNode, true);
                    m_inputState = eInputState.Regular;
                    Repaint();
                    e.Use();
                }
                break;

            case eInputState.ConnectingNode:
                // Click.
                if (e.type == UnityEngine.EventType.MouseDown && e.button == 0)
                {
                    // If we're connecting a Speech node
                    if (m_currentConnectingNode is UISpeechNode)
                    {
                        for (int i = 0; i < uiNodes.Count; i++)
                        {
                            if (uiNodes[i] == m_currentConnectingNode)
                            {
                                continue;
                            }

                            if (uiNodes[i].rect.Contains(e.mousePosition))
                            {
                                if (uiNodes[i] is UISpeechNode)
                                {
                                    UISpeechNode connecting = m_currentConnectingNode as UISpeechNode;
                                    UISpeechNode toBeChild  = uiNodes[i] as UISpeechNode;

                                    // If a relationship between these speechs already exists, swap it
                                    // around, as a 2way speech<->speech relationship cannot exist.
                                    if (connecting.SpeechNode.parents.Contains(toBeChild.SpeechNode))
                                    {
                                        // Remove the relationship
                                        connecting.SpeechNode.parents.Remove(toBeChild.SpeechNode);
                                        toBeChild.SpeechNode.Speech = null;
                                    }

                                    (m_currentConnectingNode as UISpeechNode).SpeechNode.SetSpeech((uiNodes[i] as UISpeechNode).SpeechNode);
                                }
                                else if (uiNodes[i] is UIOptionNode)
                                {
                                    (m_currentConnectingNode as UISpeechNode).SpeechNode.AddOption((uiNodes[i] as UIOptionNode).OptionNode);
                                }

                                m_inputState = eInputState.Regular;
                                e.Use();

                                break;
                            }
                        }
                    }

                    // Else if we're connecting an Option node
                    else if (m_currentConnectingNode is UIOptionNode)
                    {
                        for (int i = 0; i < uiNodes.Count; i++)
                        {
                            if (uiNodes[i] == m_currentConnectingNode)
                            {
                                continue;
                            }

                            if (uiNodes[i].rect.Contains(e.mousePosition))
                            {
                                if (uiNodes[i] is UISpeechNode)
                                {
                                    (m_currentConnectingNode as UIOptionNode).OptionNode.SetSpeech((uiNodes[i] as UISpeechNode).SpeechNode);

                                    m_inputState = eInputState.Regular;
                                    e.Use();
                                    break;
                                }
                            }
                        }
                    }
                }

                // Esc
                if (e.type == UnityEngine.EventType.KeyDown && e.keyCode == KeyCode.Escape)
                {
                    m_inputState = eInputState.Regular;
                }
                break;
            }
        }
        //--------------------------------------
        // Load New Asset
        //--------------------------------------

        public void LoadNewAsset(NPCConversation asset)
        {
            CurrentAsset = asset;
            Log("Loading new asset: " + CurrentAsset.name);

            // Clear all current UI Nodes
            uiNodes.Clear();

            // Deseralize the asset and get the conversation root
            EditableConversation conversation = CurrentAsset.DeserializeForEditor();

            if (conversation == null)
            {
                conversation = new EditableConversation();
            }
            ConversationRoot = conversation.GetRootNode();

            // If it's null, create a root
            if (ConversationRoot == null)
            {
                ConversationRoot = new EditableSpeechNode();
                ConversationRoot.EditorInfo.xPos   = (Screen.width / 2) - (UISpeechNode.Width / 2);
                ConversationRoot.EditorInfo.yPos   = 0;
                ConversationRoot.EditorInfo.isRoot = true;
                conversation.SpeechNodes.Add(ConversationRoot);
            }

            // Get a list of every node in the conversation
            List <EditableConversationNode> allNodes = new List <EditableConversationNode>();

            for (int i = 0; i < conversation.SpeechNodes.Count; i++)
            {
                allNodes.Add(conversation.SpeechNodes[i]);
            }
            for (int i = 0; i < conversation.Options.Count; i++)
            {
                allNodes.Add(conversation.Options[i]);
            }

            // For every node:
            // Find the children and parents by UID
            for (int i = 0; i < allNodes.Count; i++)
            {
                // Remove duplicate parent UIDs
                HashSet <int> noDupes = new HashSet <int>(allNodes[i].parentUIDs);
                allNodes[i].parentUIDs.Clear();
                foreach (int j in noDupes)
                {
                    allNodes[i].parentUIDs.Add(j);
                }

                allNodes[i].parents = new List <EditableConversationNode>();
                for (int j = 0; j < allNodes[i].parentUIDs.Count; j++)
                {
                    allNodes[i].parents.Add(conversation.GetNodeByUID(allNodes[i].parentUIDs[j]));
                }

                if (allNodes[i] is EditableSpeechNode)
                {
                    // Speech options
                    int count = (allNodes[i] as EditableSpeechNode).OptionUIDs.Count;
                    (allNodes[i] as EditableSpeechNode).Options = new List <EditableOptionNode>();
                    for (int j = 0; j < count; j++)
                    {
                        (allNodes[i] as EditableSpeechNode).Options.Add(
                            conversation.GetOptionByUID((allNodes[i] as EditableSpeechNode).OptionUIDs[j]));
                    }

                    // Speech following speech
                    (allNodes[i] as EditableSpeechNode).Speech = conversation.
                                                                 GetSpeechByUID((allNodes[i] as EditableSpeechNode).SpeechUID);
                }
                else if (allNodes[i] is EditableOptionNode)
                {
                    (allNodes[i] as EditableOptionNode).Speech =
                        conversation.GetSpeechByUID((allNodes[i] as EditableOptionNode).SpeechUID);
                }
            }

            // For every node:
            // 1: Create a corresponding UI Node to represent it, and add it to the list
            // 2: Tell any of the nodes children that the node is the childs parent
            for (int i = 0; i < allNodes.Count; i++)
            {
                EditableConversationNode node = allNodes[i];

                if (node is EditableSpeechNode)
                {
                    // 1
                    UISpeechNode uiNode = new UISpeechNode(node,
                                                           new Vector2(node.EditorInfo.xPos, node.EditorInfo.yPos));

                    uiNodes.Add(uiNode);

                    // 2
                    EditableSpeechNode speech = node as EditableSpeechNode;
                    if (speech.Options != null)
                    {
                        for (int j = 0; j < speech.Options.Count; j++)
                        {
                            speech.Options[j].parents.Add(speech);
                        }
                    }

                    if (speech.Speech != null)
                    {
                        speech.Speech.parents.Add(speech);
                    }
                }
                else
                {
                    // 1
                    UIOptionNode uiNode = new UIOptionNode(node,
                                                           new Vector2(node.EditorInfo.xPos, node.EditorInfo.yPos));

                    uiNodes.Add(uiNode);

                    // 2
                    EditableOptionNode option = node as EditableOptionNode;
                    if (option.Speech != null)
                    {
                        option.Speech.parents.Add(option);
                    }
                }
            }

            Recenter();
            Repaint();
#if UNITY_EDITOR
            UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
#endif
        }