TEngine 6

This commit is contained in:
Alex-Rachel
2025-03-07 23:09:46 +08:00
parent aad8ff3ee5
commit 551727687f
1988 changed files with 46223 additions and 94880 deletions

View File

@@ -0,0 +1,74 @@
#if UNITY_2019_4_OR_NEWER
using System;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
public class ColumnStyle
{
public const float MaxValue = 8388608f;
/// <summary>
/// 单元列宽度
/// </summary>
public Length Width;
/// <summary>
/// 单元列最小宽度
/// </summary>
public Length MinWidth;
/// <summary>
/// 单元列最大宽度
/// </summary>
public Length MaxWidth;
/// <summary>
/// 可伸缩
/// </summary>
public bool Stretchable = false;
/// <summary>
/// 可搜索
/// </summary>
public bool Searchable = false;
/// <summary>
/// 可排序
/// </summary>
public bool Sortable = false;
/// <summary>
/// 统计数量
/// </summary>
public bool Counter = false;
/// <summary>
/// 展示单位
/// </summary>
public string Units = string.Empty;
public ColumnStyle(Length width)
{
if (width.value > MaxValue)
width = MaxValue;
Width = width;
MinWidth = width;
MaxWidth = width;
}
public ColumnStyle(Length width, Length minWidth, Length maxWidth)
{
if (maxWidth.value > MaxValue)
maxWidth = MaxValue;
Width = width;
MinWidth = minWidth;
MaxWidth = maxWidth;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6a74bbcb5d814f94fb54042ec3b6d94c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8b25809b75e1e7141aff3c2011845aab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
#if UNITY_2019_4_OR_NEWER
using UnityEditor;
namespace YooAsset.Editor
{
public class AssetPathCell : StringValueCell
{
public AssetPathCell(string searchTag, object cellValue) : base(searchTag, cellValue)
{
}
/// <summary>
/// 检视资源对象
/// Ping an asset object in the Scene like clicking it in an inspector.
/// </summary>
public bool PingAssetObject()
{
var assetPath = StringValue;
var assetGUID = AssetDatabase.AssetPathToGUID(assetPath);
if (string.IsNullOrEmpty(assetGUID))
return false;
UnityEngine.Object asset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);
if (asset == null)
return false;
Selection.activeObject = asset;
EditorGUIUtility.PingObject(asset);
return true;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed1c077653e577846ba29aadb91f13ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
#if UNITY_2019_4_OR_NEWER
using System;
namespace YooAsset.Editor
{
public class BooleanValueCell : ITableCell, IComparable
{
public object CellValue { set; get; }
public string SearchTag { private set; get; }
public bool BooleanValue
{
get
{
return (bool)CellValue;
}
}
public BooleanValueCell(string searchTag, object cellValue)
{
SearchTag = searchTag;
CellValue = cellValue;
}
public object GetDisplayObject()
{
return CellValue.ToString();
}
public int CompareTo(object other)
{
if (other is BooleanValueCell cell)
{
return this.BooleanValue.CompareTo(cell.BooleanValue);
}
else
{
return 0;
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7b1e743b81646b49b2c05721edcf9b4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
#if UNITY_2019_4_OR_NEWER
using System;
namespace YooAsset.Editor
{
public class ButtonCell : ITableCell, IComparable
{
public object CellValue { set; get; }
public string SearchTag { private set; get; }
public ButtonCell(string searchTag)
{
SearchTag = searchTag;
}
public object GetDisplayObject()
{
return string.Empty;
}
public int CompareTo(object other)
{
return 1;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe6c2551d70d6934da0b6afce3f1062c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
#if UNITY_2019_4_OR_NEWER
using System;
namespace YooAsset.Editor
{
public class IntegerValueCell : ITableCell, IComparable
{
public object CellValue { set; get; }
public string SearchTag { private set; get; }
public long IntegerValue
{
get
{
return (long)CellValue;
}
}
public IntegerValueCell(string searchTag, object cellValue)
{
SearchTag = searchTag;
CellValue = cellValue;
}
public object GetDisplayObject()
{
return CellValue.ToString();
}
public int CompareTo(object other)
{
if (other is IntegerValueCell cell)
{
return this.IntegerValue.CompareTo(cell.IntegerValue);
}
else
{
return 0;
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: be8ecb3981efa744f89ee5d3c9e7b7ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
#if UNITY_2019_4_OR_NEWER
using System;
namespace YooAsset.Editor
{
public class SingleValueCell : ITableCell, IComparable
{
public object CellValue { set; get; }
public string SearchTag { private set; get; }
public double SingleValue
{
get
{
return (double)CellValue;
}
}
public SingleValueCell(string searchTag, object cellValue)
{
SearchTag = searchTag;
CellValue = cellValue;
}
public object GetDisplayObject()
{
return CellValue.ToString();
}
public int CompareTo(object other)
{
if (other is SingleValueCell cell)
{
return this.SingleValue.CompareTo(cell.SingleValue);
}
else
{
return 0;
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ae299b7a930e03f458977750de9ca18e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
#if UNITY_2019_4_OR_NEWER
using System;
namespace YooAsset.Editor
{
public class StringValueCell : ITableCell, IComparable
{
public object CellValue { set; get; }
public string SearchTag { private set; get; }
public string StringValue
{
get
{
return (string)CellValue;
}
}
public StringValueCell(string searchTag, object cellValue)
{
SearchTag = searchTag;
CellValue = cellValue;
}
public object GetDisplayObject()
{
return CellValue;
}
public int CompareTo(object other)
{
if (other is StringValueCell cell)
{
return this.StringValue.CompareTo(cell.StringValue);
}
else
{
return 0;
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a04fd2585c5538547b9755673aea76df
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f347ad29484952842a01a1489fbbef5d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
#if UNITY_2019_4_OR_NEWER
using System;
using System.Collections.Generic;
namespace YooAsset.Editor
{
public class DefaultTableData : ITableData
{
/// <summary>
/// 是否可见
/// </summary>
public bool Visible { set; get; } = true;
/// <summary>
/// 单元格集合
/// </summary>
public IList<ITableCell> Cells { set; get; } = new List<ITableCell>();
/// <summary>
/// 添加单元格数据
/// </summary>
public void AddCell(ITableCell cell)
{
Cells.Add(cell);
}
#region
public void AddButtonCell(string searchTag)
{
var cell = new ButtonCell(searchTag);
Cells.Add(cell);
}
public void AddAssetPathCell(string searchTag, string path)
{
var cell = new AssetPathCell(searchTag, path);
Cells.Add(cell);
}
public void AddStringValueCell(string searchTag, string value)
{
var cell = new StringValueCell(searchTag, value);
Cells.Add(cell);
}
public void AddLongValueCell(string searchTag, long value)
{
var cell = new IntegerValueCell(searchTag, value);
Cells.Add(cell);
}
public void AddDoubleValueCell(string searchTag, double value)
{
var cell = new SingleValueCell(searchTag, value);
Cells.Add(cell);
}
public void AddBoolValueCell(string searchTag, bool value)
{
var cell = new BooleanValueCell(searchTag, value);
Cells.Add(cell);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b93bf9f1eb7024c44a1c84b299dc9622
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,18 @@
#if UNITY_2019_4_OR_NEWER
namespace YooAsset.Editor
{
public interface ITableCell
{
/// <summary>
/// 单元格数值
/// </summary>
object CellValue { set; get; }
/// <summary>
/// 获取界面显示对象
/// </summary>
object GetDisplayObject();
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dcfa4e21884025c4b91db2efd543e139
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
#if UNITY_2019_4_OR_NEWER
using System;
using System.Collections.Generic;
namespace YooAsset.Editor
{
public interface ITableData
{
/// <summary>
/// 是否可见
/// </summary>
bool Visible { set; get; }
/// <summary>
/// 单元格集合
/// </summary>
IList<ITableCell> Cells { set; get; }
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 26779163e1da1ca46948287a4cc10023
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 211ee819fabdd6d4399b79e6fcf45e5c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,229 @@
#if UNITY_2019_4_OR_NEWER
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
namespace YooAsset.Editor
{
public static class DefaultSearchSystem
{
/// <summary>
/// 解析搜索命令
/// </summary>
public static List<ISearchCommand> ParseCommand(string commandContent)
{
if (string.IsNullOrEmpty(commandContent))
return new List<ISearchCommand>();
List<ISearchCommand> results = new List<ISearchCommand>(10);
string[] commands = Regex.Split(commandContent, @"\s+");
foreach (var command in commands)
{
if (command.Contains("!="))
{
var splits = command.Split(new string[] { "!=" }, StringSplitOptions.None);
if (CheckSplitsValid(command, splits) == false)
continue;
var cmd = new SearchCompare();
cmd.HeaderTitle = splits[0];
cmd.CompareValue = splits[1];
cmd.CompareOperator = "!=";
results.Add(cmd);
}
else if (command.Contains(">="))
{
var splits = command.Split(new string[] { ">=" }, StringSplitOptions.None);
if (CheckSplitsValid(command, splits) == false)
continue;
var cmd = new SearchCompare();
cmd.HeaderTitle = splits[0];
cmd.CompareValue = splits[1];
cmd.CompareOperator = ">=";
results.Add(cmd);
}
else if (command.Contains("<="))
{
var splits = command.Split(new string[] { "<=" }, StringSplitOptions.None);
if (CheckSplitsValid(command, splits) == false)
continue;
var cmd = new SearchCompare();
cmd.HeaderTitle = splits[0];
cmd.CompareValue = splits[1];
cmd.CompareOperator = "<=";
results.Add(cmd);
}
else if (command.Contains(">"))
{
var splits = command.Split('>');
if (CheckSplitsValid(command, splits) == false)
continue;
var cmd = new SearchCompare();
cmd.HeaderTitle = splits[0];
cmd.CompareValue = splits[1];
cmd.CompareOperator = ">";
results.Add(cmd);
}
else if (command.Contains("<"))
{
var splits = command.Split('<');
if (CheckSplitsValid(command, splits) == false)
continue;
var cmd = new SearchCompare();
cmd.HeaderTitle = splits[0];
cmd.CompareValue = splits[1];
cmd.CompareOperator = "<";
results.Add(cmd);
}
else if (command.Contains("="))
{
var splits = command.Split('=');
if (CheckSplitsValid(command, splits) == false)
continue;
var cmd = new SearchCompare();
cmd.HeaderTitle = splits[0];
cmd.CompareValue = splits[1];
cmd.CompareOperator = "=";
results.Add(cmd);
}
else if (command.Contains(":"))
{
var splits = command.Split(':');
if (CheckSplitsValid(command, splits) == false)
continue;
var cmd = new SearchKeyword();
cmd.SearchTag = splits[0];
cmd.Keyword = splits[1];
results.Add(cmd);
}
else
{
var cmd = new SearchKeyword();
cmd.SearchTag = string.Empty;
cmd.Keyword = command;
results.Add(cmd);
}
}
return results;
}
private static bool CheckSplitsValid(string command, string[] splits)
{
if (splits.Length != 2)
{
Debug.LogWarning($"Invalid search command : {command}");
return false;
}
if (string.IsNullOrEmpty(splits[0]))
return false;
if (string.IsNullOrEmpty(splits[1]))
return false;
return true;
}
/// <summary>
/// 搜索匹配
/// </summary>
public static void Search(List<ITableData> sourceDatas, string command)
{
var searchCmds = ParseCommand(command);
foreach (var tableData in sourceDatas)
{
tableData.Visible = Search(tableData, searchCmds);
}
}
private static bool Search(ITableData tableData, List<ISearchCommand> commands)
{
if (commands.Count == 0)
return true;
// 先匹配字符串
var searchKeywordCmds = commands.Where(cmd => cmd is SearchKeyword).ToList();
if (SearchKeyword(tableData, searchKeywordCmds) == false)
return false;
// 后匹配数值
var searchCompareCmds = commands.Where(cmd => cmd is SearchCompare).ToList();
if (SearchCompare(tableData, searchCompareCmds) == false)
return false;
return true;
}
private static bool SearchKeyword(ITableData tableData, List<ISearchCommand> commands)
{
if (commands.Count == 0)
return true;
// 匹配规则:任意字符串列匹配成果
foreach (var tableCell in tableData.Cells)
{
foreach (var cmd in commands)
{
var searchKeywordCmd = cmd as SearchKeyword;
if (tableCell is StringValueCell stringValueCell)
{
if (string.IsNullOrEmpty(searchKeywordCmd.SearchTag) == false)
{
if (searchKeywordCmd.SearchTag == stringValueCell.SearchTag)
{
if (searchKeywordCmd.CompareTo(stringValueCell.StringValue))
return true;
}
}
else
{
if (searchKeywordCmd.CompareTo(stringValueCell.StringValue))
return true;
}
}
}
}
// 匹配失败
return false;
}
private static bool SearchCompare(ITableData tableData, List<ISearchCommand> commands)
{
if (commands.Count == 0)
return true;
// 匹配规则:任意指定数值列匹配成果
foreach (var tableCell in tableData.Cells)
{
foreach (var cmd in commands)
{
var searchCompareCmd = cmd as SearchCompare;
if (tableCell is IntegerValueCell integerValueCell)
{
if (searchCompareCmd.HeaderTitle == integerValueCell.SearchTag)
{
if (searchCompareCmd.CompareTo(integerValueCell.IntegerValue))
return true;
}
}
else if (tableCell is SingleValueCell singleValueCell)
{
if (searchCompareCmd.HeaderTitle == singleValueCell.SearchTag)
{
if (searchCompareCmd.CompareTo(singleValueCell.SingleValue))
return true;
}
}
}
}
// 匹配失败
return false;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3de1e93052c2c86408ba77125da962cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
#if UNITY_2019_4_OR_NEWER
namespace YooAsset.Editor
{
public interface ISearchCommand
{
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4228528e243224045863d8ae14a16194
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,133 @@
#if UNITY_2019_4_OR_NEWER
using System;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
/// <summary>
/// 指定标题的比较搜索
/// </summary>
public class SearchCompare : ISearchCommand
{
public string HeaderTitle;
public string CompareValue;
public string CompareOperator;
/// <summary>
/// 转换的整形数值
/// </summary>
private bool _isConvertedIntegerNum = false;
private long _convertedIntegerNumber = 0;
public long IntegerNumberValue
{
get
{
if (_isConvertedIntegerNum == false)
{
_isConvertedIntegerNum = true;
_convertedIntegerNumber = long.Parse(CompareValue.ToString());
}
return _convertedIntegerNumber;
}
}
/// <summary>
/// 转换的浮点数值
/// </summary>
private bool _isConvertedSingleNum = false;
private double _convertedSingleNumber = 0;
public double SingleNumberValue
{
get
{
if (_isConvertedSingleNum == false)
{
_isConvertedSingleNum = true;
_convertedSingleNumber = double.Parse(CompareValue.ToString());
}
return _convertedSingleNumber;
}
}
public bool CompareTo(long value)
{
if (CompareOperator == ">")
{
if (value > SingleNumberValue)
return true;
}
else if (CompareOperator == ">=")
{
if (value >= SingleNumberValue)
return true;
}
else if (CompareOperator == "<")
{
if (value < SingleNumberValue)
return true;
}
else if (CompareOperator == "<=")
{
if (value <= SingleNumberValue)
return true;
}
else if (CompareOperator == "=")
{
if (value == SingleNumberValue)
return true;
}
else if (CompareOperator == "!=")
{
if (value != SingleNumberValue)
return true;
}
else
{
Debug.LogWarning($"Can not support operator : {CompareOperator}");
}
return false;
}
public bool CompareTo(double value)
{
if (CompareOperator == ">")
{
if (value > IntegerNumberValue)
return true;
}
else if (CompareOperator == ">=")
{
if (value >= IntegerNumberValue)
return true;
}
else if (CompareOperator == "<")
{
if (value < IntegerNumberValue)
return true;
}
else if (CompareOperator == "<=")
{
if (value <= IntegerNumberValue)
return true;
}
else if (CompareOperator == "=")
{
if (value == IntegerNumberValue)
return true;
}
else if (CompareOperator == "!=")
{
if (value != IntegerNumberValue)
return true;
}
else
{
Debug.LogWarning($"Can not support operator : {CompareOperator}");
}
return false;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 345cafa16ea7ccc488c96af1a4ca33c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
#if UNITY_2019_4_OR_NEWER
namespace YooAsset.Editor
{
/// <summary>
/// 搜索关键字
/// </summary>
public class SearchKeyword : ISearchCommand
{
public string SearchTag;
public string Keyword;
public bool CompareTo(string value)
{
return value.Contains(Keyword);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3c34fa79e35e66247b64f18eafa1d230
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
#if UNITY_2019_4_OR_NEWER
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
public class TableColumn
{
/// <summary>
/// 单元列索引值
/// </summary>
internal int ColumnIndex;
/// <summary>
/// 单元元素集合
/// </summary>
internal List<VisualElement> CellElements = new List<VisualElement>(1000);
/// <summary>
/// UI元素名称
/// </summary>
public string ElementName { private set; get; }
/// <summary>
/// 标题名称
/// </summary>
public string HeaderTitle { private set; get; }
/// <summary>
/// 单元列样式
/// </summary>
public ColumnStyle ColumnStyle { private set; get; }
/// <summary>
/// 制作单元格元素
/// </summary>
public Func<VisualElement> MakeCell;
/// <summary>
/// 绑定数据到单元格
/// </summary>
public Action<VisualElement, ITableData, ITableCell> BindCell;
public TableColumn(string elementName, string headerTitle, ColumnStyle columnStyle)
{
this.ElementName = elementName;
this.HeaderTitle = headerTitle;
this.ColumnStyle = columnStyle;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 034395dad363e3a4da96881de60918a3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,386 @@
#if UNITY_2019_4_OR_NEWER
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
/// <summary>
/// Unity2022版本以上推荐官方类MultiColumnListView组件
/// </summary>
public class TableViewer : VisualElement
{
public new class UxmlFactory : UxmlFactory<TableViewer, UxmlTraits>
{
}
private readonly Toolbar _toolbar;
private readonly ListView _listView;
private readonly List<TableColumn> _columns = new List<TableColumn>(10);
private List<ITableData> _itemsSource;
private List<ITableData> _sortingDatas;
// 排序相关
private string _sortingHeader;
private bool _descendingSort = true;
/// <summary>
/// 数据源
/// </summary>
public List<ITableData> itemsSource
{
get
{
return _itemsSource;
}
set
{
if (CheckItemsSource(value))
{
_itemsSource = value;
_sortingDatas = value;
}
}
}
/// <summary>
/// 选中的数据列表
/// </summary>
public List<ITableData> selectedItems
{
get
{
#if UNITY_2020_3_OR_NEWER
return _listView.selectedItems.Cast<ITableData>().ToList();
#else
List<ITableData> result = new List<ITableData>();
result.Add(_listView.selectedItem as ITableData);
return result;
#endif
}
}
/// <summary>
/// 单元视图交互事件
/// </summary>
public Action<PointerDownEvent, ITableData> ClickTableDataEvent;
/// <summary>
/// 单元视图交互事件
/// </summary>
public Action<TableColumn> ClickTableHeadEvent;
/// <summary>
/// 单元视图变化事件
/// </summary>
public Action<ITableData> SelectionChangedEvent;
public TableViewer()
{
this.style.flexShrink = 1f;
this.style.flexGrow = 1f;
// 定义标题栏
_toolbar = new Toolbar();
// 定义列表视图
_listView = new ListView();
_listView.style.flexShrink = 1f;
_listView.style.flexGrow = 1f;
_listView.makeItem = MakeListViewElement;
_listView.bindItem = BindListViewElement;
_listView.selectionType = SelectionType.Multiple;
_listView.RegisterCallback<PointerDownEvent>(OnClickListItem);
#if UNITY_2022_3_OR_NEWER
_listView.selectionChanged += OnSelectionChanged;
#elif UNITY_2020_1_OR_NEWER
_listView.onSelectionChange += OnSelectionChanged;
#else
_listView.onSelectionChanged += OnSelectionChanged;
#endif
this.Add(_toolbar);
this.Add(_listView);
}
/// <summary>
/// 获取标题UI元素
/// </summary>
public VisualElement GetHeaderElement(string elementName)
{
return _toolbar.Q<ToolbarButton>(elementName);
}
/// <summary>
/// 添加单元列
/// </summary>
public void AddColumn(TableColumn column)
{
var toolbarBtn = new ToolbarButton();
toolbarBtn.userData = column;
toolbarBtn.name = column.ElementName;
toolbarBtn.text = column.HeaderTitle;
toolbarBtn.style.flexGrow = 0;
toolbarBtn.style.width = column.ColumnStyle.Width;
toolbarBtn.style.minWidth = column.ColumnStyle.Width;
toolbarBtn.style.maxWidth = column.ColumnStyle.Width;
toolbarBtn.clickable.clickedWithEventInfo += OnClickTableHead;
SetCellElementStyle(toolbarBtn);
_toolbar.Add(toolbarBtn);
_columns.Add(column);
// 可伸缩控制柄
if (column.ColumnStyle.Stretchable)
{
int handleWidth = 3;
int minWidth = (int)column.ColumnStyle.MinWidth.value;
int maxWidth = (int)column.ColumnStyle.MaxWidth.value;
var resizeHandle = new ResizeHandle(handleWidth, toolbarBtn, minWidth, maxWidth);
resizeHandle.ResizeChanged += (float value) =>
{
float width = Mathf.Clamp(value, column.ColumnStyle.MinWidth.value, column.ColumnStyle.MaxWidth.value);
column.ColumnStyle.Width = width;
foreach (var element in column.CellElements)
{
element.style.width = width;
element.style.minWidth = width;
element.style.maxWidth = width;
}
};
_toolbar.Add(resizeHandle);
}
// 计算索引值
column.ColumnIndex = _columns.Count - 1;
if (column.ColumnStyle.Sortable == false)
toolbarBtn.SetEnabled(false);
}
/// <summary>
/// 添加单元列集合
/// </summary>
public void AddColumns(IList<TableColumn> columns)
{
foreach (var column in columns)
{
AddColumn(column);
}
}
/// <summary>
/// 重建表格视图
/// </summary>
public void RebuildView()
{
if (_itemsSource == null)
return;
var itemsSource = _sortingDatas.Where(row => row.Visible);
_listView.Clear();
_listView.ClearSelection();
_listView.itemsSource = itemsSource.ToList();
_listView.Rebuild();
// 刷新标题栏
RefreshToobar();
}
private void RefreshToobar()
{
// 设置为原始标题
foreach (var column in _columns)
{
var toobarButton = _toolbar.Q<ToolbarButton>(column.ElementName);
toobarButton.text = column.HeaderTitle;
}
// 设置元素数量
foreach (var column in _columns)
{
if (column.ColumnStyle.Counter)
{
var toobarButton = GetHeaderElement(column.ElementName) as ToolbarButton;
toobarButton.text = $"{toobarButton.text} ({itemsSource.Count()})";
}
}
// 设置展示单位
foreach (var column in _columns)
{
if (string.IsNullOrEmpty(column.ColumnStyle.Units) == false)
{
var toobarButton = GetHeaderElement(column.ElementName) as ToolbarButton;
toobarButton.text = $"{toobarButton.text} ({column.ColumnStyle.Units})";
}
}
// 设置升降符号
if (string.IsNullOrEmpty(_sortingHeader) == false)
{
var _toobarButton = _toolbar.Q<ToolbarButton>(_sortingHeader);
if (_descendingSort)
_toobarButton.text = $"{_toobarButton.text} ↓";
else
_toobarButton.text = $"{_toobarButton.text} ↑";
}
}
/// <summary>
/// 清空所有数据
/// </summary>
public void ClearAll(bool clearColumns, bool clearSource)
{
if (clearColumns)
{
_columns.Clear();
_toolbar.Clear();
}
if (clearSource)
{
if (_itemsSource != null)
_itemsSource.Clear();
if (_sortingDatas != null)
_sortingDatas.Clear();
_listView.Clear();
_listView.ClearSelection();
}
}
private void OnClickListItem(PointerDownEvent evt)
{
var selectData = _listView.selectedItem as ITableData;
if (selectData == null)
return;
ClickTableDataEvent?.Invoke(evt, selectData);
}
private void OnClickTableHead(EventBase eventBase)
{
if (_itemsSource == null)
return;
ToolbarButton toolbarBtn = eventBase.target as ToolbarButton;
var clickedColumn = toolbarBtn.userData as TableColumn;
if (clickedColumn == null)
return;
ClickTableHeadEvent?.Invoke(clickedColumn);
if (clickedColumn.ColumnStyle.Sortable == false)
return;
if (_sortingHeader != clickedColumn.ElementName)
{
_sortingHeader = clickedColumn.ElementName;
_descendingSort = false;
}
else
{
_descendingSort = !_descendingSort;
}
// 升降排序
if (_descendingSort)
_sortingDatas = _itemsSource.OrderByDescending(tableData => tableData.Cells[clickedColumn.ColumnIndex]).ToList();
else
_sortingDatas = _itemsSource.OrderBy(tableData => tableData.Cells[clickedColumn.ColumnIndex]).ToList();
// 刷新数据表
RebuildView();
}
private void OnSelectionChanged(IEnumerable<object> items)
{
foreach (var item in items)
{
var tableData = item as ITableData;
SelectionChangedEvent?.Invoke(tableData);
break;
}
}
private bool CheckItemsSource(List<ITableData> itemsSource)
{
if (itemsSource == null)
return false;
if (itemsSource.Count > 0)
{
int cellCount = itemsSource[0].Cells.Count;
for (int i = 0; i < itemsSource.Count; i++)
{
var tableData = itemsSource[i];
if (tableData == null)
{
Debug.LogWarning($"Items source has null instance !");
return false;
}
if (tableData.Cells == null || tableData.Cells.Count == 0)
{
Debug.LogWarning($"Items source data has empty cells !");
return false;
}
if (tableData.Cells.Count != cellCount)
{
Debug.LogWarning($"Items source data has inconsisten cells count ! Item index {i}");
return false;
}
}
}
return true;
}
private VisualElement MakeListViewElement()
{
VisualElement listViewElement = new VisualElement();
listViewElement.style.flexDirection = FlexDirection.Row;
foreach (var column in _columns)
{
var cellElement = column.MakeCell.Invoke();
cellElement.name = column.ElementName;
cellElement.style.flexGrow = 0f;
cellElement.style.width = column.ColumnStyle.Width;
cellElement.style.minWidth = column.ColumnStyle.Width;
cellElement.style.maxWidth = column.ColumnStyle.Width;
SetCellElementStyle(cellElement);
listViewElement.Add(cellElement);
column.CellElements.Add(cellElement);
}
return listViewElement;
}
private void BindListViewElement(VisualElement listViewElement, int index)
{
var sourceDatas = _listView.itemsSource as List<ITableData>;
var tableData = sourceDatas[index];
foreach (var colum in _columns)
{
var cellElement = listViewElement.Q(colum.ElementName);
var tableCell = tableData.Cells[colum.ColumnIndex];
colum.BindCell.Invoke(cellElement, tableData, tableCell);
}
}
private void SetCellElementStyle(VisualElement element)
{
StyleLength defaultStyle = new StyleLength(1f);
element.style.paddingTop = defaultStyle;
element.style.paddingBottom = defaultStyle;
element.style.marginTop = defaultStyle;
element.style.marginBottom = defaultStyle;
element.style.paddingLeft = 1;
element.style.paddingRight = 1;
element.style.marginLeft = 0;
element.style.marginRight = 0;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c12f27850c4d104db1dc85cf532e586
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: