using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityEngine.UIElements; namespace DesignTools.Common { [Serializable] public class DesignToolItemPickerItem { public int Id; public string Name; public int IType; } /// /// 通用 Item 选择窗口 /// 支持按类型筛选、按 Id/名称搜索、分页浏览与回填选择结果 /// public class DesignToolItemPickerWindow : EditorWindow { private readonly List allItems = new List(); private readonly List allItemTypes = new List(); private readonly Dictionary itemTypeNames = new Dictionary(); private Vector2 scrollPosition; private string searchText = ""; private int selectedType = -1; private int currentItemId; private int currentPage; private const int ITEMS_PER_PAGE = 20; private Action onItemSelected; public static void ShowWindow( List items, List itemTypes, Dictionary typeNames, int currentType, int selectedItemId, Rect ownerWindowRect, Action onSelected) { DesignToolItemPickerWindow window = CreateInstance(); window.titleContent = new GUIContent("选择道具"); window.minSize = new Vector2(700, 520); window.allItems.Clear(); window.allItems.AddRange(items.OrderBy(x => x.IType).ThenBy(x => x.Id)); window.allItemTypes.Clear(); window.allItemTypes.AddRange(itemTypes); window.itemTypeNames.Clear(); foreach (KeyValuePair pair in typeNames) { window.itemTypeNames[pair.Key] = pair.Value; } window.selectedType = currentType; window.currentItemId = selectedItemId; window.onItemSelected = onSelected; window.position = GetCenteredRect(ownerWindowRect, window.minSize); window.ShowModalUtility(); } private static Rect GetCenteredRect(Rect ownerWindowRect, Vector2 windowSize) { float x = ownerWindowRect.x + (ownerWindowRect.width - windowSize.x) * 0.5f; float y = ownerWindowRect.y + (ownerWindowRect.height - windowSize.y) * 0.5f; return new Rect(x, y, windowSize.x, windowSize.y); } private void OnGUI() { DrawToolbar(); EditorGUILayout.Space(4); DrawList(); } private void DrawToolbar() { EditorGUILayout.BeginVertical("box"); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("搜索", GUILayout.Width(40)); string newSearchText = EditorGUILayout.TextField(searchText); if (newSearchText != searchText) { searchText = newSearchText; currentPage = 0; } if (GUILayout.Button("清空", GUILayout.Width(50))) { searchText = ""; GUI.FocusControl(null); currentPage = 0; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); List typeOptions = new List { "全部类型" }; typeOptions.AddRange(allItemTypes.Select(GetTypeDisplayName)); int selectedIndex = 0; if (selectedType >= 0) { int typeIndex = allItemTypes.IndexOf(selectedType); selectedIndex = typeIndex >= 0 ? typeIndex + 1 : 0; } int newIndex = EditorGUILayout.Popup("类型", selectedIndex, typeOptions.ToArray(),GUILayout.Width(420)); int newType = newIndex == 0 ? -1 : allItemTypes[newIndex - 1]; if (newType != selectedType) { selectedType = newType; currentPage = 0; } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); EditorGUILayout.HelpBox("棋子上的宝箱如果是两个,id奇数是未解锁的,偶数是已解锁的", MessageType.Info); EditorGUILayout.EndVertical(); } private void DrawList() { List filteredItems = allItems .Where(MatchFilter) .ToList(); int totalPages = Mathf.Max(1, Mathf.CeilToInt(filteredItems.Count / (float)ITEMS_PER_PAGE)); currentPage = Mathf.Clamp(currentPage, 0, totalPages - 1); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField($"共 {filteredItems.Count} 个道具", GUILayout.Width(120)); GUILayout.FlexibleSpace(); GUI.enabled = currentPage > 0; if (GUILayout.Button("<", GUILayout.Width(30))) { currentPage--; } GUI.enabled = currentPage < totalPages - 1; if (GUILayout.Button(">", GUILayout.Width(30))) { currentPage++; } GUI.enabled = true; EditorGUILayout.LabelField($"第 {currentPage + 1}/{totalPages} 页", GUILayout.Width(90)); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(4); scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); IEnumerable pageItems = filteredItems .Skip(currentPage * ITEMS_PER_PAGE) .Take(ITEMS_PER_PAGE); foreach (DesignToolItemPickerItem item in pageItems) { DrawItemRow(item); } EditorGUILayout.EndScrollView(); } private void DrawItemRow(DesignToolItemPickerItem item) { bool isCurrent = item.Id == currentItemId; GUI.backgroundColor = isCurrent ? new Color(0.8f, 1f, 0.8f) : Color.white; EditorGUILayout.BeginVertical("box"); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(item.Id.ToString(), GUILayout.Width(70)); EditorGUILayout.LabelField(item.Name, GUILayout.Width(280)); EditorGUILayout.LabelField(GetTypeDisplayName(item.IType), GUILayout.Width(160)); GUILayout.FlexibleSpace(); if (GUILayout.Button("选择", GUILayout.Width(60))) { onItemSelected?.Invoke(item.Id); Close(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); GUI.backgroundColor = Color.white; } private bool MatchFilter(DesignToolItemPickerItem item) { if (selectedType >= 0 && item.IType != selectedType) { return false; } if (string.IsNullOrWhiteSpace(searchText)) { return true; } return item.Id.ToString().Contains(searchText, StringComparison.OrdinalIgnoreCase) || (!string.IsNullOrEmpty(item.Name) && item.Name.Contains(searchText, StringComparison.OrdinalIgnoreCase)); } private string GetTypeDisplayName(int itemType) { return itemTypeNames.TryGetValue(itemType, out string typeName) ? $"{typeName} ({itemType})" : $"类型 {itemType}"; } } }