I have a generic custom class SerializableMatrix that I made a custom property drawer for so that I can display 2D arrays as matrices in the inspector. Like this: [197683-matrixdisplay.png*|197683]
Now, I also want to implement an attribute BigBoolAttribute, that makes the booleans more clear in the inspector by making them slightly bigger and toggle green color. This way it would be easier to fill out many arrays of booleans instead of misclicking tiny checkboxes. I want to be able to get the following result:
[197684-howiwantit.png*|197684]
where clicking a square will turn it green. This by using the code:
[BigBool(40)]
public SerializableMatrix<bool> toDisplay = new SerializableMatrix<bool>(4,4);
The problem
When using an attribute it overrides the propertydrawer of SerializableMatrix, causing the matrix not to be drawn in the inspector, since the attribute works on the whole SerializableMatrix instead of the booleans in this SerializableMatrix. Instead I just get one of my custom boolean squares.
I would love for there to be a way to make the attribute basically act as if it was applied to just booleans that come along the way instead of the variable applied on: Use the original way of drawing the property, but for every property of type boolean we find in this class, we can change the drawing.
Attempted and considered solutions
- Instead of making an attribute, I can change the property drawer for bool types. This way, it indeed finds the booleans appearing in SerializableMatrix and replaces them with the custom way of drawing without messing up how the 2D arrays are drawn, so the way I want it. However, this will then be applied to all booleans, and I would need a NormalBoolAttribute everytime I want a normally drawn boolean which is not preferred. Furthermore, I can not pass a size parameter anymore as is possible with the attribute.
- I can not put the attribute in the SerializableMatrix class, because this is a generic class and it might be that there are no booleans used, causing errors (unless I could somehow put a check on the type before applying the attribute, however you can not put attributes in if statements)
- Decoration drawers can use multiple drawers in different orders. However as I understand it it does not give access to the property itself so I can not change the things needed to draw the boolean as I want since I will need the button presses to change the value of the boolean property.
- Making a separate class for SerializableBoolMatrix and write a slightly different propertydrawer. This would work however I don’t think it is a very clean solution.
- Trying to see if EditorGUI.PropertyField() can be changed in behaviour for certain types. However I could not find any documentation about this.
- Would there be some way to use [CustomPropertyDrawer(typeof())] pass the combination of being a boolean and having the attribute?
Thank you for your time and any reactions, I inserted the code below if this could be of help in clarifying the setup that I am using.
I am also open to alternative ways that get a result that works differently than what I have in mind, as long as it makes it easier filling out many 2D boolean matrices and spotting potential mistakes.
SerializableMatrix.cs
[System.Serializable]
public class SerializableMatrix<TValue>
{
public RowData[] rows;
[System.Serializable]
public class RowData
{
public TValue[] columns;
public RowData(int y)
{
columns = new TValue[y];
}
}
public SerializableMatrix(int x, int y)
{
rows = new RowData[x];
for (int i = 0; i < x; i++)
{
rows *= new RowData(y);*
}
}
}
SerializableMatrixPropertyDrawer.cs
[CustomPropertyDrawer(typeof(SerializableMatrix<>))]
public class SerializableMatrixPropertyDrawer : PropertyDrawer
{
private SerializedProperty rows;
private SerializedProperty columns;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (rows == null)
{
rows = property.FindPropertyRelative(“rows”);
}
float height = EditorGUIUtility.singleLineHeight;
if (property.isExpanded)
{
for (int i = 0; i < rows.arraySize; i++)
{
height += EditorGUI.GetPropertyHeight(rows.GetArrayElementAtIndex(i).FindPropertyRelative(“columns”).GetArrayElementAtIndex(0));
}
}
return height;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (rows == null)
{
rows = property.FindPropertyRelative(“rows”);
}
EditorGUI.BeginProperty(position, label, property);
Rect foldoutRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, label);
EditorGUI.indentLevel++;
if (property.isExpanded)
{
float addY = EditorGUIUtility.singleLineHeight;
for (int i = 0; i < rows.arraySize; i++)
{
columns = rows.GetArrayElementAtIndex(i).FindPropertyRelative(“columns”);
float addX = 0;
//EditorGUILayout.BeginHorizontal();
for (int j = 0; j < columns.arraySize; j++)
{
Rect rect = new Rect(position.x + addX, position.y + addY, EditorGUIUtility.fieldWidth, EditorGUI.GetPropertyHeight(columns.GetArrayElementAtIndex(j)));
EditorGUI.PropertyField(rect, columns.GetArrayElementAtIndex(j), GUIContent.none);
addX += rect.width;
}
//EditorGUILayout.EndHorizontal();
addY += EditorGUI.GetPropertyHeight(columns.GetArrayElementAtIndex(0));
}
}
EditorGUI.indentLevel–;
EditorGUI.EndProperty();
}
}
BigBoolAttribute.cs
public class BigBoolAttribute : PropertyAttribute
{
public readonly int size;
public BigBoolAttribute(int size)
{
this.size = size;
}
}
BigBoolDrawer.cs
[CustomPropertyDrawer(typeof(BigBoolAttribute))]
public class BigBoolDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return 60; //change this to retrieve size from attribute
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if(GUI.Button(position, “”))
{
Debug.Log(“Button pressed”);
}
}
}
*
*