Skip to content

Commit

Permalink
fix(gh): Fixes sorting on dropdown for input enum values (#3020)
Browse files Browse the repository at this point in the history
* fix(gh): Fixes sorting on dropdown for input enum values

Sorting was performed on the original values, which changed the indexes of the enum, hence modifying it's return value to an unrelated one

* fix: Robust enum extraction + unified implementation
  • Loading branch information
AlanRynne authored Nov 3, 2023
1 parent e0ca359 commit 348fe44
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ namespace ConnectorGrasshopper;

public class CreateSchemaObject : SelectKitComponentBase, IGH_VariableParameterComponent
{
private GH_Document _document;
private DebounceDispatcher nicknameChangeDebounce = new();
private bool readFailed;

Expand Down Expand Up @@ -179,8 +178,6 @@ public override void AddedToDocument(GH_Document document)
return;
}

_document = document;

var dialog = new CreateSchemaObjectDialog();
dialog.Owner = Instances.EtoDocumentEditor;
var mouse = Control.MousePosition;
Expand Down Expand Up @@ -231,6 +228,8 @@ public void SwitchConstructor(ConstructorInfo constructor)
foreach (var p in props)
RegisterPropertyAsInputParameter(p, k++);

UserInterfaceUtils.CreateCanvasDropdownForAllEnumInputs(this, props);

Name = constructor.GetCustomAttribute<SchemaInfo>().Name;
Description = constructor.GetCustomAttribute<SchemaInfo>().Description;

Expand Down Expand Up @@ -288,23 +287,9 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index)
newInputParam.Access = GH_ParamAccess.item;

Params.RegisterInputParam(newInputParam, index);

//add dropdown
if (propType.IsEnum)
{
//expire solution so that node gets proper size
ExpireSolution(true);

var instance = Activator.CreateInstance(propType);

var vals = Enum.GetValues(propType).Cast<Enum>().Select(x => x.ToString()).ToList();
var options = CreateDropDown(propName, vals, Attributes.Bounds.X, Params.Input[index].Attributes.Bounds.Y);
_document.AddObject(options, false);
Params.Input[index].AddSource(options);
}
}

public static GH_ValueList CreateDropDown(string name, List<string> values, float x, float y)
public static GH_ValueList CreateDropDown(string name, List<(string name, int value)> values, float x, float y)
{
var valueList = new GH_ValueList();
valueList.CreateAttributes();
Expand All @@ -314,13 +299,12 @@ public static GH_ValueList CreateDropDown(string name, List<string> values, floa
valueList.ListMode = GH_ValueListMode.DropDown;
valueList.ListItems.Clear();

values = values.OrderBy(x=>x).ToList();

for (int i = 0; i < values.Count; i++)
valueList.ListItems.Add(new GH_ValueListItem(values[i], i.ToString()));
valueList.ListItems.Add(new GH_ValueListItem(values[i].name, values[i].value.ToString()));

valueList.Attributes.Pivot = new PointF(x - 200, y - 10);

valueList.ListItems.Sort((item, listItem) => string.Compare(item.Name, listItem.Name));
return valueList;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ public void SetupComponent(ConstructorInfo constructor)
foreach (var p in props)
RegisterPropertyAsInputParameter(p, k++);

UserInterfaceUtils.CreateCanvasDropdownForAllEnumInputs(this, props);

Name = constructor.GetCustomAttribute<SchemaInfo>().Name;
Description = constructor.GetCustomAttribute<SchemaInfo>().Description;

Expand Down Expand Up @@ -330,38 +332,6 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index)
newInputParam.Access = GH_ParamAccess.item;

Params.RegisterInputParam(newInputParam, index);

//add dropdown
if (propType.IsEnum)
{
//expire solution so that node gets proper size
ExpireSolution(true);

var instance = Activator.CreateInstance(propType);

var vals = Enum.GetValues(propType).Cast<Enum>().Select(x => x.ToString()).ToList();
var options = CreateDropDown(propName, vals, Attributes.Bounds.X, Params.Input[index].Attributes.Bounds.Y);
OnPingDocument().AddObject(options, false);
Params.Input[index].AddSource(options);
}
}

public static GH_ValueList CreateDropDown(string name, List<string> values, float x, float y)
{
var valueList = new GH_ValueList();
valueList.CreateAttributes();
valueList.Name = name;
valueList.NickName = name + ":";
valueList.Description = "Select an option...";
valueList.ListMode = GH_ValueListMode.DropDown;
valueList.ListItems.Clear();

for (int i = 0; i < values.Count; i++)
valueList.ListItems.Add(new GH_ValueListItem(values[i], i.ToString()));

valueList.Attributes.Pivot = new PointF(x - 200, y - 10);

return valueList;
}

public override void SolveInstanceWithLogContext(IGH_DataAccess DA)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Special;

namespace ConnectorGrasshopperUtils;

public static class UserInterfaceUtils
{
/// <summary>
/// Used to Create
/// </summary>
/// <param name="name"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static GH_ValueList CreateEnumDropDown(Type enumType, string name, float xPos, float yPos, bool sorted = true)
{
if (!enumType.IsEnum)
{
throw new ArgumentException($"Input type must be {typeof(Enum)} but got {enumType.Name} ", nameof(enumType));
}

// Convert all values of an enum into a GH_ValueListItem and add them to the value list.
// This preserves both the name of the Enum value, as well as it's declared integer value (saved as a string).
var items = Enum.GetValues(enumType)
.Cast<Enum>()
.Select(x => new GH_ValueListItem(name: x.ToString(), expression: Convert.ToInt32(x).ToString()))
.ToList();

var valueList = new GH_ValueList();
valueList.CreateAttributes();
valueList.Name = name;
valueList.NickName = name + ":";
valueList.Description = "Select an option...";
valueList.ListMode = GH_ValueListMode.DropDown;
valueList.Attributes.Pivot = new PointF(xPos, yPos);

valueList.ListItems.Clear();
valueList.ListItems.AddRange(items);

if (sorted)
{
valueList.ListItems.Sort((itemA, itemB) => string.Compare(itemA.Name, itemB.Name));
}

return valueList;
}

/// <summary>
/// Creates a dropdown component on the canvas for every <see cref="Enum"/> type input of the component.
/// This assumes the inputs have already been created, and that there is a 1 to 1 relationship between
/// the number of inputs of the component and the number of properties.
/// </summary>
/// <param name="component">The component to connect the dropdowns to</param>
/// <param name="props">The <see cref="PropertyInfo"/> list of the class being created as a component.</param>
public static void CreateCanvasDropdownForAllEnumInputs(IGH_Component component, ParameterInfo[] props)
{
//Expiring solution ensures the size and position of the parent are updated before placing any input connections
component.ExpireSolution(true);

for (int index = 0; index < props.Length; index++)
{
ParameterInfo p = props[index];
if (!p.ParameterType.IsEnum)
{
continue;
}

var options = CreateEnumDropDown(
p.ParameterType,
p.Name,
component.Attributes.Bounds.X - 200,
component.Params.Input[index].Attributes.Bounds.Y - 1
);
component.OnPingDocument().AddObject(options, false);
component.Params.Input[index].AddSource(options);
}
}
}

0 comments on commit 348fe44

Please sign in to comment.