├── .gitignore ├── DemoWindow.cs ├── License.txt ├── README.md ├── README_CN.md ├── Screen.png └── SimpleEditorTableView.cs /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.meta -------------------------------------------------------------------------------- /DemoWindow.cs: -------------------------------------------------------------------------------- 1 | /*** 2 | * Copyright (c) 2024 Red Games 3 | * 4 | * Permission is hereby granted, free of charge, to any person 5 | * obtaining a copy of this software and associated documentation 6 | * files (the "Software"), to deal in the Software without 7 | * restriction, including without limitation the rights to use, 8 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following 11 | * conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | * HOLRDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USER OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | using System; 27 | using System.Linq; 28 | using UnityEditor; 29 | using UnityEngine; 30 | using Random = UnityEngine.Random; 31 | 32 | namespace RedGame.Framework.EditorTools 33 | { 34 | // Demo data class 35 | public class LightItem 36 | { 37 | public bool enabled; 38 | public string name; 39 | public LightType type; 40 | public LightShape shape; 41 | public Color color; 42 | public float intensity; 43 | } 44 | 45 | // Demo editor window 46 | public class DemoWindow : EditorWindow 47 | { 48 | private SimpleEditorTableView _tableView; 49 | private LightItem[] _lightItems = Array.Empty(); 50 | 51 | 52 | private LightType _newLightType = LightType.Directional; 53 | 54 | [MenuItem("My Tool/Show Table View Demo")] 55 | private static void ShowWindow() 56 | { 57 | var window = GetWindow(); 58 | window.titleContent = new GUIContent("Lights Table"); 59 | window.Show(); 60 | } 61 | 62 | private SimpleEditorTableView CreateTable() 63 | { 64 | SimpleEditorTableView tableView = new SimpleEditorTableView(); 65 | 66 | GUIStyle labelGUIStyle = new GUIStyle(GUI.skin.label) 67 | { 68 | padding = new RectOffset(left: 10, right: 10, top: 2, bottom: 2) 69 | }; 70 | 71 | GUIStyle disabledLabelGUIStyle = new GUIStyle(labelGUIStyle) 72 | { 73 | normal = new GUIStyleState 74 | { 75 | textColor = Color.gray 76 | } 77 | }; 78 | 79 | tableView.AddColumn("E", 30, (rect, item) => 80 | { 81 | rect.xMin += 10; 82 | item.enabled = EditorGUI.Toggle( 83 | position: rect, 84 | value: item.enabled 85 | ); 86 | }).SetMaxWidth(30).SetTooltip("Enable/Disable Light"); 87 | 88 | tableView.AddColumn("Name", 80, (rect, item) => 89 | { 90 | GUIStyle style = item.enabled ? labelGUIStyle : disabledLabelGUIStyle; 91 | item.name = EditorGUI.TextField( 92 | position: rect, 93 | text: item.name, 94 | style: style 95 | ); 96 | }).SetAutoResize(true).SetTooltip("Light name") 97 | .SetSorting((a, b) => String.Compare(a.name, b.name, StringComparison.Ordinal)); 98 | 99 | tableView.AddColumn("Type", 70, (rect, item) => 100 | { 101 | float iconSize = rect.height; 102 | Rect iconRect = new Rect(rect.x, rect.y, iconSize, iconSize); 103 | Rect labelRect = new Rect(iconRect.xMax, rect.y, rect.width - iconSize, rect.height); 104 | 105 | string iconName = GetLightIcon(item.type); 106 | EditorGUI.LabelField(iconRect, EditorGUIUtility.IconContent(iconName)); 107 | 108 | item.type = (LightType) EditorGUI.EnumPopup( 109 | position: labelRect, 110 | item.type 111 | ); 112 | }).SetAllowToggleVisibility(true).SetSorting((a, b) => a.type - b.type); 113 | 114 | tableView.AddColumn("Shape", 70, (rect, item) => 115 | { 116 | if (item.type != LightType.Directional) 117 | item.shape = (LightShape)EditorGUI.EnumPopup( 118 | position: rect, 119 | item.shape 120 | ); 121 | }).SetAllowToggleVisibility(true).SetTooltip("Shape of light"); 122 | 123 | tableView.AddColumn("Color", 100, (rect, item) => 124 | { 125 | item.color = EditorGUI.ColorField( 126 | position: rect, 127 | item.color 128 | ); 129 | }).SetAllowToggleVisibility(true); 130 | 131 | tableView.AddColumn("Intensity", 120, (rect, item) => 132 | { 133 | item.intensity = EditorGUI.Slider( 134 | position: rect, 135 | value: item.intensity, 136 | leftValue: 0, 137 | rightValue: 3 138 | ); 139 | }).SetAllowToggleVisibility(true).SetSorting((a, b) => a.intensity.CompareTo(b.intensity)); 140 | 141 | tableView.AddColumn("Edit", 60, (rect, item) => 142 | { 143 | if (GUI.Button(rect, "Delete")) 144 | { 145 | _lightItems = _lightItems.Where(x => x != item).ToArray(); 146 | } 147 | }).SetTooltip("Click to delete this light"); 148 | 149 | return tableView; 150 | } 151 | 152 | private void OnGUI() 153 | { 154 | TitleGUI(); 155 | 156 | if (_tableView == null) 157 | _tableView = CreateTable(); 158 | 159 | _tableView.DrawTableGUI(_lightItems); 160 | 161 | StatusGUI(); 162 | } 163 | 164 | private void TitleGUI() 165 | { 166 | EditorGUILayout.BeginHorizontal(); 167 | 168 | _newLightType = (LightType)EditorGUILayout.EnumPopup("Light Type", _newLightType); 169 | 170 | // Create new light button 171 | if (GUILayout.Button("Create New")) 172 | { 173 | _lightItems = _lightItems.Concat(new[] 174 | { 175 | new LightItem 176 | { 177 | enabled = true, 178 | name = GetUniqueLightName(), 179 | type = _newLightType, 180 | shape = GetRandomLightShape(), 181 | color = GetRandomColor(), 182 | intensity = Mathf.Round(Random.Range(0.0f, 3.0f) * 100) * 0.01f 183 | } 184 | }).ToArray(); 185 | 186 | _newLightType = GetRandomLightType(); 187 | } 188 | 189 | EditorGUILayout.EndHorizontal(); 190 | } 191 | 192 | private void StatusGUI() 193 | { 194 | EditorGUILayout.BeginHorizontal(); 195 | EditorGUILayout.LabelField("Total Light Count: " + _lightItems.Length); 196 | EditorGUILayout.EndHorizontal(); 197 | } 198 | 199 | private string GetUniqueLightName() 200 | { 201 | int index = 1; 202 | string lightName = "Light " + index; 203 | while (_lightItems.Any(x => x.name == lightName)) 204 | { 205 | index++; 206 | lightName = "Light " + index; 207 | } 208 | 209 | return lightName; 210 | } 211 | 212 | private Color GetRandomColor() 213 | { 214 | return new Color( 215 | Random.value, 216 | Random.value, 217 | Random.value 218 | ); 219 | } 220 | 221 | private LightType GetRandomLightType() 222 | { 223 | return (LightType) Random.Range(0, 3); 224 | } 225 | 226 | private LightShape GetRandomLightShape() 227 | { 228 | return (LightShape) Random.Range(0, 3); 229 | } 230 | 231 | private static string GetLightIcon(LightType type) 232 | { 233 | switch (type) 234 | { 235 | case LightType.Directional: 236 | return "DirectionalLight Icon"; 237 | case LightType.Spot: 238 | return "SpotLight Icon"; 239 | case LightType.Area: 240 | return "AreaLight Icon"; 241 | case LightType.Disc: 242 | return "DiscLight Icon"; 243 | default: 244 | return "d_Light Icon"; 245 | } 246 | } 247 | } 248 | } -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 RedGames 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleEditorTableView 2 | 3 | ## Introduction 4 | SimpleEditorTableView provides a simple way to create a TableView in Unity Editor GUI. It encapsulates Unity's MultiColumnHeader and ScrollView, but with a simpler and more direct interface, supporting click sorting and custom element rendering. 5 | 6 | For a complete Demo, see [DemoWindow.cs](DemoWindow.cs) 7 | 8 | ![Screen](Screen.png) 9 | 10 | ## Getting Started 11 | 12 | ### Step 1: Create an Editor Class 13 | 14 | 1. Place `SimpleEditorTableView.cs` in the Editor directory. 15 | 2. Define a data structure to store the data in the TableView. 16 | 3. Create a new EditorWindow or Editor class. 17 | 4. Add a member of the `SimpleEditorTableView` class in your Editor class. 18 | 19 | ```csharp 20 | public class LightItem 21 | { 22 | public bool enabled; 23 | public string name; 24 | public LightType type; 25 | public LightShape shape; 26 | public Color color; 27 | public float intensity; 28 | } 29 | 30 | 31 | public class MyEditor : EditorWindow 32 | { 33 | private SimpleEditorTableView _tableView; 34 | } 35 | ``` 36 | 37 | ### Step 2: Define the Table Structure 38 | 39 | Call the `SimpleEditorTableView.AddColumn()` method to define the columns in the TableView. The caller decides how to draw each element, including various properties, how to sort, etc. 40 | 41 | ```csharp 42 | private void CreateTable() 43 | { 44 | _tableView = new SimpleEditorTableView(); 45 | 46 | // first column is a toggle, with a minimum width of 50 and a maximum width of 80 47 | _tableView.AddColumn("Enabled", 50, (rect, item) => 48 | { 49 | item.enabled = EditorGUI.Toggle(rect, item.enabled); 50 | }).SetMaxWidth(80); 51 | 52 | // second column is a text field, can be sorted by name 53 | _tableView.AddColumn("Name", 100, (rect, item) => 54 | { 55 | item.name = EditorGUI.TextField(rect, item.name); 56 | }).SetMaxWidth(200).SetSorting((a, b) => a.name.CompareTo(b.name, StringComparison.Ordinal)); 57 | 58 | // define more columns here 59 | // ... 60 | } 61 | ``` 62 | 63 | * For the AddColumn method, the following parameters are required: 64 | - __title__: The title of the column. 65 | - __minWidth__: The minimum width of the column. 66 | - __onDrawItem__: A delegate for drawing the controls for each element. It accepts two parameters, one is Rect, which represents the position and size of the control, and the other is TData, which represents the data of the current element. 67 | 68 | * The return value of AddColumn can be chained: 69 | - __SetMaxWidth__: Sets the maximum width of the column. 70 | - __SetTooltip__: Sets the tooltip for the column. 71 | - __SetAutoResize__: Sets whether the column should automatically resize. 72 | - __SetAllowToggleVisibility__: Sets whether the column can be hidden. 73 | - __SetSorting__: Sets the sorting rule. Pass in a comparator to compare the size of two elements. Only ascending order sorting needs to be implemented; descending order sorting will be handled automatically. 74 | 75 | ### Step 3: Call Drawing in OnGUI 76 | Call the `SimpleEditorTableView.DrawTableGUI()` method in OnGUI to set the data. A TData array needs to be passed in. It can be inserted anywhere in OnGUI. 77 | 78 | ```csharp 79 | private LightItem[] _lightItems = new LightItem[] { 80 | // ... 81 | }; 82 | 83 | private void OnGUI() 84 | { 85 | // Draw some GUI here 86 | _tableView.DrawTableGUI(_lightItems); 87 | // Draw more GUI here 88 | } 89 | ``` -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # SimpleEditorTableView 2 | 3 | ## 简介 4 | SimpleEditorTableView 提供了一个简单的方法来创建 Unity Editor GUI 中的 TableView。 5 | 它封装了 Unity 的 MultiColumnHeader 和 ScrollView,但是接口更加简单和直接, 6 | 支持点击排序和自定义元素绘制。 7 | 8 | 完整 Demo 参见 [DemoWindow.cs](DemoWindow.cs) 9 | 10 | ![Screen](Screen.png) 11 | 12 | ## 开始使用 13 | 14 | ### 第一步:建立 Editor 类 15 | 16 | 1. 将 `SimpleEditorTableView.cs` 放到 Editor 目录下。 17 | 2. 定义一个数据结构,用于存储 TableView 中的数据。 18 | 3. 创建一个新的 EditorWindow 或者 Editor 类 19 | 4. 在你的 Editor 类中加入一个 `EditorTableView` 类的成员。 20 | 21 | ```csharp 22 | public class LightItem 23 | { 24 | public bool enabled; 25 | public string name; 26 | public LightType type; 27 | public LightShape shape; 28 | public Color color; 29 | public float intensity; 30 | } 31 | 32 | 33 | public class MyEditor : EditorWindow 34 | { 35 | private SimpleEditorTableView _tableView; 36 | 37 | 38 | 39 | } 40 | ``` 41 | 42 | ### 第二步:定义表结构 43 | 44 | 调用 `SimpleEditorTableView.AddColumn()` 方法来定义 TableView 中的列。 45 | 调用者自己决定每个元素如何画控件,包括各种属性,如何排序等。 46 | 47 | ```csharp 48 | private void CreateTable() 49 | { 50 | _tableView = new SimpleEditorTableView(); 51 | 52 | // first column is a toggle, with a minimum width of 50 and a maximum width of 80 53 | _tableView.AddColumn("Enabled", 50, (rect, item) => 54 | { 55 | item.enabled = EditorGUI.Toggle(rect, item.enabled); 56 | }).SetMaxWidth(80); 57 | 58 | // second column is a text field, can be sorted by name 59 | _tableView.AddColumn("Name", 100, (rect, item) => 60 | { 61 | item.name = EditorGUI.TextField(rect, item.name); 62 | }).SetMaxWidth(200).SetSorting((a, b) => a.name.CompareTo(b.name, StringComparison.Ordinal)); 63 | 64 | // define more columns here 65 | // ... 66 | } 67 | ``` 68 | 69 | 对于 `AddColumn` 方法,需要传入以下参数: 70 | - title: 列的标题 71 | - minWidth: 列的最小宽度 72 | - onDrawItem: 一个委托,用于绘制每个元素的控件。它接受两个参数,一个是 Rect,表示控件的位置和大小,另一个是 TData,表示当前元素的数据。 73 | 74 | `AddColumn` 返回值可以链式调用: 75 | - SetMaxWidth: 设置列的最大宽度 76 | - SetTooltip: 设置列的提示信息 77 | - SetAutoResize: 设置列是否自动调整大小 78 | - SetAllowToggleVisibility: 设置列是否可以隐藏 79 | - SetSorting: 设置排序规则。传入一个比较器,用于比较两个元素的大小。只要实现升序排序即可,降序排序会自动处理。 80 | 81 | ### 第三步:在 OnGUI 中调用绘制 82 | 在 OnGUI 中调用 `SimpleEditorTableView.DrawTableGUI()` 方法来设置数据。 83 | 需要传入一个TData的数组。可以插入到 OnGUI 的任意位置。 84 | 85 | ```csharp 86 | private LightItem[] _lightItems = new LightItem[] { 87 | // ... 88 | }; 89 | 90 | private void OnGUI() 91 | { 92 | // Draw some GUI here 93 | _tableView.DrawTableGUI(_lightItems); 94 | // Draw more GUI here 95 | } 96 | ``` 97 | -------------------------------------------------------------------------------- /Screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redclock/SimpleEditorTableView/ead472719300ed2639d7b21135beb1f366a248e2/Screen.png -------------------------------------------------------------------------------- /SimpleEditorTableView.cs: -------------------------------------------------------------------------------- 1 | /*** 2 | * Copyright (c) 2024 Red Games 3 | * 4 | * Permission is hereby granted, free of charge, to any person 5 | * obtaining a copy of this software and associated documentation 6 | * files (the "Software"), to deal in the Software without 7 | * restriction, including without limitation the rights to use, 8 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following 11 | * conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | * HOLRDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USER OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Linq; 29 | using UnityEditor; 30 | using UnityEditor.IMGUI.Controls; 31 | using UnityEngine; 32 | 33 | namespace RedGame.Framework.EditorTools 34 | { 35 | public class SimpleEditorTableView 36 | { 37 | private MultiColumnHeaderState _multiColumnHeaderState; 38 | private MultiColumnHeader _multiColumnHeader; 39 | private MultiColumnHeaderState.Column[] _columns; 40 | private readonly Color _lighterColor = Color.white * 0.3f; 41 | private readonly Color _darkerColor = Color.white * 0.1f; 42 | 43 | private Vector2 _scrollPosition; 44 | private bool _columnResized; 45 | private bool _sortingDirty; 46 | 47 | public delegate void DrawItem(Rect rect, TData item); 48 | 49 | public class ColumnDef 50 | { 51 | internal MultiColumnHeaderState.Column column; 52 | internal DrawItem onDraw; 53 | internal Comparison onSort; 54 | 55 | public ColumnDef SetMaxWidth(float maxWidth) 56 | { 57 | column.maxWidth = maxWidth; 58 | return this; 59 | } 60 | 61 | public ColumnDef SetTooltip(string tooltip) 62 | { 63 | column.headerContent.tooltip = tooltip; 64 | return this; 65 | } 66 | 67 | public ColumnDef SetAutoResize(bool autoResize) 68 | { 69 | column.autoResize = autoResize; 70 | return this; 71 | } 72 | 73 | public ColumnDef SetAllowToggleVisibility(bool allow) 74 | { 75 | column.allowToggleVisibility = allow; 76 | return this; 77 | } 78 | 79 | public ColumnDef SetSorting(Comparison onSort) 80 | { 81 | this.onSort = onSort; 82 | column.canSort = true; 83 | return this; 84 | } 85 | } 86 | 87 | private readonly List _columnDefs = new List(); 88 | 89 | public void ClearColumns() 90 | { 91 | _columnDefs.Clear(); 92 | _columnResized = true; 93 | } 94 | 95 | public ColumnDef AddColumn(string title, int minWidth, DrawItem onDrawItem) 96 | { 97 | ColumnDef columnDef = new ColumnDef() 98 | { 99 | column = new MultiColumnHeaderState.Column() 100 | { 101 | allowToggleVisibility = false, 102 | autoResize = true, 103 | minWidth = minWidth, 104 | canSort = false, 105 | sortingArrowAlignment = TextAlignment.Right, 106 | headerContent = new GUIContent(title), 107 | headerTextAlignment = TextAlignment.Left, 108 | }, 109 | onDraw = onDrawItem 110 | }; 111 | 112 | _columnDefs.Add(columnDef); 113 | _columnResized = true; 114 | return columnDef; 115 | } 116 | 117 | private void ReBuild() 118 | { 119 | _columns = _columnDefs.Select((def) => def.column).ToArray(); 120 | _multiColumnHeaderState = new MultiColumnHeaderState(_columns); 121 | _multiColumnHeader = new MultiColumnHeader(_multiColumnHeaderState); 122 | _multiColumnHeader.visibleColumnsChanged += (multiColumnHeader) => multiColumnHeader.ResizeToFit(); 123 | _multiColumnHeader.sortingChanged += (multiColumnHeader) => _sortingDirty = true; 124 | _multiColumnHeader.ResizeToFit(); 125 | _columnResized = false; 126 | } 127 | 128 | public void DrawTableGUI(TData[] data, float maxHeight = float.MaxValue, float rowHeight = -1) 129 | { 130 | if (_multiColumnHeader == null || _columnResized) 131 | ReBuild(); 132 | 133 | float rowWidth = _multiColumnHeaderState.widthOfAllVisibleColumns; 134 | if (rowHeight < 0) 135 | rowHeight = EditorGUIUtility.singleLineHeight; 136 | 137 | Rect headerRect = GUILayoutUtility.GetRect(rowWidth, rowHeight); 138 | _multiColumnHeader!.OnGUI(headerRect, xScroll: 0.0f); 139 | 140 | float sumWidth = rowWidth; 141 | float sumHeight = rowHeight * data.Length + GUI.skin.horizontalScrollbar.fixedHeight; 142 | 143 | UpdateSorting(data); 144 | 145 | Rect scrollViewPos = GUILayoutUtility.GetRect(0, sumWidth, 0, maxHeight); 146 | Rect viewRect = new Rect(0, 0, sumWidth, sumHeight); 147 | 148 | _scrollPosition = GUI.BeginScrollView( 149 | position: scrollViewPos, 150 | scrollPosition: _scrollPosition, 151 | viewRect: viewRect, 152 | alwaysShowHorizontal: false, 153 | alwaysShowVertical: false 154 | ); 155 | 156 | EditorGUILayout.BeginVertical(); 157 | 158 | for (int row = 0; row < data.Length; row++) 159 | { 160 | Rect rowRect = new Rect(0, rowHeight * row, rowWidth, rowHeight); 161 | 162 | EditorGUI.DrawRect(rect: rowRect, color: row % 2 == 0 ? _darkerColor : _lighterColor); 163 | 164 | for (int col = 0; col < _columns.Length; col++) 165 | { 166 | if (_multiColumnHeader.IsColumnVisible(col)) 167 | { 168 | int visibleColumnIndex = _multiColumnHeader.GetVisibleColumnIndex(col); 169 | Rect cellRect = _multiColumnHeader.GetCellRect(visibleColumnIndex, rowRect); 170 | _columnDefs[col].onDraw(cellRect, data[row]); 171 | } 172 | } 173 | } 174 | 175 | EditorGUILayout.EndVertical(); 176 | GUI.EndScrollView(handleScrollWheel: true); 177 | } 178 | 179 | private void UpdateSorting(TData[] data) 180 | { 181 | if (_sortingDirty) 182 | { 183 | int sortIndex = _multiColumnHeader.sortedColumnIndex; 184 | if (sortIndex >= 0) 185 | { 186 | var sortCompare = _columnDefs[sortIndex].onSort; 187 | bool ascending = _multiColumnHeader.IsSortedAscending(sortIndex); 188 | 189 | Array.Sort(data, ((a, b) => 190 | { 191 | int r = sortCompare(a, b); 192 | return ascending ? r : -r; 193 | })); 194 | } 195 | 196 | _sortingDirty = false; 197 | } 198 | } 199 | } 200 | } --------------------------------------------------------------------------------