using System.Collections.Generic; using AlicizaX.Editor; using UnityEditor; using UnityEditor.Callbacks; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; namespace AlicizaX { public sealed class PoolConfigEditorWindow : EditorWindow { private const float MinLeftWidth = 240f; private const float InitialLeftWidth = 300f; private const int ListItemHeight = 46; private const string WindowTitle = "Pool Config Editor"; private static readonly Color LeftPanelColor = new Color(0.22f, 0.22f, 0.22f, 1f); private static readonly Color RightPanelColor = new Color(0.16f, 0.16f, 0.16f, 1f); private PoolConfigScriptableObject _asset; private SerializedObject _serializedObject; private SerializedProperty _entriesProperty; private readonly List _entryIndices = new List(); private int _selectedIndex; private bool _hasUnsavedChanges; private ToolbarButton _saveButton; private Label _titleLabel; private VisualElement _leftPane; private ListView _listView; private ScrollView _detailScrollView; private Label _detailTitleLabel; private VisualElement _detailFieldsContainer; private VisualElement _emptyContainer; [MenuItem("AlicizaX/GameObjectPool/Open PoolConfig Editor")] public static void OpenWindow() { Open(Selection.activeObject as PoolConfigScriptableObject); } public static void Open(PoolConfigScriptableObject asset) { PoolConfigEditorWindow window = GetWindow(false, WindowTitle, true); window.minSize = new Vector2(920f, 560f); window.SetAsset(asset); window.Show(); } [OnOpenAsset(0)] private static bool OnOpenAsset(int instanceId, int line) { Object obj = EditorUtility.InstanceIDToObject(instanceId); if (obj is not PoolConfigScriptableObject asset) { return false; } Open(asset); return true; } private void CreateGUI() { titleContent = new GUIContent(WindowTitle, EditorGUIUtility.IconContent("ScriptableObject Icon").image); BuildUi(); if (_asset == null && Selection.activeObject is PoolConfigScriptableObject selectedAsset) { SetAsset(selectedAsset); } else { RefreshUi(); } } private void OnEnable() { titleContent = new GUIContent(WindowTitle, EditorGUIUtility.IconContent("ScriptableObject Icon").image); if (rootVisualElement.childCount == 0) { BuildUi(); } if (_asset == null && Selection.activeObject is PoolConfigScriptableObject selectedAsset) { SetAsset(selectedAsset); } else { RefreshUi(); } } private void OnSelectionChange() { if (Selection.activeObject is PoolConfigScriptableObject selectedAsset && selectedAsset != _asset) { SetAsset(selectedAsset); } } private void BuildUi() { rootVisualElement.Clear(); rootVisualElement.style.flexDirection = FlexDirection.Column; Toolbar toolbar = new Toolbar(); toolbar.style.flexShrink = 0f; _saveButton = new ToolbarButton(SaveAsset) { tooltip = "Save PoolConfig" }; _saveButton.Add(new Image { image = EditorGUIUtility.IconContent("SaveActive").image, scaleMode = ScaleMode.ScaleToFit }); _titleLabel = new Label(); _titleLabel.style.unityFontStyleAndWeight = FontStyle.Bold; _titleLabel.style.flexGrow = 1f; _titleLabel.style.marginLeft = 6f; _titleLabel.style.unityTextAlign = TextAnchor.MiddleLeft; toolbar.Add(_saveButton); toolbar.Add(_titleLabel); rootVisualElement.Add(toolbar); TwoPaneSplitView splitView = new TwoPaneSplitView(0, InitialLeftWidth, TwoPaneSplitViewOrientation.Horizontal); splitView.style.flexGrow = 1f; rootVisualElement.Add(splitView); _leftPane = new VisualElement(); _leftPane.style.flexGrow = 1f; _leftPane.style.minWidth = MinLeftWidth; _leftPane.style.backgroundColor = LeftPanelColor; _leftPane.style.paddingLeft = 4f; _leftPane.style.paddingRight = 4f; _leftPane.style.paddingTop = 4f; _leftPane.style.paddingBottom = 4f; VisualElement rightPane = new VisualElement(); rightPane.style.flexGrow = 1f; rightPane.style.backgroundColor = RightPanelColor; rightPane.style.paddingLeft = 10f; rightPane.style.paddingRight = 10f; rightPane.style.paddingTop = 8f; rightPane.style.paddingBottom = 8f; splitView.Add(_leftPane); splitView.Add(rightPane); BuildLeftPane(); BuildRightPane(rightPane); } private void BuildLeftPane() { _listView = new ListView { selectionType = SelectionType.Single, virtualizationMethod = CollectionVirtualizationMethod.FixedHeight, reorderable = false, showBorder = false, showAlternatingRowBackgrounds = AlternatingRowBackground.None, style = { flexGrow = 1f, marginBottom = 4f }, fixedItemHeight = ListItemHeight }; _listView.makeItem = MakeListItem; _listView.bindItem = BindListItem; _listView.selectionChanged += _ => OnListSelectionChanged(); _leftPane.Add(_listView); VisualElement footer = new VisualElement(); footer.style.flexDirection = FlexDirection.Row; footer.style.justifyContent = Justify.Center; footer.style.alignItems = Align.Center; footer.style.flexShrink = 0f; footer.style.height = 28f; Button addButton = new Button(AddEntry) { tooltip = "Add Item" }; addButton.style.width = 24f; addButton.style.height = 20f; addButton.style.marginRight = 4f; addButton.Add(new Image { image = EditorUtils.Styles.PlusIcon.image, scaleMode = ScaleMode.ScaleToFit }); Button removeButton = new Button(RemoveEntry) { tooltip = "Remove Item", name = "remove-button" }; removeButton.style.width = 24f; removeButton.style.height = 20f; removeButton.Add(new Image { image = EditorUtils.Styles.MinusIcon.image, scaleMode = ScaleMode.ScaleToFit }); removeButton.SetEnabled(false); footer.Add(addButton); footer.Add(removeButton); _leftPane.Add(footer); } private void BuildRightPane(VisualElement rightPane) { _emptyContainer = new VisualElement { style = { flexGrow = 1f, justifyContent = Justify.Center } }; _emptyContainer.Add(new HelpBox("No entry selected.", HelpBoxMessageType.Info)); _detailScrollView = new ScrollView { style = { flexGrow = 1f } }; _detailTitleLabel = new Label(); _detailTitleLabel.style.unityFontStyleAndWeight = FontStyle.Bold; _detailTitleLabel.style.marginBottom = 6f; _detailTitleLabel.style.unityTextAlign = TextAnchor.MiddleLeft; _detailFieldsContainer = new VisualElement(); _detailFieldsContainer.style.flexDirection = FlexDirection.Column; _detailFieldsContainer.style.flexGrow = 1f; _detailScrollView.Add(_detailTitleLabel); _detailScrollView.Add(_detailFieldsContainer); rightPane.Add(_emptyContainer); rightPane.Add(_detailScrollView); } private VisualElement MakeListItem() { VisualElement root = new VisualElement(); root.style.height = ListItemHeight; root.style.flexDirection = FlexDirection.Column; root.style.justifyContent = Justify.Center; root.style.paddingLeft = 8f; root.style.paddingRight = 8f; root.style.paddingTop = 6f; root.style.paddingBottom = 6f; root.style.marginBottom = 2f; Label primary = new Label { name = "primary" }; primary.style.unityTextAlign = TextAnchor.MiddleLeft; Label secondary = new Label { name = "secondary" }; secondary.style.unityTextAlign = TextAnchor.MiddleLeft; secondary.style.fontSize = 11f; secondary.style.color = new Color(0.72f, 0.72f, 0.72f, 1f); root.Add(primary); root.Add(secondary); return root; } private void BindListItem(VisualElement element, int index) { SerializedProperty entry = GetEntryAt(index); element.Q