using System; using System.Collections.Generic; using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEngine; namespace AlicizaX.EditorExtension.Editor { /// /// 表格视图 /// /// 数据类型 public sealed class TableView : TreeView where T : class, new() { /// /// 表格数据 /// private List _datas; /// /// 当前选择的表格数据 /// private List _selectionDatas; /// /// 根元素 /// private TableViewItem _rootItem; /// /// 所有的元素 /// private List> _items; /// /// 所有的元素绘制项 /// private List _drawItems; /// /// 搜索控件 /// private SearchField _searchField; /// /// 元素ID标记 /// private int _idSign = 0; /// /// 当选择项改变 /// public event Action> OnSelectionChanged; /// /// 搜索数据时的方法 /// public Func OnSearch; /// /// 行高度 /// public float RowHeight { get { return rowHeight; } set { rowHeight = value; } } /// /// 是否启用上下文右键点击 /// public bool IsEnableContextClick { get; set; } = true; /// /// 是否允许多选 /// public bool IsCanMultiSelect { get; set; } = true; /// /// 是否启用搜索框 /// public bool IsEnableSearch { get; set; } = false; /// /// 表格视图 /// /// 表格视图数据 /// 表格视图的所有列 public TableView(List datas, List> columns) : base(new TreeViewState()) { showAlternatingRowBackgrounds = true; showBorder = true; rowHeight = EditorGUIUtility.singleLineHeight + 4; columns.Insert(0, GetIndexColumn()); multiColumnHeader = new MultiColumnHeader(new MultiColumnHeaderState(columns.ToArray())); multiColumnHeader.sortingChanged += OnSortingChanged; multiColumnHeader.visibleColumnsChanged += OnVisibleColumnsChanged; _datas = datas; _selectionDatas = new List(); _rootItem = new TableViewItem(-1, -1, null); _items = new List>(); for (var i = 0; i < _datas.Count; i++) { _items.Add(new TableViewItem(_idSign, 0, _datas[i])); _idSign += 1; } _drawItems = new List(); _searchField = new SearchField(); Reload(); } /// /// 构造根节点 /// protected override TreeViewItem BuildRoot() { return _rootItem; } /// /// 构造所有行 /// protected override IList BuildRows(TreeViewItem root) { _drawItems.Clear(); if (hasSearch && OnSearch != null) { for (int i = 0; i < _items.Count; i++) { if (OnSearch(_items[i].Data, searchString)) { _drawItems.Add(_items[i]); } } } else { for (int i = 0; i < _items.Count; i++) { _drawItems.Add(_items[i]); } } return _drawItems; } /// /// 绘制行 /// protected override void RowGUI(RowGUIArgs args) { TableViewItem item = args.item as TableViewItem; int visibleColumns = args.GetNumVisibleColumns(); for (var i = 0; i < visibleColumns; i++) { Rect cellRect = args.GetCellRect(i); int index = args.GetColumn(i); CenterRectUsingSingleLineHeight(ref cellRect); TableColumn column = multiColumnHeader.GetColumn(index) as TableColumn; column.DrawCell?.Invoke(cellRect, item.Data, args.row, args.selected, args.focused); } } /// /// 上下文右键点击 /// protected override void ContextClicked() { if (!IsEnableContextClick) return; List selectedItems = new List(); foreach (var itemID in GetSelection()) { TableViewItem item = _items.Find((it) => { return it.id == itemID; }); if (item != null) selectedItems.Add(item.Data); } GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Add row"), false, () => { AddData(new T()); }); if (selectedItems.Count > 0) { menu.AddItem(new GUIContent("Delete selected rows"), false, () => { DeleteDatas(selectedItems); }); } menu.AddSeparator(""); menu.AddItem(new GUIContent("Clear rows"), false, () => { ClearData(); }); menu.ShowAsContext(); } /// /// 当选择项改变 /// protected override void SelectionChanged(IList selectedIds) { base.SelectionChanged(selectedIds); _selectionDatas.Clear(); foreach (var itemID in selectedIds) { TableViewItem item = _items.Find((it) => { return it.id == itemID; }); if (item != null) _selectionDatas.Add(item.Data); } OnSelectionChanged?.Invoke(_selectionDatas); } /// /// 是否允许多选 /// protected override bool CanMultiSelect(TreeViewItem item) { return IsCanMultiSelect; } /// /// 绘制表格视图 /// /// 绘制区域 public override void OnGUI(Rect rect) { if (IsEnableSearch) { Rect sub = new Rect(rect.x, rect.y, 60, 16); EditorGUI.LabelField(sub, "Search: "); sub.Set(rect.x + 60, rect.y, rect.width - 60, 18); searchString = _searchField.OnGUI(sub, searchString); rect.y += 18; rect.height -= 18; base.OnGUI(rect); } else { base.OnGUI(rect); } } /// /// 获取索引列 /// private TableColumn GetIndexColumn() { TableColumn column = new TableColumn(); column.autoResize = false; column.headerContent = new GUIContent("Index"); column.width = 50; column.canSort = false; column.Compare = null; column.DrawCell = (rect, data, rowIndex, isSelected, isFocused) => { EditorGUI.LabelField(rect, rowIndex.ToString()); }; return column; } /// /// 当重新排序 /// private void OnSortingChanged(MultiColumnHeader columnheader) { bool isAscending = multiColumnHeader.IsSortedAscending(multiColumnHeader.sortedColumnIndex); TableColumn column = multiColumnHeader.GetColumn(multiColumnHeader.sortedColumnIndex) as TableColumn; if (column.Compare != null) { _items.Sort((a, b) => { if (isAscending) { return -column.Compare(a.Data, b.Data); } else { return column.Compare(a.Data, b.Data); } }); Reload(); } } /// /// 当列激活状态改变 /// private void OnVisibleColumnsChanged(MultiColumnHeader columnheader) { Reload(); } /// /// 添加数据 /// /// 数据 public void AddData(T data) { if (_datas.Contains(data)) return; _datas.Add(data); _items.Add(new TableViewItem(_idSign, 0, data)); _idSign += 1; Reload(); } /// /// 添加数据 /// /// 数据 public void AddDatas(List datas) { for (int i = 0; i < datas.Count; i++) { T data = datas[i]; if (_datas.Contains(data)) continue; _datas.Add(data); _items.Add(new TableViewItem(_idSign, 0, data)); _idSign += 1; } Reload(); } /// /// 删除数据 /// /// 数据 public void DeleteData(T data) { if (!_datas.Contains(data)) return; _datas.Remove(data); TableViewItem item = _items.Find((i) => { return i.Data == data; }); if (item != null) { _items.Remove(item); } Reload(); } /// /// 删除数据 /// /// 数据 public void DeleteDatas(List datas) { for (int i = 0; i < datas.Count; i++) { T data = datas[i]; if (!_datas.Contains(data)) continue; _datas.Remove(data); TableViewItem item = _items.Find((t) => { return t.Data == data; }); if (item != null) { _items.Remove(item); } } Reload(); } /// /// 选中数据 /// /// 数据 public void SelectData(T data) { if (!_datas.Contains(data)) return; TableViewItem item = _items.Find((i) => { return i.Data == data; }); if (item != null) { SetSelection(new int[] { item.id }); } } /// /// 选中数据 /// /// 数据 /// 选中的操作 public void SelectData(T data, TreeViewSelectionOptions options) { if (!_datas.Contains(data)) return; TableViewItem item = _items.Find((i) => { return i.Data == data; }); if (item != null) { SetSelection(new int[] { item.id }, options); } } /// /// 选中数据 /// /// 数据 public void SelectDatas(List datas) { List ids = new List(); for (int i = 0; i < datas.Count; i++) { T data = datas[i]; if (!_datas.Contains(data)) continue; TableViewItem item = _items.Find((t) => { return t.Data == data; }); if (item != null) { ids.Add(item.id); } } if (ids.Count > 0) { SetSelection(ids); } } /// /// 选中数据 /// /// 数据 /// 选中的操作 public void SelectDatas(List datas, TreeViewSelectionOptions options) { List ids = new List(); for (int i = 0; i < datas.Count; i++) { T data = datas[i]; if (!_datas.Contains(data)) continue; TableViewItem item = _items.Find((t) => { return t.Data == data; }); if (item != null) { ids.Add(item.id); } } if (ids.Count > 0) { SetSelection(ids, options); } } /// /// 清空所有数据 /// public void ClearData() { _datas.Clear(); _items.Clear(); Reload(); } } }