private var _worldVelocity : Vector3;
public function get worldVelocity () : Vector3 { return _worldVelocity; }
private function set worldVelocity (value : Vector3) { _worldVelocity = value;
This is the end-all answer - it will allow you to mark -any- field as readonly with a single property attribute / property drawer. It’s partially based on scottmontgomerie’s answer. This version also dispatches the property height based on how “expanded” the property is.
public class ReadOnlyAttribute : PropertyAttribute
{
}
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
public class ReadOnlyDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property,
GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label, true);
}
public override void OnGUI(Rect position,
SerializedProperty property,
GUIContent label)
{
GUI.enabled = false;
EditorGUI.PropertyField(position, property, label, true);
GUI.enabled = true;
}
}
public class Test
{
[ReadOnly] public string a;
[ReadOnly] public int b;
[ReadOnly] public Material c;
[ReadOnly] public List<int> d = new List<int>();
}
The solution posted by @It3ration does not work with fields that already have a CustomPropertyDrawer.
.
Using the ReadOnly attribute will cause the field to be displayed with the default property drawer instead of the custom property drawer.
.
This solution expands on the solution by @It3ration to add 2 new attributes ( BeginReadOnlyAttribute and EndReadOnlyAttribute ) so that any fields in between the two attribute tags will be read-only. Using this method will allow CustomPropertyDrawers to work. The important part is that the new attributes use DecoratorDrawers instead of a PropertyDrawer.
.
For convenience, the ReadOnlyAttribute is also implemented but will only work for a single field with a default property drawer.
.
ReadOnlyAttribute.cs (MUST NOT be in Editor folder)
Using UnityEngine;
/// <summary>
/// Display a field as read-only in the inspector.
/// CustomPropertyDrawers will not work when this attribute is used.
/// </summary>
/// <seealso cref="BeginReadOnlyGroupAttribute"/>
/// <seealso cref="EndReadOnlyGroupAttribute"/>
public class ReadOnlyAttribute : PropertyAttribute { }
/// <summary>
/// Display one or more fields as read-only in the inspector.
/// Use <see cref="EndReadOnlyGroupAttribute"/> to close the group.
/// Works with CustomPropertyDrawers.
/// </summary>
/// <seealso cref="EndReadOnlyGroupAttribute"/>
/// <seealso cref="ReadOnlyAttribute"/>
public class BeginReadOnlyGroupAttribute : PropertyAttribute { }
/// <summary>
/// Use with <see cref="BeginReadOnlyGroupAttribute"/>.
/// Close the read-only group and resume editable fields.
/// </summary>
/// <seealso cref="BeginReadOnlyGroupAttribute"/>
/// <seealso cref="ReadOnlyAttribute"/>
public class EndReadOnlyGroupAttribute : PropertyAttribute { }
ReadOnlyDrawer.cs (MUST be in Editor folder)
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer( typeof( ReadOnlyAttribute ) )]
public class ReadOnlyDrawer : PropertyDrawer {
public override float GetPropertyHeight( SerializedProperty property, GUIContent label ) {
return EditorGUI.GetPropertyHeight( property, label, true );
}
public override void OnGUI( Rect position, SerializedProperty property, GUIContent label ) {
using (var scope = new EditorGUI.DisabledGroupScope(true)) {
EditorGUI.PropertyField( position, property, label, true );
}
}
}
[CustomPropertyDrawer( typeof( BeginReadOnlyGroupAttribute ) )]
public class BeginReadOnlyGroupDrawer : DecoratorDrawer {
public override float GetHeight() { return 0; }
public override void OnGUI( Rect position ) {
EditorGUI.BeginDisabledGroup( true );
}
}
[CustomPropertyDrawer( typeof( EndReadOnlyGroupAttribute ) )]
public class EndReadOnlyGroupDrawer : DecoratorDrawer {
public override float GetHeight() { return 0; }
public override void OnGUI( Rect position ) {
EditorGUI.EndDisabledGroup();
}
}
Example.cs
using UnityEngine;
public class ReadOnlyExample : MonoBehaviour {
[BeginReadOnlyGroup] // tag a group of fields as ReadOnly
public string a;
public int b;
public Material c;
public List<int> d = new List<int>();
public CustomTypeWithPropertyDrawer e; // Works!
[EndReadOnlyGroup]
[ReadOnly] public string a2;
[ReadOnly] public CustomTypeWithPropertyDrawer e2; // DOES NOT USE CustomPropertyDrawer!
[BeginReadOnlyGroup]
public int b2;
public Material c2;
public List<int> d2 = new List<int>();
// Attribute tags apply to the next field of which there are no more so Unity/C# complains.
// Since there are no more fields, we can omit the closing tag.
// [EndReadOnlyGroup]
}
If you just want to see the value of a variable without being able to edit, it’s good enough to just leave it private and then put the Inspector in Debug Mode
The solution provided by @Lev-Lukomskyi worked for me!!
I was missing some things though so I added them, for anyone wondering how to do these here they are.
Here is an option in case you want to be able to edit values in the inspector but then have the resulting class/struct be readonly later. Here’s an example of a Translation, Rotation, Scale struct. I’m using the Unity.Mathematics package btw. The idea here is that you create a readonly class/struct and then have a public nested class/struct marked serializable which has an implicit operator to return the readonly version you want in the end.
public readonly struct TRS
{
public float3 Translation { get; }
public quaternion Rotation { get; }
public float3 Scale { get; }
public float4x4 Matrix => float4x4.TRS(Translation, Rotation, Scale);
public TRS(float3 translation, quaternion rotation, float3 scale)
{
Translation = translation;
Rotation = rotation;
Scale = scale;
}
public TRS(float3 translation, float3 rotationDegrees, float3 scale)
{
Translation = translation;
Rotation = quaternion.Euler(rotationDegrees);
Scale = scale;
}
[System.Serializable]
public struct InspectorVersion
{
public float3 translation;
public float3 rotationDegrees;
public float3 scale;
public static implicit operator TRS(InspectorVersion i)
{
return new TRS(i.translation, i.rotationDegrees, i.scale);
}
}
}
public class ExampleBehaviour : MonoBehaviour
{
public TRS.InspectorVersion trs;
public void Start()
{
TRS t = trs;
}
}