From cac9bb196d5370c6df211cbcf70941b6c4a20f4f Mon Sep 17 00:00:00 2001 From: lrc <571244399@qq.com> Date: Mon, 29 Jun 2026 22:38:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A1=A8=E6=A0=BC=E4=B8=8A?= =?UTF-8?q?=E7=9A=84=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/XTable/XericUIActionTableEditor.cs | 29 +++ .../Core/StyleSheetUI/StyleRefreshManager.cs | 2 +- Runtime/XTable/Core/XTableClipboardData.cs | 177 ++++++++++++++++++ .../XTable/Core/XTableClipboardData.cs.meta | 11 ++ .../Rendering/Component/XericUIActionTable.cs | 28 +++ 5 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 Runtime/XTable/Core/XTableClipboardData.cs create mode 100644 Runtime/XTable/Core/XTableClipboardData.cs.meta diff --git a/Editor/XTable/XericUIActionTableEditor.cs b/Editor/XTable/XericUIActionTableEditor.cs index a6c6533..c686f88 100644 --- a/Editor/XTable/XericUIActionTableEditor.cs +++ b/Editor/XTable/XericUIActionTableEditor.cs @@ -1,6 +1,8 @@ using UnityEditor; using UnityEngine; using UnityEngine.UI; +using XericLibrary.Runtime.MacroLibrary; +using XericUI.XTable.Core; using XericUI.XTable.Rendering.Component; namespace XericUIEditor.XTable @@ -92,6 +94,33 @@ namespace XericUIEditor.XTable EditorGUILayout.Space(4); + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("导出到剪贴板", GUILayout.Height(26))) + { + var data = m_Table.BuildClipboardData(); + MacroFile.SetClipboardObject(data, MacroFile.JsonSerializerFormatter.formatterWithZip); + Debug.Log($"[XTable] 表格数据已导出到剪贴板 ({data.Cells?.Count ?? 0} 个单元格, {data.Merges?.Count ?? 0} 个合并)"); + } + if (GUILayout.Button("从剪贴板导入", GUILayout.Height(26))) + { + var data = MacroFile.GetClipboardObject(MacroFile.JsonSerializerFormatter.formatterWithZip); + if (data != null) + { + Undo.RecordObject(m_Table, "Import Table from Clipboard"); + m_Table.ApplyClipboardData(data); + serializedObject.Update(); + Repaint(); + Debug.Log($"[XTable] 已从剪贴板导入表格数据 ({data.Cells?.Count ?? 0} 个单元格, {data.Merges?.Count ?? 0} 个合并)"); + } + else + { + Debug.LogWarning("[XTable] 剪贴板中没有有效的表格数据"); + } + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(4); + bool newShow = EditorGUILayout.Toggle("显示子项", m_ShowChildren); if (newShow != m_ShowChildren) { diff --git a/Runtime/Core/StyleSheetUI/StyleRefreshManager.cs b/Runtime/Core/StyleSheetUI/StyleRefreshManager.cs index a8048d8..87d95e1 100644 --- a/Runtime/Core/StyleSheetUI/StyleRefreshManager.cs +++ b/Runtime/Core/StyleSheetUI/StyleRefreshManager.cs @@ -43,7 +43,7 @@ namespace XericUI.Core.StyleSheetUI /// public static void ForceRefreshAll() { -#if XERIC_STYLESHEET_ENABLED +#if XericLibrary XericLibrary.Runtime.SuperStyleSheet.StyleManager.ForceRefresh(); #endif diff --git a/Runtime/XTable/Core/XTableClipboardData.cs b/Runtime/XTable/Core/XTableClipboardData.cs new file mode 100644 index 0000000..ab5466c --- /dev/null +++ b/Runtime/XTable/Core/XTableClipboardData.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; + +using XericUI.XTable.Mapping; +using XericUI.XTable.Rendering.Component; + +namespace XericUI.XTable.Core +{ + /// + /// 表格粘贴复制传输对象——将表格的尺寸、单元格文本、合并信息打包为可序列化结构, + /// 配合 MacroFile.SetClipboardObject / GetClipboardObject 实现表格内容的导入导出。 + /// + [Serializable] + public class XTableClipboardData + { + [Serializable] + public struct CellEntry + { + public int Row; + public int Col; + public string Text; + public string StyleNamespace; + + public CellEntry(int row, int col, string text, string styleNamespace = null) + { + Row = row; + Col = col; + Text = text; + StyleNamespace = styleNamespace; + } + } + + [Serializable] + public struct MergeEntry + { + /// 合并起始行(全局坐标) + public int StartRow; + + /// 合并起始列(全局坐标) + public int StartCol; + + /// 合并行数 + public int RowSpan; + + /// 合并列数 + public int ColSpan; + + public MergeEntry(int startRow, int startCol, int rowSpan, int colSpan) + { + StartRow = startRow; + StartCol = startCol; + RowSpan = rowSpan; + ColSpan = colSpan; + } + } + + /// 行高数组 + public float[] RowHeights; + + /// 列宽数组 + public float[] ColWidths; + + /// 默认样式命名空间 + public string DefaultStyleNamespace; + + /// 单元格数据列表(仅序列化有文本内容的单元格) + public List Cells; + + /// 合并单元格描述列表 + public List Merges; + + public XTableClipboardData() + { + Cells = new List(); + Merges = new List(); + } + + /// + /// 从表格收集所有数据——尺寸、单元格文本、合并信息。 + /// 调用方可将返回的 DTO 传给 MacroFile.SetClipboardObject 写入剪贴板。 + /// + public static XTableClipboardData FromTable(XericUIActionTable table) + { + var data = new XTableClipboardData + { + RowHeights = table.RowHeights, + ColWidths = table.ColWidths, + DefaultStyleNamespace = table.DefaultStyleNamespace, + }; + + int rows = table.RowHeights?.Length ?? 0; + int cols = table.ColWidths?.Length ?? 0; + var tableData = table.TableData; + for (int r = 0; r < rows; r++) + { + for (int c = 0; c < cols; c++) + { + var cell = tableData.GetCell(r, c); + if (cell == null) continue; + + bool hasContent = !string.IsNullOrEmpty(cell.Text) + || !string.IsNullOrEmpty(cell.StyleNamespace); + if (!hasContent) continue; + + data.Cells.Add(new CellEntry(r, c, cell.Text, cell.StyleNamespace)); + } + } + + // 收集合并信息(全局坐标) + if (tableData != null) + { + foreach (var kv in tableData.BlockMap) + { + var block = kv.Value; + if (block.MergeDescriptors == null || block.MergeDescriptors.Count == 0) continue; + + XTableBlockMapping.ZIndexToBlockCoord(kv.Key, out int blockRow, out int blockCol); + + foreach (var desc in block.MergeDescriptors) + { + if (desc.IsCrossBlock) continue; + + int globalStartRow = blockRow * tableData.BlockSizeY + desc.LocalStartRow; + int globalStartCol = blockCol * tableData.BlockSizeX + desc.LocalStartCol; + + data.Merges.Add(new MergeEntry(globalStartRow, globalStartCol, + desc.MergeRowSpan, desc.MergeColSpan)); + } + } + } + + return data; + } + + /// + /// 将 DTO 中的单元格文本和合并信息写回表格数据层。 + /// 尺寸与命名空间的设置由表格组件在 ApplyClipboardData 中处理。 + /// + public void PopulateToTable(XericUIActionTable table) + { + var td = table.TableData; + if (td == null) return; + + int rows = table.RowHeights?.Length ?? 0; + int cols = table.ColWidths?.Length ?? 0; + + // 单元格文本 + if (Cells != null) + { + foreach (var entry in Cells) + { + if (entry.Row < 0 || entry.Row >= rows || entry.Col < 0 || entry.Col >= cols) + continue; + + var cell = td.GetOrCreateCell(entry.Row, entry.Col); + cell.Text = entry.Text; + cell.StyleNamespace = entry.StyleNamespace; + } + } + + // 合并信息 + if (Merges != null) + { + foreach (var merge in Merges) + { + if (merge.RowSpan > 1 || merge.ColSpan > 1) + { + int endRow = merge.StartRow + merge.RowSpan - 1; + int endCol = merge.StartCol + merge.ColSpan - 1; + if (endRow < rows && endCol < cols) + td.MergeCells(merge.StartRow, merge.StartCol, endRow, endCol); + } + } + } + } + } +} diff --git a/Runtime/XTable/Core/XTableClipboardData.cs.meta b/Runtime/XTable/Core/XTableClipboardData.cs.meta new file mode 100644 index 0000000..1cc04e9 --- /dev/null +++ b/Runtime/XTable/Core/XTableClipboardData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31b3bc5cc85539b4db6ac19bbb4a1888 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs index 407f5ad..b030bec 100644 --- a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs +++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs @@ -766,6 +766,34 @@ namespace XericUI.XTable.Rendering.Component RefreshView(); } + /// 构建剪贴板数据对象(尺寸 + 单元格文本 + 合并信息) + public XTableClipboardData BuildClipboardData() + { + return XTableClipboardData.FromTable(this); + } + + /// 将剪贴板数据应用到表格——覆盖尺寸、命名空间、单元格文本、合并信息并刷新 + public void ApplyClipboardData(XTableClipboardData data) + { + if (data == null) return; + + // 应用尺寸与默认命名空间 + if (data.RowHeights != null && data.RowHeights.Length > 0) + m_RowHeights = data.RowHeights; + if (data.ColWidths != null && data.ColWidths.Length > 0) + m_ColWidths = data.ColWidths; + if (!string.IsNullOrEmpty(data.DefaultStyleNamespace)) + m_DefaultStyleNamespace = data.DefaultStyleNamespace; + + // 写回单元格文本与合并信息 + data.PopulateToTable(this); + + MarkDirty(TableDirtyType.DataChanged); + RecalculateTotalSize(); + RefreshView(); + SetChildrenVisible(m_ChildrenVisible); + } + #endregion #region 单元格渲染