123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- /****************************************************
- 文件: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<T> : TreeView where T : class, new()
- {
- /// <summary>
- /// 表格数据
- /// </summary>
- private List<T> _datas;
- /// <summary>
- /// 当前选择的表格数据
- /// </summary>
- private List<T> _selectionDatas;
- /// <summary>
- /// 根元素
- /// </summary>
- private TableViewItem<T> _rootItem;
- /// <summary>
- /// 所有的元素
- /// </summary>
- private List<TableViewItem<T>> _items;
- /// <summary>
- /// 所有的元素绘制项
- /// </summary>
- private List<TreeViewItem> _drawItems;
- /// <summary>
- /// 搜索控件
- /// </summary>
- private SearchField _searchField;
- /// <summary>
- /// 元素ID标记
- /// </summary>
- private int _idSign = 0;
- /// <summary>
- /// 当选择项改变
- /// </summary>
- public event TAction<List<T>> OnSelectionChanged;
- /// <summary>
- /// 搜索数据时的方法
- /// </summary>
- public TFunc<T, string, bool> OnSearch;
- /// <summary>
- /// 添加右键单击上下文菜单项
- /// </summary>
- public TAction<GenericMenu> AddContextMenu;
- /// <summary>
- /// 行高度
- /// </summary>
- public float RowHeight
- {
- get
- {
- return rowHeight;
- }
- set
- {
- rowHeight = value;
- }
- }
- /// <summary>
- /// 是否启用上下文右键点击
- /// </summary>
- public bool IsEnableContextClick { get; set; } = true;
- /// <summary>
- /// 是否允许多选
- /// </summary>
- public bool IsCanMultiSelect { get; set; } = true;
- /// <summary>
- /// 是否启用搜索框
- /// </summary>
- public bool IsEnableSearch { get; set; } = false;
- /// <summary>
- /// 绘制搜索框
- /// </summary>
- /// <param>"arg0"是整个表格的矩形</param>
- public TFunc<Rect, Rect> DrawSearch;
- /// <summary>
- /// 是否启用筛选
- /// </summary>
- public bool IsEnableFiltrate { get; set; } = false;
- public List<TableViewItem<T>> Items => _items;
- /// <summary>
- /// 筛选时执行的方法
- /// </summary>
- public TFunc<T, bool> OnFiltrte;
- /// <summary>
- /// 表格视图
- /// </summary>
- /// <param name="datas">表格数据</param>
- /// <param name="columns">列标题数据</param>
- /// <param name="columnHeader">自定义列标题</param>
- /// <param name="isShowIndex">是否显示换序行号</param>
- public TableView(List<T> datas, List<TableColumn<T>> columns, TableColumnHeader<T> 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<T>(new MultiColumnHeaderState(columns.ToArray()));
- else
- multiColumnHeader = columnHeader;
- multiColumnHeader.sortingChanged += OnSortingChanged;
- multiColumnHeader.visibleColumnsChanged += OnVisibleColumnsChanged;
- _datas = datas;
- _selectionDatas = new List<T>();
- _rootItem = new TableViewItem<T>(-1, -1, null);
- _items = new List<TableViewItem<T>>();
- for (var i = 0; i < _datas.Count; i++)
- {
- _items.Add(new TableViewItem<T>(_idSign, 0, _datas[i]));
- _idSign += 1;
- }
- _drawItems = new List<TreeViewItem>();
- _searchField = new SearchField();
- Reload();
- }
- /// <summary>
- /// 当列激活状态改变
- /// </summary>
- private void OnVisibleColumnsChanged(MultiColumnHeader multiColumnHeader)
- {
- Reload();
- }
- /// <summary>
- /// 当重新排序
- /// </summary>
- private void OnSortingChanged(MultiColumnHeader multiColumnHeader)
- {
- bool isAscending = multiColumnHeader.IsSortedAscending(multiColumnHeader.sortedColumnIndex);
- TableColumn<T> column = multiColumnHeader.GetColumn(multiColumnHeader.sortedColumnIndex) as TableColumn<T>;
- 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();
- }
- }
- /// <summary>
- /// 获取项索引
- /// </summary>
- /// <returns></returns>
- private TableColumn<T> GetIndexColumn()
- {
- TableColumn<T> column = new TableColumn<T>();
- 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;
- }
- /// <summary>
- /// 构造根节点
- /// </summary>
- protected override TreeViewItem BuildRoot()
- {
- return _rootItem;
- }
- /// <summary>
- /// 构造所有行
- /// </summary>
- protected override IList<TreeViewItem> 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;
- }
- /// <summary>
- /// 绘制行
- /// </summary>
- protected override void RowGUI(RowGUIArgs args)
- {
- TableViewItem<T> item = args.item as TableViewItem<T>;
- 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<T> column = multiColumnHeader.GetColumn(index) as TableColumn<T>;
- 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);
- }
- }
- /// <summary>
- /// 上下文右键点击
- /// </summary>
- protected override void ContextClicked()
- {
- if (!IsEnableContextClick)
- return;
- List<TableViewItem<T>> selectedItems = new List<TableViewItem<T>>();
- foreach (var itemID in GetSelection())
- {
- TableViewItem<T> 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();
- }
- /// <summary>
- /// 当选择项改变
- /// </summary>
- protected override void SelectionChanged(IList<int> selectedIds)
- {
- base.SelectionChanged(selectedIds);
- _selectionDatas.Clear();
- foreach (var itemID in selectedIds)
- {
- TableViewItem<T> item = _items.Find((it) => { return it.id == itemID; });
- if (item != null) _selectionDatas.Add(item.Data);
- }
- OnSelectionChanged?.Invoke(_selectionDatas);
- }
- /// <summary>
- /// 是否允许多选
- /// </summary>
- protected override bool CanMultiSelect(TreeViewItem item)
- {
- return IsCanMultiSelect;
- }
- /// <summary>
- /// 绘制表格视图
- /// </summary>
- /// <param name="rect">绘制区域</param>
- 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);
- }
- }
- /// <summary>
- /// 添加数据
- /// </summary>
- /// <param name="data">数据</param>
- public void AddData(T data)
- {
- if (_datas.Contains(data))
- return;
- _datas.Add(data);
- _items.Add(new TableViewItem<T>(_idSign, 0, data));
- _idSign += 1;
- Reload();
- }
- /// <summary>
- /// 添加子数据
- /// </summary>
- /// <param name="selectedItems"></param>
- private void AddChliderData(TableViewItem<T> selectedItem)
- {
- T data = new T();
- _datas.Add(data);
- TableViewItem<T> item = new TableViewItem<T>(_idSign, selectedItem.depth+1, data);
- item.parent = selectedItem;
- item.parent.id = selectedItem.id;
- selectedItem.AddChild(item);
- _items.Add(item);
- _idSign += 1;
- Reload();
- }
- /// <summary>
- /// 添加数据
- /// </summary>
- /// <param name="datas">数据</param>
- public void AddDatas(List<T> 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<T>(_idSign, 0, data));
- _idSign += 1;
- }
- Reload();
- }
- /// <summary>
- /// 删除数据
- /// </summary>
- /// <param name="data">数据</param>
- public void DeleteData(T data)
- {
- if (!_datas.Contains(data))
- return;
- _datas.Remove(data);
- TableViewItem<T> 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<T> viewItem = item.children[j] as TableViewItem<T>;
- DeleteData(viewItem.Data);
- }
- }
- _items.Remove(item);
- }
- Reload();
- }
- /// <summary>
- /// 删除数据
- /// </summary>
- /// <param name="datas">数据</param>
- public void DeleteDatas(List<TableViewItem<T>> 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<T> 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<T> viewItem = item.children[j] as TableViewItem<T>;
- // DeleteData(viewItem.Data);
- // }
- // }
- // _items.Remove(item);
- //}
- }
- //Reload();
- }
- /// <summary>
- /// 选中数据
- /// </summary>
- /// <param name="data">数据</param>
- public void SelectData(T data)
- {
- if (!_datas.Contains(data))
- return;
- TableViewItem<T> item = _items.Find((i) => { return i.Data == data; });
- if (item != null)
- {
- SetSelection(new int[] { item.id });
- }
- }
- /// <summary>
- /// 选中数据
- /// </summary>
- /// <param name="data">数据</param>
- /// <param name="options">选中的操作</param>
- public void SelectData(T data, TreeViewSelectionOptions options)
- {
- if (!_datas.Contains(data))
- return;
- TableViewItem<T> item = _items.Find((i) => { return i.Data == data; });
- if (item != null)
- {
- SetSelection(new int[] { item.id }, options);
- }
- }
- /// <summary>
- /// 选中数据
- /// </summary>
- /// <param name="datas">数据</param>
- public void SelectDatas(List<T> datas)
- {
- List<int> ids = new List<int>();
- for (int i = 0; i < datas.Count; i++)
- {
- T data = datas[i];
- if (!_datas.Contains(data))
- continue;
- TableViewItem<T> item = _items.Find((t) => { return t.Data == data; });
- if (item != null)
- {
- ids.Add(item.id);
- }
- }
- if (ids.Count > 0)
- {
- SetSelection(ids);
- }
- }
- /// <summary>
- /// 选中数据
- /// </summary>
- /// <param name="datas">数据</param>
- /// <param name="options">选中的操作</param>
- public void SelectDatas(List<T> datas, TreeViewSelectionOptions options)
- {
- List<int> ids = new List<int>();
- for (int i = 0; i < datas.Count; i++)
- {
- T data = datas[i];
- if (!_datas.Contains(data))
- continue;
- TableViewItem<T> item = _items.Find((t) => { return t.Data == data; });
- if (item != null)
- {
- ids.Add(item.id);
- }
- }
- if (ids.Count > 0)
- {
- SetSelection(ids, options);
- }
- }
- /// <summary>
- /// 清空所有数据
- /// </summary>
- public void ClearData()
- {
- _datas.Clear();
- _items.Clear();
- Reload();
- }
- /// <summary>
- /// 移动数据位置
- /// </summary>
- /// <param name="data">数据</param>
- /// <param name="AorS">上移:1,下移:0</param>
- public void MoveDataIndex(T data, int AorS)
- {
- if (!_datas.Contains(data))
- return;
- TableViewItem<T> 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();
- }
- }
- }
|