/**************************************************** 文件:TableView.cs 作者:陶长春 邮箱:376248129@qq.com 日期:2024年12月12日 8:25:50 UnityVersion: 2021.3.13f1 功能:表格绘制 *****************************************************/ using System.Collections; using UnityEngine; using System.Collections.Generic; using UnityEditor.IMGUI.Controls; using UnityEditor; namespace TFramework { public 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 TAction> OnSelectionChanged; /// /// 搜索数据时的方法 /// public TFunc OnSearch; /// /// 添加右键单击上下文菜单项 /// public TAction AddContextMenu; /// /// 行高度 /// 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; /// /// 绘制搜索框 /// /// "arg0"是整个表格的矩形 public TFunc DrawSearch; /// /// 是否启用筛选 /// public bool IsEnableFiltrate { get; set; } = false; public List> Items => _items; /// /// 筛选时执行的方法 /// public TFunc OnFiltrte; /// /// 表格视图 /// /// 表格数据 /// 列标题数据 /// 自定义列标题 /// 是否显示换序行号 public TableView(List datas, List> columns, TableColumnHeader columnHeader = null,bool isShowIndex=true) : base(new TreeViewState()) { showAlternatingRowBackgrounds = true; showBorder = true; rowHeight = EditorGUIUtility.singleLineHeight + 4; if (isShowIndex) columns.Insert(0, GetIndexColumn()); if (columnHeader == null) multiColumnHeader = new TableColumnHeader(new MultiColumnHeaderState(columns.ToArray())); else multiColumnHeader = columnHeader; 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(); } /// /// 当列激活状态改变 /// private void OnVisibleColumnsChanged(MultiColumnHeader multiColumnHeader) { Reload(); } /// /// 当重新排序 /// private void OnSortingChanged(MultiColumnHeader multiColumnHeader) { 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 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) => { if (GUI.Button(new Rect(rect.x, rect.y, 14, rect.height), new GUIContent() { text = "▲", tooltip = "上移" }, EditorStyles.miniButtonRight)) { MoveDataIndex(data, 1); } if (GUI.Button(new Rect(rect.x + 15, rect.y, 14, rect.height), new GUIContent() { text = "▼", tooltip = "下移" }, EditorStyles.miniButtonRight)) { MoveDataIndex(data, 0); } EditorGUI.LabelField(new Rect(rect.x + 30, rect.y, rect.width - 30, rect.height), rowIndex.ToString()); }; return column; } /// /// 构造根节点 /// 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)) { if (_items[i].parent != null && _items[i].parent.id != -1 && !IsExpanded(_items[i].parent.id)) continue; _drawItems.Add(_items[i]); } } } else if (IsEnableFiltrate && OnFiltrte != null) { for (int i = 0; i < _items.Count; i++) { if (OnFiltrte(_items[i].Data)) { if (_items[i].parent != null && _items[i].parent.id != -1 && !IsExpanded(_items[i].parent.id)) continue; _drawItems.Add(_items[i]); } } } else { for (int i = 0; i < _items.Count; i++) { if (_items[i].parent != null && _items[i].parent.id != -1 && !IsExpanded(_items[i].parent.id)) continue; _drawItems.Add(_items[i]); } } SetupDepthsFromParentsAndChildren(root); return _drawItems; } /// /// 绘制行 /// protected override void RowGUI(RowGUIArgs args) { TableViewItem item = args.item as TableViewItem; if (item.parent!=null && !IsExpanded(item.parent.id)&&item.parent.id!=-1) return; 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; if (item.hasChildren&&i==0) { cellRect.x += 13; cellRect.width -= 13; } if (item.parent != null&&item.parent.id!=-1&&i==0) { cellRect.x += 13 + 3 * item.depth+13* item.parent.depth; cellRect.width -= 13 + 3 * item.depth + 13 * item.parent.depth; } 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); } GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("增加一行"), false, () => { AddData(new T()); }); if (selectedItems.Count == 1) { menu.AddItem(new GUIContent("添加子行"), false, () => { AddChliderData(selectedItems[0]); }); } if (selectedItems.Count > 0) { menu.AddItem(new GUIContent("删除选中行"), false, () => { DeleteDatas(selectedItems); }); } menu.AddSeparator(""); menu.AddItem(new GUIContent("删除所有行"), false, () => { ClearData(); }); AddContextMenu?.Invoke(menu); 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); if (DrawSearch != null) { sub = DrawSearch.Invoke(rect); } else { EditorGUI.LabelField(sub, "Search: "); sub.Set(rect.x + 60, rect.y, rect.width - 60, 18); } searchString = _searchField.OnGUI(sub, searchString); rect.y += sub.height; rect.height -= sub.height; base.OnGUI(rect); } else { base.OnGUI(rect); } } /// /// 添加数据 /// /// 数据 public void AddData(T data) { if (_datas.Contains(data)) return; _datas.Add(data); _items.Add(new TableViewItem(_idSign, 0, data)); _idSign += 1; Reload(); } /// /// 添加子数据 /// /// private void AddChliderData(TableViewItem selectedItem) { T data = new T(); _datas.Add(data); TableViewItem item = new TableViewItem(_idSign, selectedItem.depth+1, data); item.parent = selectedItem; item.parent.id = selectedItem.id; selectedItem.AddChild(item); _items.Add(item); _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) { if (item.parent != null) { item.parent.children.Remove(item); item.parent = null; } if (item.hasChildren) { for (int j = 0; j < item.children.Count; j++) { TableViewItem viewItem = item.children[j] as TableViewItem; DeleteData(viewItem.Data); } } _items.Remove(item); } Reload(); } /// /// 删除数据 /// /// 数据 public void DeleteDatas(List> datas) { for (int i = 0; i < datas.Count; i++) { T data = datas[i].Data; if (!_datas.Contains(data)) continue; DeleteData(data); //_datas.Remove(data); //TableViewItem item = _items.Find((t) => { return t.Data == data; }); //if (item != null) //{ // if (item.parent != null) // { // item.parent.children.Remove(item); // item.parent = null; // } // if (item.hasChildren) // { // for (int j = 0; j < item.children.Count; j++) // { // TableViewItem viewItem = item.children[j] as TableViewItem; // DeleteData(viewItem.Data); // } // } // _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(); } /// /// 移动数据位置 /// /// 数据 /// 上移:1,下移:0 public void MoveDataIndex(T data, int AorS) { if (!_datas.Contains(data)) return; TableViewItem item = _items.Find((i) => { return i.Data == data; }); if (AorS == 0) { if (_datas.IndexOf(data) + 1 >= _datas.Count) return; _datas.Swap(_datas.IndexOf(data), _datas.IndexOf(data) + 1); if (item != null && _items.IndexOf(item) + 1 < _items.Count) { _items.Swap(_items.IndexOf(item), _items.IndexOf(item) + 1); } } else { if (_datas.IndexOf(data) - 1 < 0) return; _datas.Swap(_datas.IndexOf(data), _datas.IndexOf(data) - 1); if (item != null && _items.IndexOf(item) - 1 >= 0) { _items.Swap(_items.IndexOf(item), _items.IndexOf(item) - 1); } } Reload(); } } }