VisualElement MakeFieldRow(FieldModel fieldModel)
        {
            var field = new BlackboardField(null, fieldModel.Name, fieldModel.Type?.FriendlyName() ?? "<unknown>");

            field.userData = fieldModel;
            var propertyView = new VisualElement();

            var fieldRow = new BlackboardRow(field, propertyView)
            {
                userData = fieldModel
            };

            fieldRow.expanded = m_ExpandedRows.Contains(fieldModel);

            field.Add(new Button(() => DeleteField(fieldRow, fieldModel))
            {
                name = "deleteComponentIcon"
            });

            var fieldType = new Button()
            {
                text = fieldModel.Type?.FriendlyName() ?? "<unknown>"
            };

            fieldType.clickable.clicked += () =>
            {
                InitializeTypeItemsAndCache(); // delay init as the type cache seems to have a weird timing issue otherwise
                SearcherWindow.Show(this, new Searcher.Searcher(new SearcherDatabase(TypeItems), new TypeSearcherAdapter("Pick a type")), item =>
                {
                    PickTypeSearcherItem titem = item as PickTypeSearcherItem;

                    if (titem == null)
                    {
                        return(true);
                    }
                    fieldModel.Type = titem.Type;
                    fieldType.text  = titem.Type.FriendlyName();

                    if (titem.Shared)
                    {
                        SetStructType(CurrentStruct, StructType.SharedComponent);
                    }

                    SetModelDirty();

                    return(true);
                }, Event.current.mousePosition, null);
            };
            propertyView.Add(new PropertyRow("Type", fieldType));

            var toggle = new Toggle()
            {
                value = fieldModel.HideInInspector
            };

            toggle.RegisterValueChangedCallback(e =>
            {
                fieldModel.HideInInspector = e.newValue;
                SetModelDirty();
            });
            propertyView.Add(new PropertyRow("Hide in inspector", toggle));

            // TODO ugly
            if (!fieldModel.Type.IsValueType && fieldModel.Type != typeof(GameObject))
            {
                propertyView.Add(new Label("This is a reference type and requires the component to be a shared component"));
            }
            return(fieldRow);
        }
 void DeleteField(BlackboardRow field, FieldModel fieldModel)
 {
     fieldModel.RemoveFromStruct();
     field.RemoveFromHierarchy();
     SetModelDirty();
 }
        void OnEnable()
        {
            rootVisualElement.styleSheets.Add(AssetDatabase.LoadAssetAtPath <StyleSheet>(UICreationHelper.TemplatePath + "ComponentEditor.uss"));

            rootVisualElement.AddToClassList("root");
            var root = rootVisualElement;

            m_GhostGraphView = new GhostGraphView(this);

            m_Blackboard = new Blackboard(m_GhostGraphView)
            {
                windowed = true
            };
            m_BlackboardContentContainer = m_Blackboard.Q("unity-content-container");

            // need wait for layout to avoid default 200px width value
            root.RegisterCallback <GeometryChangedEvent>(e =>
            {
                if (!m_Blackboard.scrollable)
                {
                    m_Blackboard.scrollable = true;
                    var sv = m_Blackboard.Q <ScrollView>();
#if UNITY_2020_1_OR_NEWER
                    sv.RemoveFromClassList(ScrollView.hContentVariantUssClassName);
                    sv.RemoveFromClassList(ScrollView.hViewportVariantUssClassName);
#else
                    sv.RemoveFromClassList(ScrollView.horizontalVariantUssClassName);
#endif
                    sv.RemoveFromClassList(ScrollView.scrollVariantUssClassName);
                }

                if (m_BlackboardContentContainer != null)
                {
                    m_BlackboardContentContainer.style.width = e.newRect.width;
                }
            });

            m_Blackboard.editTextRequested = EditTextRequested;
            m_Blackboard.addItemRequested  = AddItemRequested;
            root.Add(m_Blackboard);

            m_Blackboard.Add(m_InfoSection = new BlackboardSection()
            {
                name = "infoSection", title = "No component selected"
            });
            m_InfoSection.Add(new Label("Open an existing component or create a new one.")
            {
                name = "noSelectionLabel"
            });
            m_Blackboard.Add(m_StructSection = new BlackboardSection()
            {
                name = "structSection", title = "Struct"
            });
            m_Blackboard.Add(m_FieldsSection = new BlackboardSection()
            {
                name = "fieldsSection", title = "Fields"
            });

            m_StructNameField = new TextField("Name");
            m_StructNameField.RegisterValueChangedCallback(e =>
            {
                if (CurrentStruct.Name != e.newValue)
                {
                    CurrentStruct.Name = e.newValue;
                    SetModelDirty();
                }
            });

            m_StructSection.Add(m_StructNameField);

            m_PickStructTypeButton = new Button(() => PickStructType(CurrentStruct, SetStructType));
            var structTypeRow = new VisualElement {
                name = "structTypeRow"
            };
            structTypeRow.Add(new Label("Type"));
            structTypeRow.Add(m_PickStructTypeButton);
            m_StructSection.Add(structTypeRow);
            m_StructSection.Add(m_StructTypeLabel = new Label {
                name = "structTypeLabel"
            });

            m_FieldsSection.Q("sectionHeader").Add(new Button(() =>
            {
                FieldModel newField = CurrentStruct.Add(typeof(int), MakeUniqueFieldName("newField"));
                m_FieldsSection.Add(MakeFieldRow(newField));
                SetModelDirty();
            })
            {
                text = "+"
            });

            var bottomToolbar = new VisualElement {
                name = "bottomToolbar"
            };
            bottomToolbar.Add(m_SaveButton = new Button(Save)
            {
                text = "Save"
            });
            root.Add(bottomToolbar);

            // resume after domain reload
            if (!string.IsNullOrEmpty(m_CurrentPath) && File.Exists(m_CurrentPath))
            {
                LoadFromPath(m_CurrentPath);
            }
            else
            {
                Unload();
            }
        }