using System; using Unity.VisualScripting.ReorderableList; using UnityEditor; using UnityEngine; namespace Unity.VisualScripting { public abstract class MetadataCollectionAdaptor : IReorderableListAdaptor { protected MetadataCollectionAdaptor(Metadata metadata, Inspector parentInspector) { if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (parentInspector == null) { throw new ArgumentNullException(nameof(parentInspector)); } this.metadata = metadata; this.parentInspector = parentInspector; var wideAttribute = metadata.GetAttribute(); if (wideAttribute != null) { widthMode = wideAttribute.toEdge ? WidthMode.Edge : WidthMode.Wide; } else { widthMode = WidthMode.Thin; } listControl = new ReorderableListControl(); listControl.ContainerStyle = new GUIStyle(ReorderableListStyles.Container); listControl.FooterButtonStyle = new GUIStyle(ReorderableListStyles.FooterButton); listControl.ItemButtonStyle = new GUIStyle(ReorderableListStyles.ItemButton); listControl.ItemRemoving += ListControlOnItemRemoving; } private void ListControlOnItemRemoving(object sender, ItemRemovingEventArgs args) { var warnAttribute = metadata.GetAttribute(); if (warnAttribute != null) { args.Cancel = !EditorUtility.DisplayDialog(warnAttribute.warningTitle, warnAttribute.warningMessage, "Remove", "Cancel"); } } private float itemWidth; private WidthMode widthMode; private Metadata metadata; private ReorderableListControl listControl; protected Inspector parentInspector { get; private set; } private enum WidthMode { Thin, Wide, Edge } #region Drawing public virtual void BeginGUI() { } public virtual void EndGUI() { } public virtual void DrawItemBackground(Rect position, int index) { } protected virtual float GetTitleHeight(float width, GUIContent title) { if (title == GUIContent.none) { return 0; } return 20; } protected virtual void OnTitleGUI(Rect position, GUIContent title) { if (title == GUIContent.none) { return; } ReorderableListGUI.Title(position, title); } public float GetItemHeight(int index) { return GetItemHeight(itemWidth, index); } public abstract float GetItemHeight(float width, int index); public abstract void DrawItem(Rect position, int index); public abstract float GetItemAdaptiveWidth(int index); public float GetAdaptiveWidth() { var width = 0f; for (int i = 0; i < Count; i++) { width = Mathf.Max(width, GetItemAdaptiveWidth(i)); } width += 56; return width; } public float GetHeight(float width, GUIContent label) { if (widthMode == WidthMode.Thin) { width = Inspector.WidthWithoutLabel(metadata, width, label); } else if (widthMode == WidthMode.Edge) { width = LudiqGUIUtility.currentInspectorWidthWithoutScrollbar; } itemWidth = width - 52; // Approximation of handle + remove button var height = 0f; if (widthMode != WidthMode.Thin && label != GUIContent.none) { height += GetTitleHeight(width, label); } height += listControl.CalculateListHeight(this); height -= 10; // Remove default bottom padding if (widthMode == WidthMode.Thin) { height = Inspector.HeightWithLabel(metadata, width, height, label); } return height; } public bool Field(Rect position, GUIContent label) { var y = position.y; if (widthMode == WidthMode.Thin) { position = Inspector.BeginLabeledBlock(metadata, position, label); } else { if (widthMode == WidthMode.Edge) { position.x = 0; position.width = LudiqGUIUtility.currentInspectorWidthWithoutScrollbar; } Inspector.BeginLabeledBlock(metadata, position, GUIContent.none); } position.height += 10; // Restore default padding itemWidth = position.width - 52; var height = position.height; if (widthMode != WidthMode.Thin && label != GUIContent.none) { var titlePosition = new Rect ( position.x, y, position.width, GetTitleHeight(position.width, label) ); OnTitleGUI(titlePosition, label); y += titlePosition.height - 1; height -= titlePosition.height; } else { height = listControl.CalculateListHeight(this); } var listPosition = new Rect ( position.x, y, position.width, height ); listControl.Draw(listPosition, this); return Inspector.EndBlock(metadata); } #endregion #region Manipulation public abstract int Count { get; } public abstract bool CanDrag(int index); public abstract bool CanRemove(int index); public abstract void Add(); public abstract void Insert(int index); public abstract void Duplicate(int index); public abstract void Remove(int index); public abstract void Move(int sourceIndex, int destIndex); public abstract void Clear(); #endregion } }