添加合并单元格的用法。

This commit is contained in:
2026-06-28 23:36:07 +08:00
parent f20033743d
commit b7963afe30
3 changed files with 282 additions and 41 deletions
+141 -12
View File
@@ -3,6 +3,7 @@ using UnityEditor;
using UnityEngine;
using XericLibrary.Runtime.SuperStyleSheet;
using XericUI.XTable.Core;
using XericUI.XTable.Mapping;
using XericUI.XTable.Rendering.Component;
@@ -445,18 +446,42 @@ namespace XericUIEditor.XTable
{
Color lineColor = new Color(0.5f, 0.5f, 0.55f, 0.18f);
// 水平网格线(跳过合并区域内的线)
float y = tr.y;
for (int r = 0; r < rh.Length; r++)
{
y += rh[r] * yScale;
EditorGUI.DrawRect(new Rect(tr.x, y, tr.width, 1), lineColor);
// 检查此行是否在合并区域内(非底部边界的行)
bool skipLine = false;
if (s_ActiveTable != null && r + 1 < rh.Length)
{
var data = s_ActiveTable.TableData;
if (data != null && data.IsCellMerged(r + 1, 0))
skipLine = true;
}
if (!skipLine)
EditorGUI.DrawRect(new Rect(tr.x, y, tr.width, 1), lineColor);
}
// 垂直网格线(跳过合并区域内的线)
float x = tr.x;
for (int c = 0; c < cw.Length; c++)
{
x += cw[c] * xScale;
EditorGUI.DrawRect(new Rect(x, tr.y, 1, tr.height), lineColor);
// 检查此列是否在合并区域内(非右侧边界的列)
bool skipLine = false;
if (s_ActiveTable != null && c + 1 < cw.Length)
{
var data = s_ActiveTable.TableData;
if (data != null && data.IsCellMerged(0, c + 1))
skipLine = true;
}
if (!skipLine)
EditorGUI.DrawRect(new Rect(x, tr.y, 1, tr.height), lineColor);
}
}
@@ -471,6 +496,10 @@ namespace XericUIEditor.XTable
int sc = table.SelectedCol;
if (sr < 0 || sc < 0 || sr >= rh.Length || sc >= cw.Length) return;
// 获取选中单元格的实际显示范围(合并源需要扩展)
int hlRowSpan = 1, hlColSpan = 1;
table.IsMergeSource(sr, sc, out hlRowSpan, out hlColSpan);
if (table.HasMultiSelection)
{
int minR = Mathf.Min(table.SelectStartRow, table.SelectEndRow);
@@ -478,6 +507,13 @@ namespace XericUIEditor.XTable
int minC = Mathf.Min(table.SelectStartCol, table.SelectEndCol);
int maxC = Mathf.Max(table.SelectStartCol, table.SelectEndCol);
// 扩展多选区域以包含合并源的全部跨度
if (table.IsMergeSource(minR, minC, out int msRS, out int msCS))
{
maxR = Mathf.Max(maxR, minR + msRS - 1);
maxC = Mathf.Max(maxC, minC + msCS - 1);
}
minR = Mathf.Clamp(minR, 0, rh.Length - 1);
maxR = Mathf.Clamp(maxR, 0, rh.Length - 1);
minC = Mathf.Clamp(minC, 0, cw.Length - 1);
@@ -492,10 +528,11 @@ namespace XericUIEditor.XTable
s_MultiSelectRangeColor);
}
// 单选高亮(合并源用完整跨度)
float sx = tr.x + SumBefore(cw, sc) * xScale;
float sy = tr.y + SumBefore(rh, sr) * yScale;
float sw = cw[sc] * xScale;
float sh = rh[sr] * yScale;
float sw = SumRange(cw, sc, sc + hlColSpan) * xScale;
float sh = SumRange(rh, sr, sr + hlRowSpan) * yScale;
EditorGUI.DrawRect(new Rect(sx + 1, sy + 1, sw - 2, sh - 2),
s_SelectionColor);
@@ -763,16 +800,31 @@ namespace XericUIEditor.XTable
padding = new RectOffset(4, 4, 2, 2)
};
// Row 1: 坐标标签 | 输入框 | 应用按钮
float btnW = 44;
// Row 1: 坐标标签 | 输入框 | 应用按钮 + 合并/拆分按钮
float actionBtnW = 50;
float row1Y = barRect.y + pad;
float row2Y = barRect.y + rowH + pad + 4;
string cellLabel = table.GetSelectionText();
// 合并按钮(多选时显示)
bool showMerge = table.HasMultiSelection &&
(table.SelectStartRow != table.SelectEndRow ||
table.SelectStartCol != table.SelectEndCol);
// 拆分按钮(选中单元格是合并源时显示)
bool isMergeSource = table.IsMergeSource(table.SelectedRow,
table.SelectedCol, out _, out _);
float mergeBtnW = showMerge || isMergeSource ? actionBtnW : 0;
float unmergeBtnW = isMergeSource ? actionBtnW : 0;
// 坐标标签
GUI.Label(new Rect(barRect.x + 4, row1Y, 60, rowH), cellLabel, labelStyle);
Rect inputRect = new Rect(barRect.x + 68, row1Y, barW - 68 - btnW - pad * 2, rowH);
// 输入框
float inputW = barW - 68 - 44 - 2 - mergeBtnW - unmergeBtnW - pad * 2 - 4;
Rect inputRect = new Rect(barRect.x + 68, row1Y, inputW, rowH);
// 回车提交(仅在 CellEditing 状态下)
if (s_State == EditorState.CellEditing &&
Event.current.type == EventType.KeyDown &&
Event.current.keyCode == KeyCode.Return)
@@ -784,13 +836,51 @@ namespace XericUIEditor.XTable
GUI.SetNextControlName("XTableSceneEditInput");
s_EditText = GUI.TextField(inputRect, s_EditText, inputStyle);
if (GUI.Button(new Rect(barRect.x + barW - btnW - pad, row1Y, btnW, rowH),
"应用", btnStyle))
// 应用按钮
float rightX = barRect.x + barW - pad - 44;
if (GUI.Button(new Rect(rightX, row1Y, 44, rowH), "应用", btnStyle))
{
GUI.FocusControl(null);
ApplyCellEdit(table);
}
// 合并按钮
if (showMerge)
{
var mergeStyle = new GUIStyle(btnStyle)
{
normal = { background = MakeTex(1, 1, new Color(0.15f, 0.3f, 0.65f, 0.8f)), textColor = Color.white },
hover = { background = MakeTex(1, 1, new Color(0.2f, 0.4f, 0.85f, 0.9f)), textColor = Color.white }
};
if (GUI.Button(new Rect(rightX - mergeBtnW - 2, row1Y, mergeBtnW, rowH), "合并", mergeStyle))
{
int minR = Mathf.Min(table.SelectStartRow, table.SelectEndRow);
int maxR = Mathf.Max(table.SelectStartRow, table.SelectEndRow);
int minC = Mathf.Min(table.SelectStartCol, table.SelectEndCol);
int maxC = Mathf.Max(table.SelectStartCol, table.SelectEndCol);
table.MergeCells(minR, minC, maxR - minR + 1, maxC - minC + 1);
table.RefreshView();
SceneView.RepaintAll();
}
}
// 拆分按钮
if (isMergeSource)
{
var unmergeStyle = new GUIStyle(btnStyle)
{
normal = { background = MakeTex(1, 1, new Color(0.65f, 0.25f, 0.15f, 0.8f)), textColor = Color.white },
hover = { background = MakeTex(1, 1, new Color(0.85f, 0.35f, 0.2f, 0.9f)), textColor = Color.white }
};
float unmergeX = showMerge ? rightX - mergeBtnW - unmergeBtnW - 4 : rightX - unmergeBtnW - 2;
if (GUI.Button(new Rect(unmergeX, row1Y, unmergeBtnW, rowH), "拆分", unmergeStyle))
{
table.UnmergeCells(table.SelectedRow, table.SelectedCol);
table.RefreshView();
SceneView.RepaintAll();
}
}
// Row 2: 样式命名空间下拉框
var nsLabelStyle = new GUIStyle(GUI.skin.label)
{
@@ -800,11 +890,9 @@ namespace XericUIEditor.XTable
};
GUI.Label(new Rect(barRect.x + 4, row2Y, 36, rowH), "样式:", nsLabelStyle);
// 获取当前命名空间
string currentNS = table.GetCellStyleNamespace(
table.SelectedRow, table.SelectedCol) ?? "";
// 构建下拉选项(StyleManager.GetAvailableNamespaces 已保证 "default" 在首位)
var namespaces = StyleManager.GetAvailableNamespaces();
int currentIdx = namespaces.IndexOf(currentNS);
if (currentIdx < 0) currentIdx = 0;
@@ -908,6 +996,46 @@ namespace XericUIEditor.XTable
float ry = (Event.current.mousePosition.y - tr.y) / yScale;
col = IndexFromCoord(rx, s_ColWidths);
row = IndexFromCoord(ry, s_RowHeights);
// 点击合并覆盖的单元格时,重定向到合并源
if (row >= 0 && col >= 0 && s_ActiveTable != null)
RedirectToMergeSource(ref row, ref col);
}
/// <summary>如果指定单元格被合并覆盖,重定向到合并源(锚点)</summary>
private static void RedirectToMergeSource(ref int row, ref int col)
{
var data = s_ActiveTable.TableData;
if (data == null) return;
XTableCoordinateUtility.CellToBlockCoordinate(
row, col, data.BlockSizeX, data.BlockSizeY,
out int blockRow, out int blockCol,
out int localRow, out int localCol);
ulong zIndex = XTableBlockMapping.BlockCoordToZIndex(blockRow, blockCol);
if (!data.BlockMap.TryGetValue(zIndex, out XTableBlock block))
return;
var merge = block.GetMergeRedirect(localRow, localCol);
if (merge == null) return;
merge.GetRedirectTarget(out ulong targetBlockIndex, out int targetLocalRow, out int targetLocalCol);
if (merge.IsCrossBlock && data.BlockMap.TryGetValue(targetBlockIndex, out XTableBlock targetBlock))
{
// 跨块合并:从目标块的块坐标反算全局坐标
XTableBlockMapping.ZIndexToBlockCoord(targetBlockIndex,
out int targetBlockRow, out int targetBlockCol);
row = targetBlockRow * data.BlockSizeY + targetLocalRow;
col = targetBlockCol * data.BlockSizeX + targetLocalCol;
}
else
{
// 本地合并:源在同一块内,反算全局坐标
row = blockRow * data.BlockSizeY + targetLocalRow;
col = blockCol * data.BlockSizeX + targetLocalCol;
}
}
#endregion
@@ -987,6 +1115,7 @@ namespace XericUIEditor.XTable
}
else
{
RedirectToMergeSource(ref row, ref col);
table.SelectCell(row, col);
}