I am working on a Unity program that has a grid based system in it. I am trying to make a custom editor for the grid system, basically you can change the size of the grid, have it display a set of buttons representing the grid, and each time a button is clicked it iterates through some set of tiles.
I have most of it working, I just can't get the inspector the redraw the grid when the width/height changes. If I run the game it works, but it won't do it automatically. From what I can find it seems like recalling CreateInspectorGUI can't happen. Is there a way I can do this without using OnInspectorGUI? I am trying to stay in the UIElements system but I am not sure if I have a choice here.
My inspector code is shown below:
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
[CustomEditor(typeof(GridHolder))]
[CanEditMultipleObjects]
public class Grid_Inspector : Editor
{
SerializedProperty m_Grid_Width;
SerializedProperty m_Grid_Height;
SerializedProperty m_Grid_Size_X;
SerializedProperty m_Grid_Size_Y;
private void OnEnable()
{
m_Grid_Width = serializedObject.FindProperty("gridWidth");
m_Grid_Height = serializedObject.FindProperty("gridHeight");
m_Grid_Size_X = serializedObject.FindProperty("gridXSize");
m_Grid_Size_Y = serializedObject.FindProperty("gridYSize");
}
// public override void OnInspectorGUI()
// {
// EditorGUILayout.PropertyField(m_Grid_Width, new GUIContent("Grid Width"), GUILayout.Height(20));
// serializedObject.ApplyModifiedProperties();
// }
public override VisualElement CreateInspectorGUI()
{
VisualElement container = new VisualElement();
Label title = new Label("Grid Inspector Element");
container.Add(title);
VisualElement gridDimensions = new VisualElement();
gridDimensions.style.flexDirection = FlexDirection.Row;
PropertyField gridWidth = new PropertyField(m_Grid_Width, "Grid Dimensions (X,Y):");
PropertyField gridHeight = new PropertyField(m_Grid_Height);
gridDimensions.TrackPropertyValue(m_Grid_Width, _ => {
UnityEngine.Debug.Log("Hit");
Repaint();
});
gridDimensions.Add(gridWidth);
gridDimensions.Add(gridHeight);
VisualElement gridElementSize = new VisualElement();
gridElementSize.style.flexDirection = FlexDirection.Row;
PropertyField gridXSize = new PropertyField(m_Grid_Size_X, "Grid Size (in meters):");
PropertyField gridYSize = new PropertyField(m_Grid_Size_Y);
gridElementSize.Add(gridXSize);
gridElementSize.Add(gridYSize);
container.Add(gridDimensions);
container.Add(gridElementSize);
// // randomColorButton.style.width = new Length(50, LengthUnit.Pixel);
// // randomColorButton.style.height = new Length(50, LengthUnit.Pixel);
container.Add(DrawGrid());
return container;
}
private VisualElement CreateButton(string text, int sizeX, int sizeY)
{
Button b = new Button() { text = text };
b.style.width = new Length(sizeX, LengthUnit.Pixel);
b.style.height = new Length(sizeY, LengthUnit.Pixel);
return b;
}
private VisualElement DrawGrid()
{
VisualElement container = new VisualElement();
try
{
for(int i = 0; i < m_Grid_Height.intValue; i++)
{
VisualElement row = new VisualElement();
row.style.flexDirection = FlexDirection.Row;
for(int j = 0; j < m_Grid_Width.intValue; j++)
{
//TODO Connect this to the bool array in GridHolder
string text = true?" ":"X";
row.Add(CreateButton(text, 50, 50));
}
container.Add(row);
}
}
catch(System.Exception e)
{
UnityEngine.Debug.LogWarning(e.Message);
}
return container;
}
}
Thank you for any help you can give! Worst case I switch to the IMGUI system, but I would rather not have to do that
Instead of just calling Repaint
you would have to recreate the grid.
So you could probably do something like e.g.
public override VisualElement CreateInspectorGUI()
{
...
var gridContainer = new VisualElement();
gridDimensions.TrackPropertyValue(m_Grid_Width, _ => {
UnityEngine.Debug.Log("Hit");
DrawGrid(gridContainer);
// Afaik Repaint is only to cause a new call to OnInspectorGUI
// it shouldn't be relevant for UIElements as any change
// on the VisualElements should already cause a repaint of that container anyway
});
...
container.Add(gridContainer);
DrawGrid(gridContainer);
return container;
}
// instead of creating and returning the container rather just
// take a container as parameter and generate the grid into it
private VisualElement DrawGrid(VisualElement container)
{
// remove any previous content
container.Clear();
...
}
so instead of creating the grid only once in CreateInspectorGUI
you recreate it every time the size is modified, passing in the root container you want to place it in.