private void createEntity(object sender, EventArgs e)
        {
            cGUID thisID = Utilities.GenerateGUID(DateTime.Now.ToString("G"));

            if (createDatatypeEntity.Checked)
            {
                //Make the DatatypeEntity
                DatatypeEntity newEntity = new DatatypeEntity(thisID);
                newEntity.type      = (CathodeDataType)entityVariant.SelectedIndex;
                newEntity.parameter = Utilities.GenerateGUID(textBox1.Text);

                //Make the parameter to give this DatatypeEntity a value (the only time you WOULDN'T want this is if the val is coming from a linked entity)
                CathodeParameter thisParam = null;
                switch (newEntity.type)
                {
                case CathodeDataType.POSITION:
                    thisParam = new CathodeTransform();
                    break;

                case CathodeDataType.FLOAT:
                    thisParam = new CathodeFloat();
                    break;

                case CathodeDataType.FILEPATH:
                case CathodeDataType.STRING:
                    thisParam = new CathodeString();
                    break;

                case CathodeDataType.SPLINE_DATA:
                    thisParam = new CathodeSpline();
                    break;

                case CathodeDataType.ENUM:
                    thisParam = new CathodeEnum();
                    ((CathodeEnum)thisParam).enumID = new cGUID("4C-B9-82-48");     //ALERTNESS_STATE is the first alphabetically
                    break;

                case CathodeDataType.SHORT_GUID:
                    thisParam = new CathodeResource();
                    ((CathodeResource)thisParam).resourceID = new cGUID("00-00-00-00");
                    break;

                case CathodeDataType.BOOL:
                    thisParam = new CathodeBool();
                    break;

                case CathodeDataType.DIRECTION:
                    thisParam = new CathodeVector3();
                    break;

                case CathodeDataType.INTEGER:
                    thisParam = new CathodeInteger();
                    break;
                }
                newEntity.parameters.Add(new CathodeLoadedParameter(newEntity.parameter, thisParam));

                //Add to flowgraph & save name
                flow.datatypes.Add(newEntity);
                if (NodeDB.GetCathodeName(newEntity.parameter) == newEntity.parameter.ToString())
                {
                    NodeDBEx.AddNewParameterName(newEntity.parameter, textBox1.Text);
                }
                NewEntity = newEntity;
            }
            else if (createFunctionEntity.Checked)
            {
                //Create FunctionEntity
                FunctionEntity newEntity = new FunctionEntity(thisID);
                switch (entityVariant.Text)
                {
                //TODO: find a nicer way of auto selecting this (E.G. can we reflect to class names?)
                case "CAGEAnimation":
                    newEntity = new CAGEAnimation(thisID);
                    break;

                case "TriggerSequence":
                    newEntity = new TriggerSequence(thisID);
                    break;
                }
                newEntity.function = CathodeEntityDatabase.GetEntityAtIndex(entityVariant.SelectedIndex).guid;
                //TODO: auto populate params here

                //Add to flowgraph & save name
                flow.functions.Add(newEntity);
                NodeDBEx.AddNewNodeName(thisID, textBox1.Text);
                NewEntity = newEntity;
            }
            else if (createFlowgraphEntity.Checked)
            {
                //Create FunctionEntity
                FunctionEntity   newEntity         = new FunctionEntity(thisID);
                CathodeFlowgraph selectedFlowgraph = availableFlows.FirstOrDefault(o => o.name == entityVariant.Text);
                if (selectedFlowgraph == null)
                {
                    MessageBox.Show("Failed to look up flowgraph!\nPlease report this issue on GitHub.\n\n" + entityVariant.Text, "Could not find flowgraph!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                newEntity.function = selectedFlowgraph.nodeID;

                //Add to flowgraph & save name
                flow.functions.Add(newEntity);
                NodeDBEx.AddNewNodeName(thisID, textBox1.Text);
                NewEntity = newEntity;
            }

            this.Close();
        }
        public CAGEAnimationEditor(CAGEAnimation _node)
        {
            animNode = _node;
            InitializeComponent();

            animNode.keyframeHeaders = animNode.keyframeHeaders.OrderBy(o => o.parameterID).ToList();
            string   previousGroup   = "";
            int      groupCount      = 0;
            int      maxWidth        = 0;
            int      groupBoxOffset  = 3;
            int      groupHeight     = 0;
            int      countInGroup    = 0;
            GroupBox currentGroupBox = null;

            for (int i = 0; i < animNode.keyframeHeaders.Count; i++)
            {
                string paramGroupName = NodeDBEx.GetParameterName(animNode.keyframeHeaders[i].parameterID);
                if (i == 0 || previousGroup != paramGroupName)
                {
                    if (currentGroupBox != null)
                    {
                        currentGroupBox.Size = new Size(maxWidth, groupHeight);
                        groupBoxOffset      += currentGroupBox.Size.Height + 10;
                    }

                    currentGroupBox          = new GroupBox();
                    currentGroupBox.Text     = paramGroupName;
                    currentGroupBox.Location = new Point(3, groupBoxOffset);
                    NodeParams.Controls.Add(currentGroupBox);
                    groupCount++;
                    maxWidth     = 0;
                    groupHeight  = 0;
                    countInGroup = 0;
                }
                previousGroup = paramGroupName;

                TextBox paramName = new TextBox();
                paramName.Text     = NodeDBEx.GetParameterName(animNode.keyframeHeaders[i].parameterSubID);
                paramName.ReadOnly = true;
                paramName.Location = new Point(6, 19 + (countInGroup * 23));
                paramName.Size     = new Size(119, 20);
                currentGroupBox.Controls.Add(paramName);

                CathodeParameterKeyframe paramData = animNode.keyframeData.FirstOrDefault(o => o.ID == animNode.keyframeHeaders[i].keyframeDataID);
                //TODO: populate full min max keyframes so new ones can be created
                int keyframeWidth = paramName.Location.X + paramName.Width;
                if (paramData != null)
                {
                    for (int x = 0; x < paramData.keyframes.Count; x++)
                    {
                        Button keyframeBtn = new Button();
                        keyframeBtn.Size     = new Size(27, 23);
                        keyframeBtn.Location = new Point(134 + ((keyframeBtn.Size.Width + 6) * x), 18 + (countInGroup * 23));
                        keyframeBtn.Text     = paramData.keyframes[x].secondsSinceStart.ToString();
                        keyframeBtn.AccessibleDescription = paramData.ID.ToString() + " " + x + " " + paramName.Text;
                        keyframeBtn.Click += KeyframeBtn_Click;
                        currentGroupBox.Controls.Add(keyframeBtn);
                        if (keyframeBtn.Location.X > maxWidth)
                        {
                            maxWidth = keyframeBtn.Location.X;
                        }
                        keyframeWidth = keyframeBtn.Location.X + keyframeBtn.Width;
                    }
                }

                CathodeFlowgraph flow;
                CathodeEntity    resolvedEntity = EditorUtils.ResolveHierarchy(animNode.keyframeHeaders[i].connectedEntity, out flow);
                if (resolvedEntity != null)
                {
                    TextBox controllingEntity = new TextBox();
                    controllingEntity.Text     = "Controlling: " + NodeDBEx.GetEntityName(resolvedEntity.nodeID);
                    controllingEntity.Location = new Point(keyframeWidth + 5, 18 + (countInGroup * 23));
                    controllingEntity.Size     = new Size(200, 20);
                    controllingEntity.ReadOnly = true;
                    currentGroupBox.Controls.Add(controllingEntity);
                    int thisWidth = controllingEntity.Location.X + controllingEntity.Width + 5;
                    if (thisWidth > maxWidth)
                    {
                        maxWidth = thisWidth;
                    }
                }

                groupHeight = paramName.Location.Y + paramName.Height + 5;
                countInGroup++;
            }
            if (currentGroupBox != null)
            {
                currentGroupBox.Size = new Size(maxWidth, groupHeight);
            }
        }