-
Notifications
You must be signed in to change notification settings - Fork 634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AGD-2199 - custom dropdown node #11958
Changes from 87 commits
2fdcfcc
30e278d
c0553ff
00587d3
37f164b
795dfd7
d15bfd1
975b821
047b9e2
4c843b2
c05095f
8b1d743
93377f7
b1ec208
0960dd5
9361301
a37cb5e
93f4013
d6e00e2
d576591
b6cc773
00c78e1
103b0ea
312bd9e
0fb12c6
9e25ff2
83f201f
58d37ee
4e0473a
34a82ba
5a4ac2c
6d17a1a
8999190
1423185
b4bc256
68b99df
07c08c7
0a425ef
4794e0f
bc67923
a1d597c
51e71ae
c8cb45a
58c17ba
35effd3
beccd48
dad3c80
99bec28
2bf0479
49bfb1b
9cf40e5
5a60114
1f14c3e
5ac8d1b
8129161
9576110
e4e1345
6c465dc
9c80434
9bb71ce
e849045
c41f397
f036043
b445a0a
bea4f47
b322185
490905e
882e237
4ec277d
d916b86
8b53b5c
a1a783f
6214991
b591474
5327934
f64efbf
d952576
8839d44
920e548
443d557
ef941ea
22199a4
1b7fe1a
e776bd4
88b4f6c
5e1eef9
0b11cd6
27ccb15
752c90f
882f0b5
223deee
f0b7445
86c439d
7f74e9e
1ba123d
ae35692
7a5992b
735d0c4
80ad1d1
24e8014
45047e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
## In Depth | ||
The Custom Dropdown node allows a user to create a dropdown selection input with custom labels and values. If all values are numbers, the output will be a double, and if all values are integers the output will be an integer. In the example below, "Two" is selected in the Custom Dropdown Menu node, making the output of that node the integer `2`. | ||
___ | ||
## Example File | ||
|
||
![Number](./CoreNodeModels.Input.CustomSelection_img.jpg) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,6 @@ private DynamoViewModel DynamoViewModel | |
|
||
public DynamoNodeButton() | ||
{ | ||
Style = (Style)SharedDictionaryManager.DynamoModernDictionary["SNodeTextButton"]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting the style in the constructor was preventing me from overriding the style in XAML. I moved this to a default style in DynamoModern which applies to all |
||
} | ||
|
||
public DynamoNodeButton(ModelBase model, string eventName) | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.Serialization; | ||
using System.Xml; | ||
|
||
using Autodesk.DesignScript.Runtime; | ||
|
||
using Dynamo.Graph; | ||
using Dynamo.Graph.Nodes; | ||
|
||
using Newtonsoft.Json; | ||
|
||
using ProtoCore.AST.AssociativeAST; | ||
|
||
namespace CoreNodeModels.Input | ||
{ | ||
/// <summary> | ||
/// This node allow the user to create a dropdown menu with an with an arbitrary number of customization items | ||
twastvedt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// </summary> | ||
[NodeName("Custom Dropdown Menu")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @LongNguyenP @saintentropy - not sure if this is worth doing, but perhaps this node should actually serialize as the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mjkkirschner We are going to look into it with follow up task |
||
[NodeCategory(BuiltinNodeCategories.CORE_INPUT)] | ||
[NodeDescription("CustomSelectionNodeDescription", typeof(Properties.Resources))] | ||
[NodeSearchTags("CustomSelectionSearchTags", typeof(Properties.Resources))] | ||
[OutPortNames("value")] | ||
[OutPortTypes("var")] | ||
[OutPortDescriptions("Selected value")] | ||
twastvedt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[IsDesignScriptCompatible] | ||
public class CustomSelection : DSDropDownBase | ||
{ | ||
private List<DynamoDropDownItem> serializedItems; | ||
|
||
public List<DynamoDropDownItem> SerializedItems | ||
twastvedt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
get => serializedItems; | ||
set | ||
{ | ||
serializedItems = value; | ||
|
||
Items.Clear(); | ||
|
||
foreach (DynamoDropDownItem item in serializedItems) | ||
{ | ||
Items.Add(item); | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Construct a new Custom Dropdown Menu node | ||
/// </summary> | ||
public CustomSelection() : base("Value") | ||
{ | ||
ArgumentLacing = LacingStrategy.Disabled; | ||
twastvedt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Items.Add(new DynamoDropDownItem("One", "1")); | ||
Items.Add(new DynamoDropDownItem("Two", "2")); | ||
Items.Add(new DynamoDropDownItem("Three", "3")); | ||
|
||
SelectedIndex = 0; | ||
} | ||
|
||
[JsonConstructor] | ||
protected CustomSelection(IEnumerable<PortModel> inPorts, IEnumerable<PortModel> outPorts) : base("Value", inPorts, outPorts) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Build the AST for this node | ||
/// </summary> | ||
/// <param name="inputAstNodes"></param> | ||
/// <returns></returns> | ||
[IsVisibleInDynamoLibrary(false)] | ||
public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes) | ||
{ | ||
AssociativeNode associativeNode = AstFactory.BuildPrimitiveNodeFromObject(GetSelectedValue()); | ||
|
||
return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), associativeNode) }; | ||
} | ||
|
||
/// <summary> | ||
/// Return the selected item as an int, or a double, or a string | ||
/// </summary> | ||
/// <returns></returns> | ||
private object GetSelectedValue() | ||
{ | ||
if (SelectedIndex == -1) | ||
{ | ||
return null; | ||
} | ||
|
||
DynamoDropDownItem selectedItem = Items[SelectedIndex]; | ||
|
||
if (selectedItem?.Item is string value) | ||
{ | ||
if (string.IsNullOrWhiteSpace(value)) | ||
{ | ||
return value; | ||
} | ||
|
||
if (Items.All(item => item is null || ( item.Item is string v && ( string.IsNullOrEmpty(v) || int.TryParse(v, out _) ) ))) | ||
{ | ||
int.TryParse(value, out int intValue); | ||
return intValue; | ||
} | ||
|
||
if (Items.All(item => item is null || ( item.Item is string v && ( string.IsNullOrEmpty(v) || double.TryParse(v, out _) ) ))) | ||
{ | ||
double.TryParse(value, out double doubleValue); | ||
return doubleValue; | ||
} | ||
|
||
return value; | ||
} | ||
|
||
return selectedItem?.Item; | ||
} | ||
|
||
protected override SelectionState PopulateItemsCore(string currentSelection) | ||
{ | ||
return SelectionState.Restore; | ||
} | ||
|
||
[OnSerializing] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what does this attribute do? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a Newtonsoft pre-serialization hook. https://www.newtonsoft.com/json/help/html/SerializationCallbacks.htm |
||
private void OnSerializing(StreamingContext context) | ||
{ | ||
serializedItems = Items.ToList(); | ||
} | ||
|
||
[Obsolete] | ||
protected override void SerializeCore(XmlElement nodeElement, SaveContext context) | ||
{ | ||
nodeElement.SetAttribute("serializedItems", JsonConvert.SerializeObject(Items)); | ||
|
||
base.SerializeCore(nodeElement, context); | ||
} | ||
|
||
[Obsolete] | ||
protected override void DeserializeCore(XmlElement nodeElement, SaveContext context) | ||
{ | ||
XmlAttribute itemsAttribute = nodeElement.Attributes["serializedItems"]; | ||
|
||
if (itemsAttribute == null) | ||
{ | ||
return; | ||
} | ||
|
||
List<DynamoDropDownItem> items = JsonConvert.DeserializeObject<List<DynamoDropDownItem>>(itemsAttribute.Value); | ||
|
||
Items.Clear(); | ||
|
||
foreach (DynamoDropDownItem item in items) | ||
{ | ||
Items.Add(item); | ||
} | ||
|
||
base.DeserializeCore(nodeElement, context); | ||
} | ||
|
||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if the types are mixed? Can you use strings? What are valid value types etc?
Is this dynamic behavior important - I ask this because as we're working on the MSIL compiler - it's very hard to determine the output types of nodes that have dynamic behavior like this - not super important but I imagine that if we move forward with that work outside of a POC we're going to need some principles around not introducing dynamic behavior without a really good reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Immediate answers: values default to strings unless the criteria are met. So, anything's valid, it will just be a string unless we can make everything numbers. I'll add that, or whatever we decide here, to the description.
I'm definitely open to alternatives, though I think this behavior is pretty convenient, intuiting a user's expectations in most common scenarios. I'm not sure what the alternative to dynamic behavior here is. Separate String custom selection and Number custom selection nodes sounds awkward for the user. I imagine the original inspiration for this part may have been the experience in Grasshopper. Though there it's less a feature of the custom selection node itself and more of the global type coercion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's put this on the back burner.