using UnityEngine; using UnityEditor; using System.Reflection; namespace NaughtyAttributes.Editor { [CustomPropertyDrawer(typeof(ProgressBarAttribute))] public class ProgressBarPropertyDrawer : PropertyDrawerBase { protected override float GetPropertyHeight_Internal(SerializedProperty property, GUIContent label) { ProgressBarAttribute progressBarAttribute = PropertyUtility.GetAttribute(property); var maxValue = GetMaxValue(property, progressBarAttribute); return IsNumber(property) && IsNumber(maxValue) ? GetPropertyHeight(property) : GetPropertyHeight(property) + GetHelpBoxHeight(); } protected override void OnGUI_Internal(Rect rect, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(rect, label, property); if (!IsNumber(property)) { string message = string.Format("Field {0} is not a number", property.name); DrawDefaultPropertyAndHelpBox(rect, property, message, MessageType.Warning); return; } ProgressBarAttribute progressBarAttribute = PropertyUtility.GetAttribute(property); var value = property.propertyType == SerializedPropertyType.Integer ? property.intValue : property.floatValue; var valueFormatted = property.propertyType == SerializedPropertyType.Integer ? value.ToString() : string.Format("{0:0.00}", value); var maxValue = GetMaxValue(property, progressBarAttribute); if (maxValue != null && IsNumber(maxValue)) { var fillPercentage = value / CastToFloat(maxValue); var barLabel = (!string.IsNullOrEmpty(progressBarAttribute.Name) ? "[" + progressBarAttribute.Name + "] " : "") + valueFormatted + "/" + maxValue; var barColor = progressBarAttribute.Color.GetColor(); var labelColor = Color.white; var indentLength = NaughtyEditorGUI.GetIndentLength(rect); Rect barRect = new Rect() { x = rect.x + indentLength, y = rect.y, width = rect.width - indentLength, height = EditorGUIUtility.singleLineHeight }; DrawBar(barRect, Mathf.Clamp01(fillPercentage), barLabel, barColor, labelColor); } else { string message = string.Format( "The provided dynamic max value for the progress bar is not correct. Please check if the '{0}' is correct, or the return type is float/int", nameof(progressBarAttribute.MaxValueName)); DrawDefaultPropertyAndHelpBox(rect, property, message, MessageType.Warning); } EditorGUI.EndProperty(); } private object GetMaxValue(SerializedProperty property, ProgressBarAttribute progressBarAttribute) { if (string.IsNullOrEmpty(progressBarAttribute.MaxValueName)) { return progressBarAttribute.MaxValue; } else { object target = PropertyUtility.GetTargetObjectWithProperty(property); FieldInfo valuesFieldInfo = ReflectionUtility.GetField(target, progressBarAttribute.MaxValueName); if (valuesFieldInfo != null) { return valuesFieldInfo.GetValue(target); } PropertyInfo valuesPropertyInfo = ReflectionUtility.GetProperty(target, progressBarAttribute.MaxValueName); if (valuesPropertyInfo != null) { return valuesPropertyInfo.GetValue(target); } MethodInfo methodValuesInfo = ReflectionUtility.GetMethod(target, progressBarAttribute.MaxValueName); if (methodValuesInfo != null && (methodValuesInfo.ReturnType == typeof(float) || methodValuesInfo.ReturnType == typeof(int)) && methodValuesInfo.GetParameters().Length == 0) { return methodValuesInfo.Invoke(target, null); } return null; } } private void DrawBar(Rect rect, float fillPercent, string label, Color barColor, Color labelColor) { if (Event.current.type != EventType.Repaint) { return; } var fillRect = new Rect(rect.x, rect.y, rect.width * fillPercent, rect.height); EditorGUI.DrawRect(rect, new Color(0.13f, 0.13f, 0.13f)); EditorGUI.DrawRect(fillRect, barColor); // set alignment and cache the default var align = GUI.skin.label.alignment; GUI.skin.label.alignment = TextAnchor.UpperCenter; // set the color and cache the default var c = GUI.contentColor; GUI.contentColor = labelColor; // calculate the position var labelRect = new Rect(rect.x, rect.y - 2, rect.width, rect.height); // draw~ EditorGUI.DropShadowLabel(labelRect, label); // reset color and alignment GUI.contentColor = c; GUI.skin.label.alignment = align; } private bool IsNumber(SerializedProperty property) { bool isNumber = property.propertyType == SerializedPropertyType.Float || property.propertyType == SerializedPropertyType.Integer; return isNumber; } private bool IsNumber(object obj) { return (obj is float) || (obj is int); } private float CastToFloat(object obj) { if (obj is int) { return (int)obj; } else { return (float)obj; } } } }