- Home /
property drawer for enum + two other attributes
hi everyone, i have a class like this :
using UnityEngine;
using System;
[System.Serializable]
public class ScaledCurve
{
public float Speed = 1;
public Animation Animation;
//public int FPS;
public AnimationFPS FPS;
}
public enum AnimationFPS { WEB = 15, Film = 24, PAL = 25, NTSC = 30, HDTV = 60, UHDTV = 120 }
now, i'm writing a drawer for it in unity 4 but : i can't make the enum show properly, and, i want the float slider show in one line then go to next vertical line and show the other stuff there, here is what i tried till now : using UnityEngine; using UnityEditor; using System;
[CustomPropertyDrawer(typeof(ScaledCurve))]
public class ScaledCurveDrawer : PropertyDrawer
{
const int curveWidth = 50;
const float min = 0.1f;
const float max = 10;
const int fmin = 15;
const int fmax = 120;
const int animFieldWidth = 120;
private const int FPSWidth = 70;
private float wid;
public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
{
SerializedProperty speed = prop.FindPropertyRelative("Speed");
SerializedProperty anim = prop.FindPropertyRelative("Animation");
SerializedProperty fps = prop.FindPropertyRelative("fps");
EditorGUILayout.BeginVertical();
EditorGUILayout.BeginHorizontal();
// Draw Speed
EditorGUI.Slider(
new Rect(pos.x, pos.y, pos.width, pos.height),
speed, min, max, label);
// Draw FPS
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
//EditorGUI.PropertyField(
// new Rect(pos.width - (animFieldWidth) - FPSWidth, pos.y, FPSWidth, pos.height), fps);
EditorGUI.Popup(
new Rect(3, 3, pos.width - 6, 15),
"FPS",3,
fps.enumNames);
EditorGUI.indentLevel++;
// Draw Animation Field
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField(
new Rect(pos.width - animFieldWidth, pos.y, animFieldWidth, pos.height),
anim, GUIContent.none);
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
}
now, the problem is like this : 1- begin horizontal and vertical gives error 2- the editorGUI.propertyField is not what i'm looking for, EditorGUI.EnumPopup is looking for an enum and i can't use the serialized fps variable that i'm defining
can anyone help on these? also i saw this page : [blog post about property drawer] [1]: http://blogs.unity3d.com/2012/09/07/property-drawers-in-unity-4/
would be nice if someone can write those [Popup] and [Angle] functions and share with us
thanks for help
Answer by Jiraiyah · Mar 09, 2013 at 07:46 PM
heh i just found the solution, anyway, i put it together just in case anyone has some problem like this : 1- first you need a public enum as i had in the serializable class :
using UnityEngine;
using System;
[System.Serializable]
public class AnimationClass
{
public float Speed = 1;
public Animation Animation;
//public int FPS;
public AnimationFPS FPS;
}
public enum AnimationFPS { WEB = 15, Film = 24, PAL = 25, NTSC = 30, HDTV = 60, UHDTV = 120 }
2- now you need to address it in the drawer class like this :
using UnityEngine;
using UnityEditor;
using System;
[CustomPropertyDrawer(typeof(AnimationClass))]
public class AnimationClassDrawer : PropertyDrawer
{
const float min = 0.1f; // this is the minimum number for the float slider of speed
const float max = 10; // this is the maximum number for the float slider of speed
const int ControlHeight = 16; // this is the height of each control line
// we check if we are adding a new class to the inspector gui, if so, we add the control height
// so that the next control goes bellow of our second line of previous control
public override float GetPropertyHeight(SerializedProperty prop,
GUIContent label)
{
return base.GetPropertyHeight(prop, label) + ControlHeight;
}
public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
{
// we go one indent inside to make things nicer
EditorGUI.indentLevel = 1;
// we find the same Speed float of the animationClass
SerializedProperty speed = prop.FindPropertyRelative("Speed");
// we find the same Animation variable on animationClass
SerializedProperty anim = prop.FindPropertyRelative("Animation");
// we check for any change on GUI
EditorGUI.BeginChangeCheck();
// Draw Speed slider
EditorGUI.Slider(new Rect(pos.x, pos.y, pos.width, 15),
speed, min, max, label);
// Now add a lable beside slider so that we know what it do
EditorGUI.LabelField(new Rect(pos.x +pos.width /2 - 65, pos.y, 60, pos.height), "Speed :");
//define a new rect
Rect ExtraPosition = EditorGUI.IndentedRect(pos);
// now we want to put things in second line
ExtraPosition.y += ControlHeight;
ExtraPosition.height = ControlHeight+5;
// now we can add the other stuff here but to make it simpler and more coder friendly
// for future, i put them in another method
DrawAnimControls(ExtraPosition, anim, prop,label);
}
void DrawAnimControls(Rect position, SerializedProperty prop1, SerializedProperty fps, GUIContent label)
{
// we check if things changed
EditorGUI.BeginChangeCheck();
// we need to devide the width of inspector gui to 2, so that we can add 2 fields there
position.width = position.width /2 ;
// Draw Animation Field
EditorGUI.PropertyField(
position,
prop1, GUIContent.none);
position.x += position.width ;
// now we add another label so that we know what the enum is about
EditorGUI.LabelField(new Rect(position.x, position.y, 50, position.height), "FPS :");
// and finally we add the enum to GUI
// remember that you can't address the enum variable of animClass directly,
// but if you defiend a variable of type of that enum, then you can search for the
// name of that variable, here i had : "public AnimationFPS FPS"
// and with using "fps.FindPropertyRelative("FPS")" i can find that variable
// and make a property field for that !
EditorGUI.PropertyField(new Rect(position.x+55, position.y, position.width-55, position.height), fps.FindPropertyRelative("FPS"), GUIContent.none);
}
}
remember, i wanted to have the slider in first line and the rest in second line, hence the reason i added that Control Height at GetPropertyHeight method
at the end, i should say that unity document was helpful, but i got the idea of changing height for the lines from the link of the blog post i sent before i hope it helps others like me that had this issue now the only thing i want is to find a way to remake the same [Popup] functionality i saw in that blog post, but i think it's out of my current experiance so can anyone help? have fun
Answer by Ashkan_gc · Aug 31, 2015 at 10:06 AM
here it is an implementation attributed to Gamajun studio (my employer) with an MIT license to use Here is the drawer
//(C) Gamajun s.r.o with M.I.T license
//http://opensource.org/licenses/MIT
using UnityEngine;
using System.Collections;
using UnityEditor;
namespace Our
{
[CustomPropertyDrawer(typeof(PopUpAttribute))]
public class PopUpPropertyDrawer : PropertyDrawer
{
private int index = 0;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
PopUpAttribute items = attribute as PopUpAttribute;
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
if (property.propertyType == SerializedPropertyType.String)
{
var prevIndex = index;
index = EditorGUI.Popup(position, property.displayName, index, items.items);
if (prevIndex != index)
{
property.stringValue = items.items[index];
}
}
else
EditorGUI.LabelField(position, label.text, "Use PopUp for strings.");
}
}
}
And here is the attribute
//(C) Gamajun s.r.o M.I.T license
//http://opensource.org/licenses/MIT
using UnityEngine;
using System.Collections;
namespace Our
{
public class PopUpAttribute : PropertyAttribute
{
public string[] items;
public PopUpAttribute(params string[] args)
{
items = args;
}
}
}
You should not set param argument "args" in PopUpAttribute as object[] but string[].
This will avoid boxing and unwanted null or cast exception. $$anonymous$$oreover, the compiler will prevent those errors.
Edit: Now you are good to go =D
Yes for sure, Internally I wanted to make this more flexible and add more types but shared too fast, It's what I get for hurrying up at sharing.
Yes for sure, Internally I wanted to make this more flexible and add more types but shared too fast, It's what I get for hurrying up at sharing. Type safety is a great thing and I actually don't like dynamic languages at all.
In fact, you could have use param object[], but ins$$anonymous$$d of casting "as string" you should have used ToString when the element is not null. It works too.
First of all I forgot to mention that no boxing operation would happen since both object and string are reference types, boxing is the operation of wrapping a value type inside a reference type. Well it could be done using ToString or maybe a few more methods but it wasn't my intention and it was none required work.
Your answer
Follow this Question
Related Questions
Material doesn't have a color property '_Color' 4 Answers
Unity Property Drawer - Making more space 2 Answers
Simple question about Guitext 1 Answer