public Foldout()
        {
            m_Toggle       = new Toggle();
            m_Toggle.value = true;
            m_Toggle.OnValueChanged((evt) =>
            {
                value = m_Toggle.value;
                evt.StopPropagation();
            });
            m_Toggle.AddToClassList(s_ToggleClassName);
            shadow.Add(m_Toggle);

            m_Container = new VisualElement();
            m_Container.clippingOptions = ClippingOptions.ClipContents;
            m_Container.AddToClassList(s_ContentContainerClassName);
            shadow.Add(m_Container);

            AddToClassList(s_FoldoutClassName);
        }
        // 0 = Value, 1 = name, 2 = public, 3 = synced, 4 = syncType
        public UdonParameterProperty(UdonGraph graphView, UdonNodeDefinition definition, UdonNodeData nodeData)
        {
            this.graph      = graphView;
            this.definition = definition;
            this.nodeData   = nodeData;

            // Make sure the incoming nodeData has the right number of nodeValues (super old graphs didn't have sync info)
            if (this.nodeData.nodeValues.Length != 5)
            {
                this.nodeData.nodeValues = GetDefaultNodeValues();
                for (int i = 0; i < nodeData.nodeValues.Length; i++)
                {
                    this.nodeData.nodeValues[i] = nodeData.nodeValues[i];
                }
            }

            // Public Toggle
            isPublic = new EngineUI.Toggle
            {
                text  = "public",
                value = (bool)GetValue(ValueIndices.isPublic)
            };
            isPublic.OnValueChanged(e =>
            {
                SetNewValue(e.newValue, ValueIndices.isPublic);
            });
            Add(isPublic);

            // Is Synced Field
            isSynced = new EngineUI.Toggle
            {
                text  = "synced",
                value = (bool)GetValue(ValueIndices.isSynced),
            };

            isSynced.OnValueChanged(e =>
            {
                SetNewValue(e.newValue, ValueIndices.isSynced);
                syncField.visible = e.newValue;
            });
            Add(isSynced);

            // Sync Field, add to isSynced
            List <string> choices = new List <string>()
            {
                "none", "linear", "smooth"
            };

            syncField = new EditorUI.PopupField <string>(choices, 0)
            {
                visible = isSynced.value
            };
            syncField.OnValueChanged(e =>
            {
                SetNewValue(e.newValue, ValueIndices.syncType);
            });
            isSynced.Add(syncField);

            // Container to show/edit Default Value
            var friendlyName = UdonGraphExtensions.FriendlyTypeName(definition.type).FriendlyNameify();

            defaultValueContainer = new VisualElement
            {
                new Label("default value")
                {
                    name = "default-value-label"
                }
            };
            var field = GetTheRightField(definition.type);

            if (field != null)
            {
                // TODO: need to handle cases where we can't generate the field above
                defaultValueContainer.Add(field);
                Add(defaultValueContainer);
            }
        }
        public BlackboardFieldPropertyView(AbstractNodeGraph graph, INodeProperty property)
        {
            AddStyleSheetPath("Styles/NodeGraphBlackboard");
            m_Graph = graph;

            m_Reference = new TextField();
            m_Reference.OnValueChanged(evt =>
            {
                property.reference = evt.newValue;
                DirtyNodes(ModificationScope.Graph);
            });
            m_Reference.value = property.reference;
            AddRow("Reference", m_Reference);

            if (property is ValueProperty <float> )
            {
                var        floatProperty = (ValueProperty <float>)property;
                FloatField floatField    = new FloatField {
                    value = floatProperty.value
                };
                floatField.OnValueChanged(evt =>
                {
                    floatProperty.value = (float)evt.newValue;
                    DirtyNodes();
                });
                AddRow("Default", floatField);

                /*if (floatProperty.floatType == FloatType.Slider)
                 * {
                 *  var minField = new FloatField { value = floatProperty.rangeValues.x };
                 *  minField.OnValueChanged(minEvt =>
                 *      {
                 *          floatProperty.rangeValues = new Vector2((float)minEvt.newValue, floatProperty.rangeValues.y);
                 *          floatProperty.value = Mathf.Max(Mathf.Min(floatProperty.value, floatProperty.rangeValues.y), floatProperty.rangeValues.x);
                 *          floatField.value = floatProperty.value;
                 *          DirtyNodes();
                 *      });
                 *  minRow = AddRow("Min", minField);
                 *  var maxField = new FloatField { value = floatProperty.rangeValues.y };
                 *  maxField.OnValueChanged(maxEvt =>
                 *      {
                 *          floatProperty.rangeValues = new Vector2(floatProperty.rangeValues.x, (float)maxEvt.newValue);
                 *          floatProperty.value = Mathf.Max(Mathf.Min(floatProperty.value, floatProperty.rangeValues.y), floatProperty.rangeValues.x);
                 *          floatField.value = floatProperty.value;
                 *          DirtyNodes();
                 *      });
                 *  maxRow = AddRow("Max", maxField);
                 * }*/
            }
            else if (property is ValueProperty <int> )
            {
                var intProperty = (ValueProperty <int>)property;

                var field = new IntegerField {
                    value = intProperty.value
                };
                field.OnValueChanged(intEvt =>
                {
                    intProperty.value = intEvt.newValue;
                    DirtyNodes();
                });
                AddRow("Default", field);
            }
            else if (property is ValueProperty <Vector2> )
            {
                var vectorProperty = (ValueProperty <Vector2>)property;
                var field          = new Vector2Field {
                    value = vectorProperty.value
                };
                field.OnValueChanged(evt =>
                {
                    vectorProperty.value = evt.newValue;
                    DirtyNodes();
                });
                AddRow("Default", field);
            }
            else if (property is ValueProperty <Vector3> )
            {
                var vectorProperty = (ValueProperty <Vector3>)property;
                var field          = new Vector3Field {
                    value = vectorProperty.value
                };
                field.OnValueChanged(evt =>
                {
                    vectorProperty.value = evt.newValue;
                    DirtyNodes();
                });
                AddRow("Default", field);
            }
            else if (property is ValueProperty <Vector4> )
            {
                var vectorProperty = (ValueProperty <Vector4>)property;
                var field          = new Vector4Field {
                    value = vectorProperty.value
                };
                field.OnValueChanged(evt =>
                {
                    vectorProperty.value = evt.newValue;
                    DirtyNodes();
                });
                AddRow("Default", field);
            }
            else if (property is ValueProperty <Color> )
            {
                var colorProperty = (ValueProperty <Color>)property;
                //todo add HDR
                var colorField = new ColorField {
                    value = (Color)property.defaultValue, showEyeDropper = false
                };
                colorField.OnValueChanged(evt =>
                {
                    colorProperty.value = evt.newValue;
                    DirtyNodes();
                });
                AddRow("Default", colorField);
            }
            else if (property is ValueProperty <Texture2D> )
            {
                var textureProperty = (ValueProperty <Texture2D>)property;
                var field           = new ObjectField {
                    value = textureProperty.value, objectType = typeof(Texture2D)
                };
                field.OnValueChanged(evt =>
                {
                    textureProperty.value = (Texture2D)evt.newValue;
                    DirtyNodes();
                });
                AddRow("Default", field);
            }
            else if (property is ValueProperty <Cubemap> )
            {
                var cubemapProperty = (ValueProperty <Cubemap>)property;
                var field           = new ObjectField {
                    value = cubemapProperty.value, objectType = typeof(Cubemap)
                };
                field.OnValueChanged(evt =>
                {
                    cubemapProperty.value = (Cubemap)evt.newValue;
                    DirtyNodes();
                });
                AddRow("Default", field);
            }
            else if (property is ValueProperty <bool> )
            {
                var booleanProperty = (ValueProperty <bool>)property;
                EventCallback <ChangeEvent <bool> > onBooleanChanged = evt =>
                {
                    booleanProperty.value = evt.newValue;
                    DirtyNodes();
                };
                var field = new Toggle();
                field.OnValueChanged(onBooleanChanged);
                field.value = booleanProperty.value;
                AddRow("Default", field);
            }
//            AddRow("Type", new TextField());
//            AddRow("Exposed", new Toggle(null));
//            AddRow("Range", new Toggle(null));
//            AddRow("Default", new TextField());
//            AddRow("Tooltip", new TextField());


            AddToClassList("sgblackboardFieldPropertyView");
        }