private static string GenerateNodeNameInternal(CathodeEntity entity, CathodeFlowgraph currentFlowgraph) { string desc = ""; switch (entity.variant) { case EntityVariant.DATATYPE: desc = NodeDBEx.GetParameterName(((DatatypeEntity)entity).parameter) + " (DataType " + ((DatatypeEntity)entity).type.ToString() + ")"; break; case EntityVariant.FUNCTION: desc = NodeDBEx.GetEntityName(entity.nodeID) + " (" + NodeDBEx.GetParameterName(((FunctionEntity)entity).function) + ")"; break; case EntityVariant.OVERRIDE: //desc = NodeDBEx.GetEntityName(entity.nodeID) + " (" + HierarchyToString(((OverrideEntity)entity).hierarchy, currentFlowgraph) + ")"; desc = NodeDBEx.GetEntityName(entity.nodeID) + " (*OVERRIDE*)"; break; case EntityVariant.PROXY: //desc = NodeDBEx.GetEntityName(entity.nodeID) + " (" + HierarchyToString(((ProxyEntity)entity).hierarchy, currentFlowgraph) + ")"; desc = NodeDBEx.GetEntityName(entity.nodeID) + " (*PROXY*)"; break; case EntityVariant.NOT_SETUP: //desc = NodeDBEx.GetEntityName(entity.nodeID); desc = NodeDBEx.GetEntityName(entity.nodeID) + " (*NOT SETUP*)"; break; } return("[" + entity.nodeID.ToString() + "] " + desc); }
private void rename_node_closed(Object sender, FormClosedEventArgs e) { if (((CathodeEditorGUI_RenameNode)sender).didSave && ((CathodeEditorGUI_RenameNode)sender).NodeID == CurrentInstance.selectedEntity.nodeID) { NodeDBEx.AddNewNodeName(CurrentInstance.selectedEntity.nodeID, ((CathodeEditorGUI_RenameNode)sender).NodeName); string nodeID = CurrentInstance.selectedEntity.nodeID.ToString(); string newNodeName = EditorUtils.GenerateNodeName(CurrentInstance.selectedEntity, CurrentInstance.selectedFlowgraph); for (int i = 0; i < flowgraph_content.Items.Count; i++) { if (flowgraph_content.Items[i].ToString().Substring(1, 11) == nodeID) { flowgraph_content.Items[i] = newNodeName; break; } } for (int i = 0; i < flowgraph_content_RAW.Count; i++) { if (flowgraph_content_RAW[i].Substring(1, 11) == nodeID) { flowgraph_content_RAW[i] = newNodeName; break; } } LoadEntity(CurrentInstance.selectedEntity); } this.BringToFront(); this.Focus(); }
/* Display an entity hierarchy as a string */ public static string HierarchyToString(List <cGUID> hierarchy) { CathodeFlowgraph currentFlowgraphToSearch = CurrentInstance.selectedFlowgraph; CathodeEntity entity = null; string combinedString = ""; for (int i = 0; i < hierarchy.Count; i++) { if (hierarchy[i] == new cGUID("00-00-00-00")) { break; } entity = currentFlowgraphToSearch.GetEntityByID(hierarchy[i]); if (entity != null) { combinedString += NodeDBEx.GetEntityName(entity.nodeID) + " -> "; } if (entity != null && entity.variant == EntityVariant.FUNCTION) { CathodeFlowgraph flowRef = CurrentInstance.commandsPAK.GetFlowgraph(((FunctionEntity)entity).function); if (flowRef != null) { currentFlowgraphToSearch = flowRef; } } } if (combinedString.Length >= 4) { combinedString = combinedString.Substring(0, combinedString.Length - 4); } return(combinedString); }
/* Save the current edits */ public void SaveCommandsPAK() { if (CurrentInstance.commandsPAK == null) { return; } Cursor.Current = Cursors.WaitCursor; try { CurrentInstance.commandsPAK.Save(); } catch (Exception e) { Cursor.Current = Cursors.Default; MessageBox.Show("Failed to save COMMANDS.PAK!\n" + e.Message, "Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } NodeDBEx.SaveNames(); if (modifyMVR.Checked) { CathodeMovers mvr = new CathodeMovers(CurrentInstance.commandsPAK.Filepath.Replace("COMMANDS.PAK", "MODELS.MVR")); for (int i = 0; i < mvr.Movers.Count; i++) { /* * if (mvr.Movers[i].IsThisTypeID == MoverType.STATIC_MODEL) * { * CathodeFlowgraph flowgraph = GetFlowgraphContainingNode(mvr.Movers[i].NodeID); * if (flowgraph == null) continue; * if (flowgraph.name.Contains("REQUIRED_ASSETS") && flowgraph.name.Contains("VFX")) continue; * MoverEntry mover = mvr.Movers[i]; * mover.IsThisTypeID = MoverType.DYNAMIC_MODEL; * mvr.Movers[i] = mover; * } */ MOVER_DESCRIPTOR mover = mvr.Movers[i]; //This is a **TEMP** hack! mover.Transform = System.Numerics.Matrix4x4.CreateScale(new System.Numerics.Vector3(0, 0, 0)) * System.Numerics.Matrix4x4.CreateFromQuaternion(System.Numerics.Quaternion.Identity) * System.Numerics.Matrix4x4.CreateTranslation(new System.Numerics.Vector3(-9999.0f, -9999.0f, -9999.0f)); mover.IsThisTypeID = MoverType.DYNAMIC_MODEL; mover.NodeID = new cGUID("00-00-00-00"); mvr.Movers[i] = mover; } if (mvr.FilePath != "") { mvr.Save(); } } Cursor.Current = Cursors.Default; }
private void RefreshNodeLinks() { node_children.BeginUpdate(); node_children.Items.Clear(); linkedNodeListIDs.Clear(); addNewLink.Enabled = currentlyShowingChildLinks; //removeSelectedLink.Enabled = currentlyShowingChildLinks; //out_pin_goto.Enabled = currentlyShowingChildLinks; showLinkParents.Text = (currentlyShowingChildLinks) ? "Parents" : "Children"; if (CurrentInstance.selectedFlowgraph == null || CurrentInstance.selectedEntity == null) { return; } if (currentlyShowingChildLinks) { //Child links (pins out of this node) foreach (CathodeNodeLink link in CurrentInstance.selectedEntity.childLinks) { node_children.Items.Add( /*"[" + link.connectionID.ToString() + "] " +*/ "(" + NodeDBEx.GetParameterName(link.parentParamID) + ") => " + NodeDBEx.GetEntityName(link.childID) + " (" + NodeDBEx.GetParameterName(link.childParamID) + ")"); linkedNodeListIDs.Add(link.connectionID); } } else { //Parent links (pins into this node) List <CathodeEntity> ents = CurrentInstance.selectedFlowgraph.GetEntities(); foreach (CathodeEntity entity in ents) { foreach (CathodeNodeLink link in entity.childLinks) { if (link.childID != CurrentInstance.selectedEntity.nodeID) { continue; } node_children.Items.Add( /*"[" + link.connectionID.ToString() + "] " +*/ NodeDBEx.GetEntityName(entity.nodeID) + " (" + NodeDBEx.GetParameterName(link.parentParamID) + ") => " + "(" + NodeDBEx.GetParameterName(link.childParamID) + ")"); linkedNodeListIDs.Add(link.connectionID); } } } node_children.EndUpdate(); }
public void LoadCommandsPAK(string level) { //Reset UI ClearUI(true, true, true); CurrentInstance.commandsPAK = null; //Load string path_to_ENV = SharedData.pathToAI + "/DATA/ENV/PRODUCTION/" + level; try { CurrentInstance.commandsPAK = new CommandsPAK(path_to_ENV + "/WORLD/COMMANDS.PAK"); } catch (Exception e) { MessageBox.Show("Failed to load COMMANDS.PAK!\n" + e.Message, "Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error); CurrentInstance.commandsPAK = null; return; } //Sanity check if (!CurrentInstance.commandsPAK.Loaded) { MessageBox.Show("Failed to load COMMANDS.PAK!\nPlease place this executable in your Alien: Isolation folder.", "Environment error!", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } else if (CurrentInstance.commandsPAK.EntryPoints[0] == null) { MessageBox.Show("Failed to load COMMANDS.PAK!\nPlease reset your game files.", "COMMANDS.PAK corrupted!", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } //Load in any custom param/node names NodeDBEx.LoadNames(); //Begin caching entity names so we don't have to keep generating them if (currentBackgroundCacher != null) { currentBackgroundCacher.Dispose(); } currentBackgroundCacher = Task.Factory.StartNew(() => EditorUtils.GenerateEntityNameCache(this)); //Populate file tree treeHelper.UpdateFileTree(CurrentInstance.commandsPAK.GetFlowgraphNames().ToList()); //Show info in UI RefreshStatsUI(); }
public CathodeEditorGUI_RemoveParameter(CathodeEntity entity) { InitializeComponent(); if (entity.parameters.Count == 0) { this.Close(); return; } _entity = entity; parameterToDelete.BeginUpdate(); parameterToDelete.Items.Clear(); for (int i = 0; i < _entity.parameters.Count; i++) { parameterToDelete.Items.Add(NodeDBEx.GetParameterName(_entity.parameters[i].paramID)); } parameterToDelete.SelectedIndex = 0; parameterToDelete.EndUpdate(); }
public CathodeEditorGUI_RenameNode(cGUID node) { InitializeComponent(); entity_name.Text = NodeDBEx.GetEntityName(node); NodeID = node; }
/* Load a entity into the UI */ private void LoadEntity(CathodeEntity edit_node) { if (edit_node == null) { return; } ClearUI(false, false, true); CurrentInstance.selectedEntity = edit_node; Cursor.Current = Cursors.WaitCursor; //populate info labels selected_node_id.Text = edit_node.nodeID.ToString(); selected_node_type.Text = edit_node.variant.ToString(); string nodetypedesc = ""; switch (edit_node.variant) { case EntityVariant.FUNCTION: nodetypedesc = NodeDBEx.GetParameterName(((FunctionEntity)edit_node).function); node_to_flowgraph_jump.Visible = (CurrentInstance.commandsPAK.GetFlowgraph(((FunctionEntity)edit_node).function) != null); selected_node_name.Text = NodeDBEx.GetEntityName(edit_node.nodeID); #if DEBUG //TODO: PULL THIS INTO STABLE editCAGEAnimationKeyframes.Visible = nodetypedesc == "CAGEAnimation"; #endif break; case EntityVariant.DATATYPE: nodetypedesc = "DataType " + ((DatatypeEntity)edit_node).type.ToString(); selected_node_name.Text = NodeDBEx.GetParameterName(((DatatypeEntity)edit_node).parameter); break; case EntityVariant.PROXY: case EntityVariant.OVERRIDE: node_to_flowgraph_jump.Visible = true; selected_node_name.Text = NodeDBEx.GetEntityName(edit_node.nodeID); break; default: selected_node_name.Text = NodeDBEx.GetEntityName(edit_node.nodeID); break; } selected_node_type_description.Text = nodetypedesc; //show resource editor button if this node has a resource reference cGUID resourceParamID = Utilities.GenerateGUID("resource"); CathodeLoadedParameter resourceParam = CurrentInstance.selectedEntity.parameters.FirstOrDefault(o => o.paramID == resourceParamID); #if DEBUG //TODO: PULL THIS INTO STABLE editNodeResources.Visible = ((resourceParam != null) || CurrentInstance.selectedEntity.resources.Count != 0); #endif //populate parameter inputs int current_ui_offset = 7; for (int i = 0; i < edit_node.parameters.Count; i++) { if (edit_node.parameters[i].paramID == resourceParamID) { continue; //We use the resource editor button (above) for resource parameters } CathodeParameter this_param = edit_node.parameters[i].content; UserControl parameterGUI = null; switch (this_param.dataType) { case CathodeDataType.POSITION: parameterGUI = new GUI_TransformDataType(); ((GUI_TransformDataType)parameterGUI).PopulateUI((CathodeTransform)this_param, edit_node.parameters[i].paramID); break; case CathodeDataType.INTEGER: parameterGUI = new GUI_NumericDataType(); ((GUI_NumericDataType)parameterGUI).PopulateUI_Int((CathodeInteger)this_param, edit_node.parameters[i].paramID); break; case CathodeDataType.STRING: parameterGUI = new GUI_StringDataType(); ((GUI_StringDataType)parameterGUI).PopulateUI((CathodeString)this_param, edit_node.parameters[i].paramID); break; case CathodeDataType.BOOL: parameterGUI = new GUI_BoolDataType(); ((GUI_BoolDataType)parameterGUI).PopulateUI((CathodeBool)this_param, edit_node.parameters[i].paramID); break; case CathodeDataType.FLOAT: parameterGUI = new GUI_NumericDataType(); ((GUI_NumericDataType)parameterGUI).PopulateUI_Float((CathodeFloat)this_param, edit_node.parameters[i].paramID); break; case CathodeDataType.DIRECTION: parameterGUI = new GUI_VectorDataType(); ((GUI_VectorDataType)parameterGUI).PopulateUI((CathodeVector3)this_param, edit_node.parameters[i].paramID); break; case CathodeDataType.ENUM: parameterGUI = new GUI_EnumDataType(); ((GUI_EnumDataType)parameterGUI).PopulateUI((CathodeEnum)this_param, edit_node.parameters[i].paramID); break; case CathodeDataType.SHORT_GUID: parameterGUI = new GUI_HexDataType(); ((GUI_HexDataType)parameterGUI).PopulateUI((CathodeResource)this_param, edit_node.parameters[i].paramID, CurrentInstance.selectedFlowgraph); break; case CathodeDataType.SPLINE_DATA: parameterGUI = new GUI_SplineDataType(); ((GUI_SplineDataType)parameterGUI).PopulateUI((CathodeSpline)this_param, edit_node.parameters[i].paramID); break; } parameterGUI.Location = new Point(15, current_ui_offset); current_ui_offset += parameterGUI.Height + 6; NodeParams.Controls.Add(parameterGUI); } RefreshNodeLinks(); Cursor.Current = Cursors.Default; }
/* Duplicate selected entity */ private void duplicateSelectedNode_Click(object sender, EventArgs e) { if (CurrentInstance.selectedEntity == null) { return; } if (!ConfirmAction("Are you sure you want to duplicate this entity?")) { return; } //Generate new node ID and name CathodeEntity newEnt = Utilities.CloneObject(CurrentInstance.selectedEntity); newEnt.nodeID = Utilities.GenerateGUID(DateTime.Now.ToString("G")); NodeDBEx.AddNewNodeName(newEnt.nodeID, NodeDBEx.GetEntityName(CurrentInstance.selectedEntity.nodeID) + "_clone"); //Add parent links in to this node that linked in to the other node List <CathodeEntity> ents = CurrentInstance.selectedFlowgraph.GetEntities(); List <CathodeNodeLink> newLinks = new List <CathodeNodeLink>(); int num_of_new_things = 1; foreach (CathodeEntity entity in ents) { newLinks.Clear(); foreach (CathodeNodeLink link in entity.childLinks) { if (link.childID == CurrentInstance.selectedEntity.nodeID) { CathodeNodeLink newLink = new CathodeNodeLink(); newLink.connectionID = Utilities.GenerateGUID(DateTime.Now.ToString("G") + num_of_new_things.ToString()); num_of_new_things++; newLink.childID = newEnt.nodeID; newLink.childParamID = link.childParamID; newLink.parentParamID = link.parentParamID; newLinks.Add(newLink); } } if (newLinks.Count != 0) { entity.childLinks.AddRange(newLinks); } } //Save back to flowgraph switch (newEnt.variant) { case EntityVariant.FUNCTION: CurrentInstance.selectedFlowgraph.functions.Add((FunctionEntity)newEnt); break; case EntityVariant.DATATYPE: CurrentInstance.selectedFlowgraph.datatypes.Add((DatatypeEntity)newEnt); break; case EntityVariant.PROXY: CurrentInstance.selectedFlowgraph.proxies.Add((ProxyEntity)newEnt); break; case EntityVariant.OVERRIDE: CurrentInstance.selectedFlowgraph.overrides.Add((OverrideEntity)newEnt); break; case EntityVariant.NOT_SETUP: CurrentInstance.selectedFlowgraph.unknowns.Add(newEnt); break; } //Load in to UI ReloadUIForNewEntity(newEnt); }
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(); }
/* Utility: generate a list of suggested parameters for an entity */ public static List <string> GenerateParameterList(CathodeEntity entity, out bool didGenerateFromDB) { didGenerateFromDB = false; List <string> items = new List <string>(); if (CurrentInstance.commandsPAK == null) { return(items); } switch (entity.variant) { case EntityVariant.FUNCTION: cGUID function = ((FunctionEntity)entity).function; List <CathodeEntityDatabase.ParameterDefinition> parameters = CathodeEntityDatabase.GetParametersFromEntity(function); if (parameters != null) { didGenerateFromDB = true; for (int i = 0; i < parameters.Count; i++) { items.Add(parameters[i].name); } } else { string[] options = NodeDB.GetEntityParameterList(NodeDBEx.GetParameterName(function)); items.Add("trigger"); items.Add("reference"); //TODO: populate all params from EntityMethodInterface? if (options == null) { CathodeFlowgraph flow = CurrentInstance.commandsPAK.GetFlowgraph(function); if (flow == null) { break; } for (int i = 0; i < flow.datatypes.Count; i++) { string to_add = NodeDBEx.GetParameterName(flow.datatypes[i].parameter); //TODO: also return datatype here if (!items.Contains(to_add)) { items.Add(to_add); } } } else { for (int i = 0; i < options.Length; i++) { if (!items.Contains(options[i])) { items.Add(options[i]); } } } } break; case EntityVariant.DATATYPE: items.Add(NodeDBEx.GetParameterName(((DatatypeEntity)entity).parameter)); break; //TODO: support other types here } items.Sort(); return(items); }
private void button1_Click(object sender, EventArgs e) { if (param_name.Text == "") { return; } cGUID thisParamID = Utilities.GenerateGUID(param_name.Text); foreach (CathodeLoadedParameter param in node.parameters) { if (param.paramID == thisParamID) { MessageBox.Show("This parameter already exists on the entity!"); return; } } CathodeParameter thisParam = null; switch ((CathodeDataType)param_datatype.SelectedIndex) { 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; } node.parameters.Add(new CathodeLoadedParameter(thisParamID, thisParam)); //If this parameter doesn't come up in the CATHODE string table, add it to our own if (NodeDB.GetCathodeName(thisParamID) == thisParamID.ToString()) { NodeDBEx.AddNewParameterName(thisParamID, param_name.Text); } 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); } }