#if UNITY_EDITOR using UnityEditor; using UnityEngine; [CustomPropertyDrawer(typeof(ShapeScannerConfiguration))] public class BoolMatrixDrawer : PropertyDrawer { private const float ToggleSize = 18f; private const float RowLabelWidth = 24f; private const float Padding = 2f; public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { var rowsProp = property.FindPropertyRelative("rows"); var columnsProp = property.FindPropertyRelative("columns"); int rows = rowsProp != null ? rowsProp.arraySize : 0; int cols = Mathf.Max(0, columnsProp != null ? columnsProp.intValue : 0); // Header (one line), columns field (one line), buttons (one line), then one line per row int totalLines = 1 + 1 + 1 + Mathf.Max(1, rows); float lineHeight = EditorGUIUtility.singleLineHeight + Padding; return totalLines * lineHeight + Padding; } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); var rowsProp = property.FindPropertyRelative("rows"); var columnsProp = property.FindPropertyRelative("columns"); if (rowsProp == null || columnsProp == null) { EditorGUI.HelpBox(position, "BoolMatrix is missing 'rows' or 'columns' properties.", MessageType.Error); EditorGUI.EndProperty(); return; } // Layout helper float lineHeight = EditorGUIUtility.singleLineHeight; Rect line = new Rect(position.x, position.y, position.width, lineHeight); // Header EditorGUI.LabelField(line, label, EditorStyles.boldLabel); line.y += lineHeight + Padding; // Draw requiredCorrectPercentage var requiredCorrectProp = property.FindPropertyRelative("requiredCorrectPercentage"); EditorGUI.PropertyField(line, requiredCorrectProp, new GUIContent("Required Correct Percentage")); line.y += lineHeight + Padding; // Columns field EditorGUI.BeginChangeCheck(); int cols = Mathf.Max(0, EditorGUI.IntField(line, "Columns", columnsProp.intValue)); if (EditorGUI.EndChangeCheck()) { columnsProp.intValue = cols; // Resize each row to match new column count for (int r = 0; r < rowsProp.arraySize; r++) { var rowProp = rowsProp.GetArrayElementAtIndex(r); var cellsProp = rowProp.FindPropertyRelative("cells"); ResizeBoolArray(cellsProp, cols); } } line.y += lineHeight + Padding; // Row controls (Add/Remove) using (new EditorGUI.IndentLevelScope()) { Rect left = new Rect(line.x, line.y, 120, lineHeight); if (GUI.Button(left, "Add Row")) { int newIndex = rowsProp.arraySize; rowsProp.InsertArrayElementAtIndex(newIndex); var rowProp = rowsProp.GetArrayElementAtIndex(newIndex); var cellsProp = rowProp.FindPropertyRelative("cells"); ResizeBoolArray(cellsProp, columnsProp.intValue); } Rect right = new Rect(line.x + 130, line.y, 140, lineHeight); if (GUI.Button(right, "Remove Last Row") && rowsProp.arraySize > 0) { rowsProp.DeleteArrayElementAtIndex(rowsProp.arraySize - 1); } } line.y += lineHeight + Padding; // Draw grid int rowCount = rowsProp.arraySize; int colCount = Mathf.Max(0, columnsProp.intValue); for (int r = 0; r < rowCount; r++) { var rowProp = rowsProp.GetArrayElementAtIndex(r); var cellsProp = rowProp.FindPropertyRelative("cells"); // Ensure row width if (cellsProp.arraySize != colCount) ResizeBoolArray(cellsProp, colCount); // Row label Rect rowLabel = new Rect(line.x, line.y, RowLabelWidth, lineHeight); EditorGUI.LabelField(rowLabel, $"R{r}"); // Toggle strip float startX = rowLabel.x + RowLabelWidth + Padding; for (int c = 0; c < colCount; c++) { Rect toggleRect = new Rect(startX + c * (ToggleSize + 2), line.y, ToggleSize, lineHeight); var cellProp = cellsProp.GetArrayElementAtIndex(c); bool newVal = EditorGUI.Toggle(toggleRect, GUIContent.none, cellProp.boolValue); if (newVal != cellProp.boolValue) cellProp.boolValue = newVal; } line.y += lineHeight + Padding; } EditorGUI.EndProperty(); } private void ResizeBoolArray(SerializedProperty listProp, int newSize) { if (listProp == null) return; newSize = Mathf.Max(0, newSize); // Grow while (listProp.arraySize < newSize) { int i = listProp.arraySize; listProp.InsertArrayElementAtIndex(i); var elem = listProp.GetArrayElementAtIndex(i); elem.boolValue = false; } // Shrink while (listProp.arraySize > newSize) { listProp.DeleteArrayElementAtIndex(listProp.arraySize - 1); } } } #endif