Files
SoulliesOfficial f26f9fd374 爆更
2026-03-20 12:07:44 -04:00

277 lines
8.0 KiB
C#

using LunaWolfStudiosEditor.ScriptableSheets.Layout;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using static UnityEditor.GenericMenu;
namespace LunaWolfStudiosEditor.ScriptableSheets
{
public class SheetsMultiColumnHeader : MultiColumnHeader
{
private static readonly FieldInfo s_ColumnRectsField = typeof(MultiColumnHeader).GetField("m_ColumnRects", BindingFlags.Instance | BindingFlags.NonPublic);
private readonly MenuFunction2 m_CopyColumnFunc;
private readonly MenuFunction2 m_SearchFilterFunc;
private int m_ContextColumn;
private HashSet<int> m_DockedColumns = new HashSet<int>();
public HashSet<int> DockedColumns { get => m_DockedColumns; set => m_DockedColumns = value; }
public event HeaderCallback dockedColumnsChanged;
private float m_ScrollX;
private float m_WidthOfAllVisibleDockedColumns;
public SheetsMultiColumnHeader(MultiColumnHeaderState state, MenuFunction2 copyColumnFunc, MenuFunction2 searchFilterFunc) : base(state)
{
m_CopyColumnFunc = copyColumnFunc;
m_SearchFilterFunc = searchFilterFunc;
}
public override void OnGUI(Rect rect, float xScroll)
{
// We want to draw the ColumnHeader as a single line, but each row will be the row height.
var totalHeaderRect = new Rect(0f, 0f, rect.width, rect.height);
rect.height = EditorGUIUtility.singleLineHeight;
base.OnGUI(rect, xScroll);
if (DockedColumns.Count > 0)
{
UpdateColumnHeaderRectsWithDocking(totalHeaderRect, xScroll);
}
else if (totalHeaderRect.height > rect.height)
{
UpdateColumnHeaderRectHeight(totalHeaderRect);
}
}
private void UpdateColumnHeaderRectHeight(Rect totalHeaderRect)
{
var columnRects = (Rect[]) s_ColumnRectsField.GetValue(this);
for (var i = 0; i < columnRects.Length; i++)
{
columnRects[i].height = totalHeaderRect.height;
}
s_ColumnRectsField.SetValue(this, columnRects);
}
private void UpdateColumnHeaderRectsWithDocking(Rect totalHeaderRect, float xScroll)
{
var columnRects = (Rect[]) s_ColumnRectsField.GetValue(this);
var rect = totalHeaderRect;
var dockedRect = new Rect();
for (var i = 0; i < state.visibleColumns.Length; i++)
{
var num = state.visibleColumns[i];
var column = state.columns[num];
if (i > 0)
{
rect.x += rect.width;
}
rect.width = column.width;
columnRects[i] = rect;
// Name and Actions column move with scroll.
if (num <= 1 && DockedColumns.Contains(num))
{
// Logic for the first docked column differs from the next.
if (dockedRect == Rect.zero)
{
columnRects[i].x = Mathf.Max(columnRects[i].x, columnRects[0].x + xScroll);
dockedRect = columnRects[i];
}
else
{
columnRects[i].x += xScroll;
dockedRect.xMax = columnRects[i].xMax;
}
}
else if (dockedRect.xMax > columnRects[i].x)
{
var columRectXMax = columnRects[i].xMax;
columnRects[i].x = dockedRect.xMax;
columnRects[i].width = Mathf.Max(0, columRectXMax - columnRects[i].x);
}
}
s_ColumnRectsField.SetValue(this, columnRects);
m_ScrollX = xScroll;
// Store this once so we don't have to repeatedly call it for the ColumnHeaderGUI.
m_WidthOfAllVisibleDockedColumns = GetWidthOfAllVisibleDockedColumns();
}
protected override void ColumnHeaderGUI(MultiColumnHeaderState.Column column, Rect headerRect, int columnIndex)
{
headerRect.height = EditorGUIUtility.singleLineHeight;
var isDocked = false;
if (DockedColumns.Count > 0)
{
if (DockedColumns.Contains(columnIndex))
{
isDocked = true;
// If Actions is docked then we just add the scroll X to all docked columns.
if (DockedColumns.Contains(0))
{
headerRect.x += m_ScrollX;
}
else
{
headerRect.x = Mathf.Max(headerRect.x, GetColumnRect(0).x + m_ScrollX);
}
EditorGUI.DrawRect(headerRect, SheetLayout.DockedHeaderBackgroundColor);
}
// Don't hide the Actions column label.
else if (columnIndex > 0 && m_WidthOfAllVisibleDockedColumns > 0)
{
var xOffset = m_WidthOfAllVisibleDockedColumns + m_ScrollX;
if (headerRect.x < xOffset)
{
var delta = xOffset - headerRect.x;
headerRect.x += delta;
headerRect.xMax -= delta;
if (headerRect.width < SheetLayout.MinColumnHeaderWidth)
{
return;
}
}
}
}
SortingButton(column, headerRect, columnIndex);
var style = GetStyle(column.headerTextAlignment);
if (isDocked)
{
style = new GUIStyle(style)
{
normal = { textColor = SheetLayout.DockedHeaderLabelColor }
};
}
var num = SheetLayout.kWindowToolbarHeight;
var position = new Rect(headerRect.x, headerRect.yMax - num, headerRect.width, num);
GUI.Label(position, column.headerContent, style);
var e = Event.current;
if (e.type == EventType.MouseDown && e.button == 1 && headerRect.Contains(e.mousePosition))
{
m_ContextColumn = columnIndex;
}
}
protected override void AddColumnHeaderContextMenuItems(GenericMenu menu)
{
var contextColumn = state.columns[m_ContextColumn];
var contextColumnName = contextColumn.headerContent.text;
menu.AddDisabledItem(new GUIContent($"[{contextColumnName}]"));
// Can only Dock Actions and Name column.
if (m_ContextColumn <= 1)
{
menu.AddItem(EditorGUIUtility.TrTextContent("Dock column"), DockedColumns.Contains(m_ContextColumn), ToggleColumnDocking, m_ContextColumn);
}
if (m_ContextColumn > 0)
{
menu.AddItem(EditorGUIUtility.TrTextContent("Hide column"), false, ToggleColumnVisibility, m_ContextColumn);
menu.AddItem(EditorGUIUtility.TrTextContent("Copy column"), false, m_CopyColumnFunc, m_ContextColumn);
menu.AddItem(EditorGUIUtility.TrTextContent("Copy property path"), false, CopyPropertyPath, m_ContextColumn);
menu.AddItem(EditorGUIUtility.TrTextContent("Filter by property"), false, m_SearchFilterFunc, m_ContextColumn);
menu.AddSeparator(string.Empty);
}
menu.AddItem(EditorGUIUtility.TrTextContent("Resize to Fit"), false, ResizeToFit);
menu.AddSeparator(string.Empty);
var columnNameCounters = new Dictionary<string, int>();
for (int i = 0; i < state.columns.Length && i < SheetLayout.MenuItemLimit; i++)
{
var column = state.columns[i];
var columnName = column.headerContent.text;
var menuItemName = columnName;
if (columnNameCounters.ContainsKey(columnName))
{
columnNameCounters[columnName]++;
menuItemName = $"{columnName} ({columnNameCounters[columnName]})";
}
else
{
columnNameCounters[columnName] = 0;
}
if (column.allowToggleVisibility)
{
menu.AddItem(new GUIContent(menuItemName), state.visibleColumns.Contains(i), ToggleColumnVisibility, i);
}
else
{
menu.AddDisabledItem(new GUIContent(menuItemName));
}
}
m_ContextColumn = 0;
}
public float GetWidthOfAllVisibleDockedColumns()
{
return state.visibleColumns.Where(v => m_DockedColumns.Contains(v)).Sum(d => state.columns[d].width);
}
protected virtual void OnDockedColumnsChanged()
{
dockedColumnsChanged?.Invoke(this);
}
private GUIStyle GetStyle(TextAlignment alignment)
{
switch (alignment)
{
case TextAlignment.Left:
return DefaultStyles.columnHeader;
case TextAlignment.Center:
return DefaultStyles.columnHeaderCenterAligned;
case TextAlignment.Right:
return DefaultStyles.columnHeaderRightAligned;
default:
return DefaultStyles.columnHeader;
}
}
private void ToggleColumnVisibility(object columnData)
{
ToggleVisibility((int) columnData);
}
private void ToggleColumnDocking(object columnData)
{
var columnIndex = (int) columnData;
if (DockedColumns.Contains(columnIndex))
{
DockedColumns.Remove(columnIndex);
}
else
{
DockedColumns.Add(columnIndex);
}
OnDockedColumnsChanged();
}
private void CopyPropertyPath(object columnData)
{
EditorGUIUtility.systemCopyBuffer = state.columns[(int) columnData].headerContent.tooltip;
}
}
}