public static void DrawLine( GUITableState tableState, List <TableColumn> columns, List <TableCell> row, float currentX, float currentY, float rowHeight) { for (int i = 0; i < row.Count; i++) { if (i >= columns.Count) { Debug.LogWarning("The number of cells in this row is more than the number of columns"); continue; } if (!tableState.columnVisible [i]) { continue; } TableColumn column = columns [i]; TableCell property = row[i]; GUI.enabled = column.entry.enabledCells; property.DrawCell(new Rect(currentX, currentY, tableState.columnSizes[i], rowHeight)); currentX += tableState.columnSizes[i] + 4f; } }
/// <summary> /// Draw a table completely manually. /// Each cell has to be created and given as parameter in cells. /// </summary> /// <returns>The updated table state.</returns> /// <param name="tableState">The Table state.</param> /// <param name="columns">The Columns of the table.</param> /// <param name="cells">The Cells as a list of rows.</param> /// <param name="collectionProperty">The SerializeProperty of the collection. This is useful for reorderable tables.</param> /// <param name="options">The table options.</param> public static GUITableState DrawTable( GUITableState tableState, List <TableColumn> columns, List <List <TableCell> > cells, SerializedProperty collectionProperty, params GUITableOption[] options) { GUITableEntry tableEntry = new GUITableEntry(options); if (tableState == null) { tableState = new GUITableState(); tableState.CheckState(columns, tableEntry, float.MaxValue); } float requiredHeight = GUITable.TableHeight(tableEntry, cells.Count) + 10; if (tableEntry.allowScrollView && tableState.totalWidth + 19 > Screen.width / EditorGUIUtility.pixelsPerPoint) { requiredHeight += EditorGUIUtility.singleLineHeight; } Rect position = GUILayoutUtility.GetRect( tableEntry.allowScrollView ? Screen.width / EditorGUIUtility.pixelsPerPoint - 40 : tableState.totalWidth, requiredHeight); if (Event.current.type == EventType.Layout) { return(tableState); } else { return(GUITable.DrawTable(position, tableState, columns, cells, collectionProperty, options)); } }
/// <summary> /// Draw a table just from the collection's property. /// This will create columns for all the visible members in the elements' class, /// similar to what Unity would show in the classic vertical collection display, but as a table instead. /// </summary> /// <returns>The updated table state.</returns> /// <param name="rect">The table's containing rectangle.</param> /// <param name="tableState">The Table state.</param> /// <param name="collectionProperty">The serialized property of the collection.</param> /// <param name="options">The table options.</param> public static GUITableState DrawTable( Rect rect, GUITableState tableState, SerializedProperty collectionProperty, params GUITableOption[] options) { bool isObjectReferencesCollection = false; List <string> properties = SerializationHelpers.GetElementsSerializedFields(collectionProperty, out isObjectReferencesCollection); if (properties == null && collectionProperty.arraySize == 0) { DrawTable( rect, null, new List <TableColumn> () { new TableColumn(collectionProperty.displayName + "(properties unknown, add at least 1 element)", TableColumn.Sortable(false), TableColumn.Resizeable(false)) }, new List <List <TableCell> > (), collectionProperty, options); return(tableState); } if (isObjectReferencesCollection) { List <SelectorColumn> columns = new List <SelectorColumn> (); columns.Add(new SelectObjectReferenceColumn("Object Reference", TableColumn.Optional(true))); columns.AddRange(properties.Select(prop => (SelectorColumn) new SelectFromPropertyNameColumn(prop, ObjectNames.NicifyVariableName(prop)))); return(DrawTable(rect, tableState, collectionProperty, columns, options)); } return(DrawTable(rect, tableState, collectionProperty, properties, options)); }
/// <summary> /// Draw a table from the columns' settings, the path for the corresponding properties and a selector function /// that takes a SerializedProperty and returns the TableCell to put in the corresponding cell. /// </summary> /// <returns>The updated table state.</returns> /// <param name="rect">The table's containing rectangle.</param> /// <param name="tableState">The Table state.</param> /// <param name="collectionProperty">The serialized property of the collection.</param> /// <param name="columns">The Selector Columns.</param> /// <param name="options">The table options.</param> public static GUITableState DrawTable( Rect rect, GUITableState tableState, SerializedProperty collectionProperty, List <SelectorColumn> columns, params GUITableOption[] options) { GUITableEntry tableEntry = new GUITableEntry(options); List <List <TableCell> > rows = new List <List <TableCell> >(); for (int i = 0; i < collectionProperty.arraySize; i++) { SerializedProperty sp = collectionProperty.FindPropertyRelative(SerializationHelpers.GetElementAtIndexRelativePath(i)); if (tableEntry.filter != null && !tableEntry.filter(sp)) { continue; } List <TableCell> row = new List <TableCell>(); foreach (SelectorColumn col in columns) { row.Add(col.GetCell(sp)); } rows.Add(row); } return(DrawTable(rect, tableState, columns.Select((col) => (TableColumn)col).ToList(), rows, collectionProperty, options)); }
/// <summary> /// Draw a table completely manually. /// Each cell has to be created and given as parameter in cells. /// A collectionProperty is needed for reorderable tables. Use an overload with a collectionProperty. /// </summary> /// <returns>The updated table state.</returns> /// <param name="tableState">The Table state.</param> /// <param name="columns">The Columns of the table.</param> /// <param name="cells">The Cells as a list of rows.</param> /// <param name="options">The table options.</param> public static GUITableState DrawTable( GUITableState tableState, List <TableColumn> columns, List <List <TableCell> > cells, params GUITableOption[] options) { return(DrawTable(tableState, columns, cells, null, options)); }
/// <summary> /// Draw a table using just the paths of the properties to display. /// This will create columns automatically using the property name as title, and will create /// PropertyCell instances for each element. /// </summary> /// <returns>The updated table state.</returns> /// <param name="tableState">The Table state.</param> /// <param name="collectionProperty">The serialized property of the collection.</param> /// <param name="properties">The paths (names) of the properties to display.</param> /// <param name="options">The table options.</param> public static GUITableState DrawTable( GUITableState tableState, SerializedProperty collectionProperty, List <string> properties, params GUITableOption[] options) { List <SelectorColumn> columns = properties.Select(prop => (SelectorColumn) new SelectFromPropertyNameColumn( prop, ObjectNames.NicifyVariableName(prop))).ToList(); return(DrawTable(tableState, collectionProperty, columns, options)); }
public static void DrawHeaders( Rect rect, GUITableState tableState, List <TableColumn> columns, float currentX, float currentY) { tableState.RightClickMenu(columns, rect); for (int i = 0; i < columns.Count; i++) { TableColumn column = columns[i]; if (!tableState.columnVisible [i]) { continue; } string columnName = column.title; if (tableState.sortByColumnIndex == i) { if (tableState.sortIncreasing) { columnName += " " + '\u25B2'.ToString(); } else { columnName += " " + '\u25BC'.ToString(); } } GUI.enabled = true; tableState.ResizeColumn(i, currentX, rect); GUI.enabled = column.entry.enabledTitle; if (GUI.Button(new Rect(currentX, currentY, tableState.columnSizes[i] + 4, EditorGUIUtility.singleLineHeight), columnName, EditorStyles.miniButtonMid) && column.entry.isSortable) { if (tableState.sortByColumnIndex == i && tableState.sortIncreasing) { tableState.sortIncreasing = false; } else if (tableState.sortByColumnIndex == i && !tableState.sortIncreasing) { tableState.sortByColumnIndex = -1; } else { tableState.sortByColumnIndex = i; tableState.sortIncreasing = true; } } currentX += tableState.columnSizes[i] + 4f; } }
/// <summary> /// Initializes a <see cref="EditorGUITable.GUITableState"/> with a key to save it in EditorPrefs. /// This constructor can't be used in ScriptableObject's constructor or in the property's declaration, /// because it uses the EditorPrefs. Use it in OnEnable or Awake instead. /// </summary> /// <param name="prefsKey">Prefs key.</param> public GUITableState(string prefsKey) { this.prefsKey = prefsKey; GUITableState loadedState = Load(prefsKey); this.scrollPos = loadedState.scrollPos; this.sortByColumnIndex = loadedState.sortByColumnIndex; this.sortIncreasing = loadedState.sortIncreasing; this.columnSizes = loadedState.columnSizes; this.columnVisible = loadedState.columnVisible; }
/// <summary> /// Draw a table using just the paths of the properties to display. /// This will create columns automatically using the property name as title, and will create /// PropertyCell instances for each element. /// </summary> /// <returns>The updated table state.</returns> /// <param name="tableState">The Table state.</param> /// <param name="collectionProperty">The serialized property of the collection.</param> /// <param name="properties">The paths (names) of the properties to display.</param> /// <param name="options">The table options.</param> public static GUITableState DrawTable( GUITableState tableState, SerializedProperty collectionProperty, List <string> properties, params GUITableOption[] options) { List <SelectorColumn> columns = ParsingHelpers.ParseColumns(properties); if (SerializationHelpers.IsObjectReferencesCollection(collectionProperty)) { columns.Insert(0, new SelectObjectReferenceColumn()); } return(DrawTable(tableState, collectionProperty, columns, options)); }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (!IsFirstElementQuickCheck(property.propertyPath)) { if (!IsCollectionQuickCheck(property.propertyPath)) { DrawNotACollectionMessage(position, property, label); return; } return; } string collectionPath, index; if (!IsCollectionFullCheck(property.propertyPath, out index, out collectionPath)) { DrawNotACollectionMessage(position, property, label); return; } if (index != "0") { return; } // Sometimes GetLastRect returns 0, so we keep the last relevant value if (GUILayoutUtility.GetLastRect().width > 1f) { lastRect = GUILayoutUtility.GetLastRect(); } SerializedProperty collectionProperty = property.serializedObject.FindProperty(collectionPath); EditorGUI.indentLevel = 0; Rect r = new Rect(position.x + 15f, position.y, position.width - 15f, lastRect.height); TableAttribute tableAttribute = (TableAttribute)attribute; tableState = DrawTable(r, collectionProperty, label, tableAttribute); }
/// <summary> /// Draw a table just from the collection's property. /// This will create columns for all the visible members in the elements' class, /// similar to what Unity would show in the classic vertical collection display, but as a table instead. /// </summary> /// <returns>The updated table state.</returns> /// <param name="tableState">The Table state.</param> /// <param name="collectionProperty">The serialized property of the collection.</param> /// <param name="options">The table options.</param> public static GUITableState DrawTable( GUITableState tableState, SerializedProperty collectionProperty, params GUITableOption[] options) { List <string> properties = SerializationHelpers.GetElementsSerializedFields(collectionProperty); if (properties == null && collectionProperty.arraySize == 0) { DrawTable( null, new List <TableColumn> () { new TableColumn(TableColumn.Title(collectionProperty.displayName + "(properties unknown, add at least 1 element)"), TableColumn.Sortable(false), TableColumn.Resizeable(false)) }, new List <List <TableCell> > (), collectionProperty, options); return(tableState); } return(DrawTable(tableState, collectionProperty, properties, options)); }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { TableAttribute tableAttribute = (TableAttribute)attribute; //Check that it is a collection Match match = Regex.Match(property.propertyPath, "^([a-zA-Z0-9_]*).Array.data\\[([0-9]*)\\]$"); if (!match.Success) { EditorGUI.LabelField(position, label.text, "Use the Table attribute with a collection."); return; } string collectionPath = match.Groups[1].Value; // Check that it's the first element string index = match.Groups[2].Value; if (index != "0") { return; } // Sometimes GetLastRect returns 0, so we keep the last relevant value if (GUILayoutUtility.GetLastRect().width > 1f) { lastRect = GUILayoutUtility.GetLastRect(); } SerializedProperty collectionProperty = property.serializedObject.FindProperty(collectionPath); EditorGUI.indentLevel = 0; Rect r = new Rect(position.x + 15f, position.y, position.width - 15f, lastRect.height); tableState = DrawTable(r, collectionProperty, label, tableAttribute); }
/// <summary> /// Draw a table completely manually. /// Each cell has to be created and given as parameter in cells. /// </summary> /// <returns>The updated table state.</returns> /// <param name="rect">The table's containing rectangle.</param> /// <param name="tableState">The Table state.</param> /// <param name="columns">The Columns of the table.</param> /// <param name="cells">The Cells as a list of rows.</param> /// <param name="collectionProperty">The SerializeProperty of the collection. This is useful for reorderable tables.</param> /// <param name="options">The table options.</param> public static GUITableState DrawTable( Rect rect, GUITableState tableState, List <TableColumn> columns, List <List <TableCell> > cells, SerializedProperty collectionProperty, params GUITableOption[] options) { GUITableEntry tableEntry = new GUITableEntry(options); if (tableState == null) { tableState = new GUITableState(); } if (tableEntry.reorderable) { if (collectionProperty == null) { Debug.LogError("The collection's serialized property is needed to draw a reorderable table."); return(tableState); } staticCells = cells; if (tableState.reorderableList == null) { ReorderableList list = new ReorderableList( collectionProperty.serializedObject, collectionProperty, true, true, true, true); list.drawElementCallback = (Rect r, int index, bool isActive, bool isFocused) => { DrawLine(tableState, columns, orderedRows[index], r.xMin + (list.draggable ? 0 : 14), r.yMin, tableEntry.rowHeight); }; list.elementHeight = tableEntry.rowHeight; list.drawHeaderCallback = (Rect r) => { DrawHeaders(r, tableState, columns, r.xMin + 12, r.yMin); }; list.onRemoveCallback = (l) => { l.serializedProperty.DeleteArrayElementAtIndex(staticCells.IndexOf(orderedRows[l.index])); }; tableState.SetReorderableList(list); } } tableState.CheckState(columns, tableEntry, rect.width); orderedRows = cells; if (tableState.sortByColumnIndex >= 0) { if (tableState.sortIncreasing) { orderedRows = cells.OrderBy(row => row [tableState.sortByColumnIndex]).ToList(); } else { orderedRows = cells.OrderByDescending(row => row [tableState.sortByColumnIndex]).ToList(); } } if (tableEntry.reorderable) { tableState.reorderableList.DoList(new Rect(rect.x, rect.y, tableState.totalWidth + 23f, rect.height)); collectionProperty.serializedObject.ApplyModifiedProperties(); return(tableState); } float rowHeight = tableEntry.rowHeight; float currentX = rect.x; float currentY = rect.y + 5; bool displayScrollView = tableState.totalWidth > rect.width && tableEntry.allowScrollView; tableState.RightClickMenu(columns, rect); DrawHeaders(rect, tableState, columns, currentX - tableState.scrollPos.x, currentY); GUI.enabled = true; currentY += EditorGUIUtility.singleLineHeight; if (tableEntry.allowScrollView) { tableState.scrollPos = GUI.BeginScrollView( new Rect(currentX, currentY, rect.width, TableHeight(tableEntry, cells.Count)), tableState.scrollPos, new Rect(0f, 0f, tableState.totalWidth, tableEntry.rowHeight * cells.Count)); currentX = 0f; currentY = 0f; } if (orderedRows.Count == 0) { currentX = tableEntry.allowScrollView ? 0 : rect.x; GUIHelpers.DrawRect(new Rect(currentX, currentY, tableState.totalWidth, rowHeight), TABLE_BG_COLOR); GUI.Label(new Rect(currentX + 5, currentY, rect.width, rowHeight), "Collection is empty"); } else { foreach (List <TableCell> row in orderedRows) { currentX = tableEntry.allowScrollView ? 0 : rect.x; DrawLine(tableState, columns, row, currentX, currentY, rowHeight); currentY += rowHeight; } } GUI.enabled = true; if (tableEntry.allowScrollView) { GUI.EndScrollView(); } tableState.Save(); return(tableState); }
public static void DrawHeaders( Rect rect, GUITableState tableState, List <TableColumn> columns, float currentX, float currentY, bool rotated = false) { tableState.RightClickMenu(columns, rect); for (int i = 0; i < columns.Count; i++) { TableColumn column = columns[i]; if (!tableState.columnVisible [i]) { continue; } string columnName = column.entry.title; if (tableState.sortByColumnIndex == i) { if (tableState.sortIncreasing) { columnName += " " + '\u25B2'.ToString(); } else { columnName += " " + '\u25BC'.ToString(); } } GUI.enabled = true; if (!rotated) { tableState.ResizeColumn(columns, i, currentX, rect); } GUI.enabled = column.entry.enabledTitle; Rect headerRect = new Rect(currentX, currentY, tableState.absoluteColumnSizes[i] + 4, EditorGUIUtility.singleLineHeight); GUIStyle buttonStyle = new GUIStyle(EditorStyles.miniButtonMid); Matrix4x4 matrix = GUI.matrix; if (rotated) { Vector2 pivot = new Vector2(headerRect.center.x, headerRect.center.y); GUIUtility.RotateAroundPivot(-45f, pivot); buttonStyle.normal.background = null; buttonStyle.active.background = null; buttonStyle.alignment = TextAnchor.MiddleLeft; headerRect = new Rect(headerRect.center.x - 10f, headerRect.min.y, buttonStyle.CalcSize(new GUIContent(columnName)).x, headerRect.height); } if (GUI.Button(headerRect, columnName, buttonStyle) && column.entry.isSortable) { if (tableState.sortByColumnIndex == i && tableState.sortIncreasing) { tableState.sortIncreasing = false; } else if (tableState.sortByColumnIndex == i && !tableState.sortIncreasing) { tableState.sortByColumnIndex = -1; } else { tableState.sortByColumnIndex = i; tableState.sortIncreasing = true; } } if (rotated) { GUI.matrix = matrix; } currentX += tableState.absoluteColumnSizes[i] + 4f; } }