public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            DisplayTimeSpanAttribute timeSpanAttribute = attribute as DisplayTimeSpanAttribute;

            Rect valuesRect = DisplayLabel(position, label);

            TimeSpanDisplayMode displayMode = timeSpanAttribute.DisplayMode;

            EditorGUI.indentLevel++;
            Rect indentedValuesRect = EditorGUI.IndentedRect(valuesRect);

            EditorGUI.indentLevel--;

            switch (displayMode)
            {
            case TimeSpanDisplayMode.SingleMode:
                DisplayTimeSpanWithSingleUnit(indentedValuesRect, property, timeSpanAttribute);
                break;

            case TimeSpanDisplayMode.SingleModeSelectable:
                DisplayTimeSpanWithSelectableUnit(indentedValuesRect, property, timeSpanAttribute);
                break;

            case TimeSpanDisplayMode.ColumnMode:
            default:
                DisplayTimeSpanAsColumns(indentedValuesRect, property, timeSpanAttribute);
                break;
            }
        }
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            DisplayTimeSpanAttribute displayAttribute = attribute as DisplayTimeSpanAttribute;

            TimeSpanDisplayMode displayMode = displayAttribute.DisplayMode;

            switch (displayMode)
            {
            case TimeSpanDisplayMode.SingleMode:
            case TimeSpanDisplayMode.SingleModeSelectable:
                return(EditorGUIUtility.singleLineHeight * 2f);

            case TimeSpanDisplayMode.ColumnMode:
            default:
                return(EditorGUIUtility.singleLineHeight * 3f);
            }
        }
        /// <summary>
        /// Renders the time span data as a float field with a drop-down to select the time unit (milliseconds, seconds, minutes, hours)
        /// </summary>
        /// <param name="position">The rectangle depicting the available render area</param>
        /// <param name="property">The property containing the float value to be displayed as a time span</param>
        /// <param name="displayTimeSpanAttribute">The attribute that identifies the float as a time span value</param>
        /// <returns>A rectangle depicting the remaining available area</returns>
        protected virtual Rect DisplayTimeSpanWithSingleUnit(Rect position, SerializedProperty property, DisplayTimeSpanAttribute displayTimeSpanAttribute)
        {
            TimeSpan propertyTimeSpanValue = displayTimeSpanAttribute.UnderlyingValueType.GetTimeSpanValue(property.floatValue);

            float columnSpacing = 1f;

            float columnWidth = (position.width * 0.5f) - columnSpacing;

            Rect valueRect = new Rect(position);

            valueRect.width  = columnWidth;
            valueRect.height = EditorGUIUtility.singleLineHeight;

            Rect unitRect = new Rect(valueRect);

            unitRect.x = valueRect.xMax + columnSpacing;

            TimeIntervalType timeSpanUnit = displayTimeSpanAttribute.UnderlyingValueType;

            EditorGUI.LabelField(unitRect, timeSpanUnit.ToString());

            float currentValue = timeSpanUnit.GetFloatValue(propertyTimeSpanValue);

            currentValue = Mathf.Abs(EditorGUI.FloatField(valueRect, currentValue));

            TimeSpan currentTimespanValue = timeSpanUnit.GetTimeSpanValue(currentValue);

            property.floatValue = displayTimeSpanAttribute.UnderlyingValueType.GetFloatValue(currentTimespanValue);

            Rect returnRect = new Rect(position);

            returnRect.y      += EditorGUIUtility.singleLineHeight;
            returnRect.height -= EditorGUIUtility.singleLineHeight;

            return(returnRect);
        }
        /// <summary>
        /// Renders the time span data as columns pertaining to each unit (milliseconds, seconds, minutes, hours)
        /// </summary>
        /// <param name="position">The rectangle depicting the available render area</param>
        /// <param name="property">The property containing the float value to be displayed as a time span</param>
        /// <param name="displayTimeSpanAttribute">The attribute that identifies the float as a time span value</param>
        /// <returns>A rectangle depicting the remaining available area</returns>
        protected virtual Rect DisplayTimeSpanAsColumns(Rect position, SerializedProperty property, DisplayTimeSpanAttribute displayTimeSpanAttribute)
        {
            float columnSpacing = 1f;

            // separate into 4 columns (Hours, Minutes, Seconds, Milliseconds)
            // we're not going to support days because it's going to be rare we need a timer that long
            float columnWidth = (position.width / 4f) - columnSpacing;

            TimeSpan propertyTimeSpanValue = displayTimeSpanAttribute.UnderlyingValueType.GetTimeSpanValue(property.floatValue);

            string[] timeTypeNames  = Enum.GetNames(typeof(TimeIntervalType));
            float[]  timeTypeValues = GetTimeIntervalValues(propertyTimeSpanValue);

            float xPosition = position.x;

            // Skip the Day value by starting at the second last element (timeTypeNames.Length - 2)
            for (int i = timeTypeNames.Length - 2; i >= 0; i--)
            {
                string currentIntervalName  = timeTypeNames[i];
                float  currentIntervalValue = timeTypeValues[i];

                Rect displayRect = new Rect(position);
                displayRect.x      = xPosition;
                displayRect.width  = columnWidth;
                displayRect.height = EditorGUIUtility.singleLineHeight;

                GUI.Label(displayRect, currentIntervalName);

                displayRect.y += EditorGUIUtility.singleLineHeight;

                timeTypeValues[i] = Mathf.Abs(EditorGUI.FloatField(displayRect, currentIntervalValue));

                xPosition = displayRect.xMax + columnSpacing;
            }

            propertyTimeSpanValue = SetTimeIntervalValues(timeTypeValues);

            property.floatValue = displayTimeSpanAttribute.UnderlyingValueType.GetFloatValue(propertyTimeSpanValue);

            Rect returnRect = new Rect(position);

            returnRect.y      += EditorGUIUtility.singleLineHeight * 2f;
            returnRect.height -= EditorGUIUtility.singleLineHeight * 2f;

            return(returnRect);
        }
        /// <summary>
        /// Renders the time span data as a float field with a drop-down to select the time unit (milliseconds, seconds, minutes, hours)
        /// </summary>
        /// <param name="position">The rectangle depicting the available render area</param>
        /// <param name="property">The property containing the float value to be displayed as a time span</param>
        /// <param name="displayTimeSpanAttribute">The attribute that identifies the float as a time span value</param>
        /// <returns>A rectangle depicting the remaining available area</returns>
        protected virtual Rect DisplayTimeSpanWithSelectableUnit(Rect position, SerializedProperty property, DisplayTimeSpanAttribute displayTimeSpanAttribute)
        {
            TimeSpan propertyTimeSpanValue = displayTimeSpanAttribute.UnderlyingValueType.GetTimeSpanValue(property.floatValue);

            float columnSpacing = 1f;

            float columnWidth = (position.width * 0.5f) - columnSpacing;

            Rect valueRect = new Rect(position);

            valueRect.width  = columnWidth;
            valueRect.height = EditorGUIUtility.singleLineHeight;

            Rect unitRect = new Rect(valueRect);

            unitRect.x = valueRect.xMax + columnSpacing;

            TimeIntervalType timeSpanUnit;

            if (!intervalSelectionCache.TryGetValue(property.propertyPath, out timeSpanUnit))
            {
                timeSpanUnit = displayTimeSpanAttribute.UnderlyingValueType;
                intervalSelectionCache.Add(property.propertyPath, timeSpanUnit);
            }

            timeSpanUnit = (TimeIntervalType)EditorGUI.EnumPopup(unitRect, timeSpanUnit);

            intervalSelectionCache[property.propertyPath] = timeSpanUnit;

            float currentValue = timeSpanUnit.GetFloatValue(propertyTimeSpanValue);

            currentValue = Mathf.Abs(EditorGUI.FloatField(valueRect, currentValue));

            TimeSpan currentTimespanValue = timeSpanUnit.GetTimeSpanValue(currentValue);

            property.floatValue = displayTimeSpanAttribute.UnderlyingValueType.GetFloatValue(currentTimespanValue);

            Rect returnRect = new Rect(position);

            returnRect.y      += EditorGUIUtility.singleLineHeight;
            returnRect.height -= EditorGUIUtility.singleLineHeight;

            return(returnRect);
        }