修复表格尺寸编辑功能,添加行列删除按钮

This commit is contained in:
2026-06-27 19:08:57 +08:00
parent 4b5396bcbf
commit 08df172165
2 changed files with 174 additions and 44 deletions
+70 -44
View File
@@ -540,8 +540,11 @@ namespace XericUIEditor.XTable
private const float BUBBLE_W = 60;
private const float BUBBLE_H = 22;
private const float BUBBLE_APPLY_BTN_W = 24;
private const float BUBBLE_DEL_BTN_W = 24;
private static GUIStyle s_BubbleApplyBtnStyle;
private static GUIStyle s_BubbleApplyBtnStyleActive;
private static GUIStyle s_BubbleDelBtnStyle;
private static void EnsureBubbleStyles()
{
@@ -550,14 +553,26 @@ namespace XericUIEditor.XTable
{
fontSize = 11,
fontStyle = FontStyle.Bold,
normal = { textColor = Color.white, background = MakeTex(1, 1, s_ApplyBtnColor) },
hover = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.2f, 0.55f, 0.2f, 0.95f)) },
active = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.1f, 0.4f, 0.1f, 0.95f)) },
normal = { textColor = new Color(0.5f, 0.5f, 0.5f), background = MakeTex(1, 1, new Color(0.25f, 0.25f, 0.25f, 0.6f)) },
hover = { textColor = new Color(0.7f, 0.7f, 0.7f), background = MakeTex(1, 1, new Color(0.35f, 0.35f, 0.35f, 0.8f)) },
active = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.15f, 0.15f, 0.15f, 0.8f)) },
padding = new RectOffset(0, 0, 0, 0),
margin = new RectOffset(0, 0, 0, 0),
alignment = TextAnchor.MiddleCenter,
border = new RectOffset(0, 0, 0, 0)
};
s_BubbleApplyBtnStyleActive = new GUIStyle(s_BubbleApplyBtnStyle)
{
normal = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.2f, 0.6f, 0.2f, 0.9f)) },
hover = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.2f, 0.55f, 0.2f, 0.95f)) },
active = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.1f, 0.4f, 0.1f, 0.95f)) }
};
s_BubbleDelBtnStyle = new GUIStyle(s_BubbleApplyBtnStyle)
{
normal = { textColor = new Color(0.6f, 0.3f, 0.3f), background = MakeTex(1, 1, new Color(0.3f, 0.15f, 0.15f, 0.6f)) },
hover = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.7f, 0.2f, 0.2f, 0.95f)) },
active = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.5f, 0.1f, 0.1f, 0.95f)) }
};
}
private static void DrawSizeEditBubble(float[] rh, float[] cw, Rect tr,
@@ -566,64 +581,65 @@ namespace XericUIEditor.XTable
int selRow = table.SelectedRow;
int selCol = table.SelectedCol;
// 列宽气泡
// 气泡固定总宽:输入框 + 应用按钮 + 删除按钮 + 间距
const float totalW = BUBBLE_W + BUBBLE_APPLY_BTN_W + BUBBLE_DEL_BTN_W + 4f;
// ── 列宽气泡:左对齐列左边缘,位于列标签上方 ──
if (selCol >= 0 && selCol < cw.Length && selRow < 0)
{
float cx = tr.x + SumBefore(cw, selCol) * xScale;
float cwScaled = cw[selCol] * xScale;
float bubbleX = cx + cwScaled / 2f - BUBBLE_W / 2f;
float bubbleY = tr.y - ROW_H - MARGIN - 28f;
DrawBubble(table, bubbleX, bubbleY, cw[selCol], isColumn: true, index: selCol);
float bx = cx + 2f;
float by = tr.y - ROW_H - MARGIN - BUBBLE_H - 4f;
DrawBubble(table, bx, by, cw[selCol], totalW, isColumn: true, index: selCol);
}
// ── 行高气泡:左对齐行标签左侧 ──
if (selRow >= 0 && selRow < rh.Length && selCol < 0)
{
float ry = tr.y + SumBefore(rh, selRow) * yScale;
float rhScaled = rh[selRow] * yScale;
float bubbleX = tr.x - COL_W - MARGIN - 86f;
float bubbleY = ry + rhScaled / 2f - 12f;
DrawBubble(table, bubbleX, bubbleY, rh[selRow], isColumn: false, index: selRow);
float bx = tr.x - COL_W - MARGIN - totalW - 4f;
float by = ry + (rhScaled - BUBBLE_H) / 2f;
DrawBubble(table, bx, by, rh[selRow], totalW, isColumn: false, index: selRow);
}
// ── 单元格选中时同时显示 ──
if (selRow >= 0 && selCol >= 0)
{
if (selCol < cw.Length)
{
float cx = tr.x + SumBefore(cw, selCol) * xScale;
float cwScaled = cw[selCol] * xScale;
float bubbleX = cx + cwScaled / 2f - BUBBLE_W / 2f;
float bubbleY = tr.y - ROW_H - MARGIN - 28f;
DrawBubble(table, bubbleX, bubbleY, cw[selCol], isColumn: true, index: selCol);
float bx = cx + 2f;
float by = tr.y - ROW_H - MARGIN - BUBBLE_H - 4f;
DrawBubble(table, bx, by, cw[selCol], totalW, isColumn: true, index: selCol);
}
if (selRow < rh.Length)
{
float ry = tr.y + SumBefore(rh, selRow) * yScale;
float rhScaled = rh[selRow] * yScale;
float bubbleX = tr.x - COL_W - MARGIN - 86f;
float bubbleY = ry + rhScaled / 2f - 12f;
DrawBubble(table, bubbleX, bubbleY, rh[selRow], isColumn: false, index: selRow);
float bx = tr.x - COL_W - MARGIN - totalW - 4f;
float by = ry + (rhScaled - BUBBLE_H) / 2f;
DrawBubble(table, bx, by, rh[selRow], totalW, isColumn: false, index: selRow);
}
}
}
private static void DrawBubble(XericUIActionTable table,
float x, float y, float currentValue,
bool isColumn, int index)
float totalW, bool isColumn, int index)
{
string controlName = isColumn
? $"XTableColSizeEdit_{index}"
: $"XTableRowSizeEdit_{index}";
bool isFocused = GUI.GetNameOfFocusedControl() == controlName;
// 气泡容器(含输入框 + 应用按钮)
float totalW = isFocused ? BUBBLE_W + BUBBLE_APPLY_BTN_W + 2f : BUBBLE_W;
Rect bubbleRect = new Rect(x - (isFocused ? (BUBBLE_APPLY_BTN_W + 2f) / 2f : 0), y, totalW, BUBBLE_H);
Rect bubbleRect = new Rect(x, y, totalW, BUBBLE_H);
EditorGUI.DrawRect(bubbleRect, s_BubbleBg);
EditorGUI.DrawRect(new Rect(bubbleRect.x, bubbleRect.y, bubbleRect.width, 1), s_BubbleBorder);
EditorGUI.DrawRect(new Rect(bubbleRect.x, bubbleRect.y + BUBBLE_H - 1, bubbleRect.width, 1), s_BubbleBorder);
EditorGUI.DrawRect(new Rect(bubbleRect.x, bubbleRect.y, 1, BUBBLE_H), s_BubbleBorder);
EditorGUI.DrawRect(new Rect(bubbleRect.x + bubbleRect.width - 1, bubbleRect.y, 1, BUBBLE_H), s_BubbleBorder);
EditorGUI.DrawRect(new Rect(x, y, totalW, 1), s_BubbleBorder);
EditorGUI.DrawRect(new Rect(x, y + BUBBLE_H - 1, totalW, 1), s_BubbleBorder);
EditorGUI.DrawRect(new Rect(x, y, 1, BUBBLE_H), s_BubbleBorder);
EditorGUI.DrawRect(new Rect(x + totalW - 1, y, 1, BUBBLE_H), s_BubbleBorder);
var inputStyle = new GUIStyle(GUI.skin.textField)
{
@@ -632,33 +648,31 @@ namespace XericUIEditor.XTable
alignment = TextAnchor.MiddleCenter
};
Rect inputRect = new Rect(bubbleRect.x + 2, bubbleRect.y + 2,
BUBBLE_W - 4, BUBBLE_H - 4);
// 输入框占左
Rect inputRect = new Rect(x + 2, y + 2, BUBBLE_W - 4, BUBBLE_H - 4);
GUI.SetNextControlName(controlName);
if (isFocused)
{
s_SizeEditText = GUI.TextField(inputRect, s_SizeEditText, inputStyle);
}
else
{
GUI.TextField(inputRect, currentValue.ToString("F0"), inputStyle);
// 应用按钮 — 聚焦时绿色,否则灰色
EnsureBubbleStyles();
Rect applyBtnRect = new Rect(x + BUBBLE_W + 1f, y + 1, BUBBLE_APPLY_BTN_W, BUBBLE_H - 2);
var btnStyle = isFocused ? s_BubbleApplyBtnStyleActive : s_BubbleApplyBtnStyle;
if (GUI.Button(applyBtnRect, "✓", btnStyle))
{
ApplyBubbleEdit(table, isColumn, index);
GUI.FocusControl(null);
}
// ── 应用按钮(GUI.Button 确保正确交互)──
if (isFocused)
// 删除按钮 — 删除当前行/列
Rect delBtnRect = new Rect(x + BUBBLE_W + BUBBLE_APPLY_BTN_W + 2f, y + 1, BUBBLE_DEL_BTN_W, BUBBLE_H - 2);
if (GUI.Button(delBtnRect, "✕", s_BubbleDelBtnStyle))
{
EnsureBubbleStyles();
Rect applyBtnRect = new Rect(
bubbleRect.x + BUBBLE_W + 2f, bubbleRect.y,
BUBBLE_APPLY_BTN_W, BUBBLE_H);
if (GUI.Button(applyBtnRect, "✓", s_BubbleApplyBtnStyle))
{
ApplyBubbleEdit(table, isColumn, index);
GUI.FocusControl(null);
}
ApplyBubbleDelete(table, isColumn, index);
}
// 回车提交
@@ -687,6 +701,18 @@ namespace XericUIEditor.XTable
SceneView.RepaintAll();
}
private static void ApplyBubbleDelete(XericUIActionTable table, bool isColumn, int index)
{
if (isColumn)
table.RemoveColumn(index);
else
table.RemoveRow(index);
GUI.FocusControl(null);
s_State = EditorState.TableNavigation;
SceneView.RepaintAll();
}
#endregion
#region 底部输入框
@@ -330,6 +330,110 @@ namespace XericUI.XTable.Rendering.Component
#endif
}
/// <summary>删除指定行,单元格数据上移</summary>
public void RemoveRow(int row)
{
if (row < 0 || row >= m_RowHeights.Length) return;
#if UNITY_EDITOR
UnityEditor.Undo.RecordObject(this, "Remove Table Row");
#endif
int colCount = m_ColWidths.Length;
// 先解除涉及该行的合并
for (int c = 0; c < colCount; c++)
TableData.UnmergeCells(row, c);
// 将下方行数据上移
for (int r = row + 1; r < m_RowHeights.Length; r++)
for (int c = 0; c < colCount; c++)
{
var data = TableData.GetCell(r, c);
if (data != null)
TableData.SetCell(r - 1, c, data);
else
TableData.SetCell(r - 1, c, null); // 显式清空原位置
}
// 清空最后一行数据
int lastRow = m_RowHeights.Length - 1;
for (int c = 0; c < colCount; c++)
TableData.SetCell(lastRow, c, null);
// 缩小行高数组
int newLen = m_RowHeights.Length - 1;
var newArr = new float[newLen];
for (int i = 0; i < row; i++)
newArr[i] = m_RowHeights[i];
for (int i = row; i < newLen; i++)
newArr[i] = m_RowHeights[i + 1];
m_RowHeights = newArr;
// 更新选中状态
if (m_SelectedRow >= m_RowHeights.Length)
m_SelectedRow = Mathf.Max(-1, m_RowHeights.Length - 1);
if (m_SelectStartRow >= m_RowHeights.Length)
m_SelectStartRow = Mathf.Max(-1, m_RowHeights.Length - 1);
if (m_SelectEndRow >= m_RowHeights.Length)
m_SelectEndRow = Mathf.Max(-1, m_RowHeights.Length - 1);
MarkDirty(TableDirtyType.LayoutChanged | TableDirtyType.DataChanged | TableDirtyType.SelectionChanged);
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);
#endif
}
/// <summary>删除指定列,单元格数据左移</summary>
public void RemoveColumn(int col)
{
if (col < 0 || col >= m_ColWidths.Length) return;
#if UNITY_EDITOR
UnityEditor.Undo.RecordObject(this, "Remove Table Column");
#endif
int rowCount = m_RowHeights.Length;
// 先解除涉及该列的合并
for (int r = 0; r < rowCount; r++)
TableData.UnmergeCells(r, col);
// 将右侧列数据左移
for (int r = 0; r < rowCount; r++)
for (int c = col + 1; c < m_ColWidths.Length; c++)
{
var data = TableData.GetCell(r, c);
if (data != null)
TableData.SetCell(r, c - 1, data);
else
TableData.SetCell(r, c - 1, null);
}
// 清空最后一列数据
int lastCol = m_ColWidths.Length - 1;
for (int r = 0; r < rowCount; r++)
TableData.SetCell(r, lastCol, null);
// 缩小列宽数组
int newLen = m_ColWidths.Length - 1;
var newArr = new float[newLen];
for (int i = 0; i < col; i++)
newArr[i] = m_ColWidths[i];
for (int i = col; i < newLen; i++)
newArr[i] = m_ColWidths[i + 1];
m_ColWidths = newArr;
// 更新选中状态
if (m_SelectedCol >= m_ColWidths.Length)
m_SelectedCol = Mathf.Max(-1, m_ColWidths.Length - 1);
if (m_SelectStartCol >= m_ColWidths.Length)
m_SelectStartCol = Mathf.Max(-1, m_ColWidths.Length - 1);
if (m_SelectEndCol >= m_ColWidths.Length)
m_SelectEndCol = Mathf.Max(-1, m_ColWidths.Length - 1);
MarkDirty(TableDirtyType.LayoutChanged | TableDirtyType.DataChanged | TableDirtyType.SelectionChanged);
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);
#endif
}
public void SelectCell(int row, int col)
{
ClearMultiSelection();