Files

372 lines
17 KiB
C#

using UnityEditor;
using UnityEngine;
namespace EasyChart.Editor
{
[CustomPropertyDrawer(typeof(AxisConfig))]
public class AxisConfigDrawer : PropertyDrawer
{
private static readonly string[] _labelFormatOptions =
{
"None",
"F0",
"F1",
"F2",
"N0",
"N2",
"P0",
"E2",
"Custom"
};
private static int ResolveLabelFormatIndex(string fmt, out bool isCustom)
{
if (string.IsNullOrEmpty(fmt))
{
isCustom = false;
return 0;
}
for (int i = 1; i < _labelFormatOptions.Length - 1; i++)
{
if (_labelFormatOptions[i] == fmt)
{
isCustom = false;
return i;
}
}
isCustom = true;
return _labelFormatOptions.Length - 1;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
float line = EditorGUIUtility.singleLineHeight;
float space = EditorGUIUtility.standardVerticalSpacing;
// Get all properties
var idProp = property.FindPropertyRelative("id");
var axisTypeProp = property.FindPropertyRelative("axisType");
var visibleProp = property.FindPropertyRelative("visible");
var colorProp = property.FindPropertyRelative("color");
var widthProp = property.FindPropertyRelative("width");
var labelStyleProp = property.FindPropertyRelative("labelStyle");
var labelPlacementProp = property.FindPropertyRelative("labelPlacement");
var labelsProp = property.FindPropertyRelative("labels");
var labelFormatProp = property.FindPropertyRelative("labelFormat");
var autoRangeMinProp = property.FindPropertyRelative("autoRangeMin");
var autoRangeMaxProp = property.FindPropertyRelative("autoRangeMax");
var autoRangeRoundingProp = property.FindPropertyRelative("autoRangeRounding");
var autoRangeUnitProp = property.FindPropertyRelative("autoRangeUnit");
var minValueProp = property.FindPropertyRelative("minValue");
var maxValueProp = property.FindPropertyRelative("maxValue");
var autoTicksProp = property.FindPropertyRelative("autoTicks");
var splitCountProp = property.FindPropertyRelative("splitCount");
var categoryAutoScrollProp = property.FindPropertyRelative("categoryAutoScroll");
var categorySmoothScrollProp = property.FindPropertyRelative("categorySmoothScroll");
var categoryScrollIntervalProp = property.FindPropertyRelative("categoryScrollInterval");
var categoryScrollStepProp = property.FindPropertyRelative("categoryScrollStep");
var showUnitProp = property.FindPropertyRelative("showUnit");
var unitTextProp = property.FindPropertyRelative("unitText");
var unitLabelStyleProp = property.FindPropertyRelative("unitLabelStyle");
Rect r = new Rect(position.x, position.y, position.width, line);
property.isExpanded = EditorGUI.Foldout(r, property.isExpanded, label, true);
r.y += line + space;
if (property.isExpanded)
{
EditorGUI.indentLevel++;
bool isCategoryAxis = axisTypeProp != null && axisTypeProp.enumValueIndex == (int)AxisType.Category;
bool isValueAxis = axisTypeProp == null || axisTypeProp.enumValueIndex == (int)AxisType.Value;
// ===== Section 1: Basic Info =====
EditorGUI.BeginDisabledGroup(true);
if (idProp != null) { EditorGUI.PropertyField(r, idProp); r.y += line + space; }
EditorGUI.EndDisabledGroup();
if (axisTypeProp != null) { EditorGUI.PropertyField(r, axisTypeProp); r.y += line + space; }
if (visibleProp != null) { EditorGUI.PropertyField(r, visibleProp); r.y += line + space; }
// ===== Section 2: Axis Line Style =====
r.y += space; // Add separator
EditorGUI.LabelField(r, "Axis Line", EditorStyles.boldLabel);
r.y += line + space;
if (colorProp != null) { EditorGUI.PropertyField(r, colorProp); r.y += line + space; }
if (widthProp != null) { EditorGUI.PropertyField(r, widthProp); r.y += line + space; }
// ===== Section 3: Range Settings (Value axis only) =====
if (isValueAxis)
{
r.y += space;
EditorGUI.LabelField(r, "Range", EditorStyles.boldLabel);
r.y += line + space;
if (autoRangeMinProp != null) { EditorGUI.PropertyField(r, autoRangeMinProp); r.y += line + space; }
if (autoRangeMinProp != null && !autoRangeMinProp.boolValue)
{
EditorGUI.indentLevel++;
if (minValueProp != null) { EditorGUI.PropertyField(r, minValueProp); r.y += line + space; }
EditorGUI.indentLevel--;
}
if (autoRangeMaxProp != null) { EditorGUI.PropertyField(r, autoRangeMaxProp); r.y += line + space; }
if (autoRangeMaxProp != null && !autoRangeMaxProp.boolValue)
{
EditorGUI.indentLevel++;
if (maxValueProp != null) { EditorGUI.PropertyField(r, maxValueProp); r.y += line + space; }
EditorGUI.indentLevel--;
}
if (autoRangeRoundingProp != null) { EditorGUI.PropertyField(r, autoRangeRoundingProp); r.y += line + space; }
if (autoRangeRoundingProp != null && autoRangeUnitProp != null)
{
if (autoRangeRoundingProp.enumValueIndex == 4)
{
EditorGUI.indentLevel++;
EditorGUI.PropertyField(r, autoRangeUnitProp);
r.y += line + space;
EditorGUI.indentLevel--;
}
}
}
// ===== Section 4: Ticks/Split Settings =====
r.y += space;
EditorGUI.LabelField(r, "Ticks", EditorStyles.boldLabel);
r.y += line + space;
if (autoTicksProp != null) { EditorGUI.PropertyField(r, autoTicksProp); r.y += line + space; }
if (autoTicksProp != null && !autoTicksProp.boolValue)
{
EditorGUI.indentLevel++;
if (splitCountProp != null)
{
var splitLabel = isCategoryAxis ? new GUIContent("VisibleCount") : new GUIContent("Split Count");
EditorGUI.PropertyField(r, splitCountProp, splitLabel);
r.y += line + space;
}
EditorGUI.indentLevel--;
}
// ===== Section 5: Label Settings =====
r.y += space;
EditorGUI.LabelField(r, "Labels", EditorStyles.boldLabel);
r.y += line + space;
if (labelStyleProp != null) { EditorGUI.PropertyField(r, labelStyleProp, true); r.y += EditorGUI.GetPropertyHeight(labelStyleProp, true) + space; }
if (labelPlacementProp != null) { EditorGUI.PropertyField(r, labelPlacementProp); r.y += line + space; }
if (labelFormatProp != null)
{
string current = labelFormatProp.stringValue;
bool custom;
int index = ResolveLabelFormatIndex(current, out custom);
var popupRect = EditorGUI.PrefixLabel(r, new GUIContent("LabelFormat"));
int newIndex = EditorGUI.Popup(popupRect, index, _labelFormatOptions);
r.y += line + space;
int customIndex = _labelFormatOptions.Length - 1;
if (newIndex != index)
{
if (newIndex == 0)
{
labelFormatProp.stringValue = string.Empty;
custom = false;
}
else if (newIndex == customIndex)
{
if (!custom) labelFormatProp.stringValue = string.Empty;
custom = true;
}
else
{
labelFormatProp.stringValue = _labelFormatOptions[newIndex];
custom = false;
}
}
if (newIndex == customIndex)
{
EditorGUI.indentLevel++;
string v = labelFormatProp.stringValue;
if (v == null) v = string.Empty;
string nv = EditorGUI.TextField(r, new GUIContent("Format"), v);
if (nv != v) labelFormatProp.stringValue = nv;
r.y += line + space;
EditorGUI.indentLevel--;
}
}
if (isCategoryAxis && labelsProp != null)
{
float h = EditorGUI.GetPropertyHeight(labelsProp, true);
EditorGUI.PropertyField(new Rect(r.x, r.y, r.width, h), labelsProp, new GUIContent("Category Labels"), true);
r.y += h + space;
}
// ===== Section 6: Unit Settings (Value axis only) =====
if (isValueAxis && showUnitProp != null)
{
r.y += space;
EditorGUI.LabelField(r, "Unit", EditorStyles.boldLabel);
r.y += line + space;
EditorGUI.PropertyField(r, showUnitProp);
r.y += line + space;
if (showUnitProp.boolValue)
{
EditorGUI.indentLevel++;
if (unitTextProp != null) { EditorGUI.PropertyField(r, unitTextProp); r.y += line + space; }
if (unitLabelStyleProp != null)
{
float uh = EditorGUI.GetPropertyHeight(unitLabelStyleProp, true);
EditorGUI.PropertyField(new Rect(r.x, r.y, r.width, uh), unitLabelStyleProp, true);
r.y += uh + space;
}
EditorGUI.indentLevel--;
}
}
// ===== Section 7: Category Scroll Settings (Category axis only) =====
if (isCategoryAxis && categoryAutoScrollProp != null)
{
r.y += space;
EditorGUI.LabelField(r, "Auto Scroll", EditorStyles.boldLabel);
r.y += line + space;
EditorGUI.PropertyField(r, categoryAutoScrollProp);
r.y += line + space;
if (categoryAutoScrollProp.boolValue)
{
EditorGUI.indentLevel++;
if (categorySmoothScrollProp != null) { EditorGUI.PropertyField(r, categorySmoothScrollProp); r.y += line + space; }
if (categoryScrollIntervalProp != null) { EditorGUI.PropertyField(r, categoryScrollIntervalProp); r.y += line + space; }
if (categoryScrollStepProp != null) { EditorGUI.PropertyField(r, categoryScrollStepProp); r.y += line + space; }
EditorGUI.indentLevel--;
}
}
EditorGUI.indentLevel--;
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float line = EditorGUIUtility.singleLineHeight;
float space = EditorGUIUtility.standardVerticalSpacing;
float h = line; // Foldout
if (!property.isExpanded) return h;
var axisTypeProp = property.FindPropertyRelative("axisType");
var labelsProp = property.FindPropertyRelative("labels");
var labelStyleProp = property.FindPropertyRelative("labelStyle");
var labelFormatProp = property.FindPropertyRelative("labelFormat");
var autoRangeMinProp = property.FindPropertyRelative("autoRangeMin");
var autoRangeMaxProp = property.FindPropertyRelative("autoRangeMax");
var autoRangeRoundingProp = property.FindPropertyRelative("autoRangeRounding");
var autoRangeUnitProp = property.FindPropertyRelative("autoRangeUnit");
var autoTicksProp = property.FindPropertyRelative("autoTicks");
var categoryAutoScrollProp = property.FindPropertyRelative("categoryAutoScroll");
var showUnitProp = property.FindPropertyRelative("showUnit");
var unitLabelStyleProp = property.FindPropertyRelative("unitLabelStyle");
bool isCategoryAxis = axisTypeProp != null && axisTypeProp.enumValueIndex == (int)AxisType.Category;
bool isValueAxis = axisTypeProp == null || axisTypeProp.enumValueIndex == (int)AxisType.Value;
// Section 1: Basic Info
h += line + space; // id
h += line + space; // axisType
h += line + space; // visible
// Section 2: Axis Line (header + fields)
h += space + line + space; // header
h += line + space; // color
h += line + space; // width
// Section 3: Range (Value axis only)
if (isValueAxis)
{
h += space + line + space; // header
if (autoRangeMinProp != null)
{
h += line + space; // autoRangeMin
if (!autoRangeMinProp.boolValue) h += line + space; // minValue
}
if (autoRangeMaxProp != null)
{
h += line + space; // autoRangeMax
if (!autoRangeMaxProp.boolValue) h += line + space; // maxValue
}
if (autoRangeRoundingProp != null) h += line + space;
if (autoRangeRoundingProp != null && autoRangeUnitProp != null && autoRangeRoundingProp.enumValueIndex == 4)
{
h += line + space; // autoRangeUnit
}
}
// Section 4: Ticks (header + fields)
h += space + line + space; // header
if (autoTicksProp != null) h += line + space; // autoTicks
if (autoTicksProp != null && !autoTicksProp.boolValue) h += line + space; // splitCount/VisibleCount
// Section 5: Labels (header + fields)
h += space + line + space; // header
if (labelStyleProp != null) h += EditorGUI.GetPropertyHeight(labelStyleProp, true) + space;
h += line + space; // labelPlacement
h += line + space; // labelFormat
if (labelFormatProp != null)
{
bool custom;
int idx = ResolveLabelFormatIndex(labelFormatProp.stringValue, out custom);
if (idx == _labelFormatOptions.Length - 1) h += line + space; // custom format field
}
if (isCategoryAxis && labelsProp != null)
{
h += EditorGUI.GetPropertyHeight(labelsProp, true) + space; // Category Labels
}
// Section 6: Unit (Value axis only)
if (isValueAxis && showUnitProp != null)
{
h += space + line + space; // header
h += line + space; // showUnit
if (showUnitProp.boolValue)
{
h += line + space; // unitText
if (unitLabelStyleProp != null) h += EditorGUI.GetPropertyHeight(unitLabelStyleProp, true) + space;
}
}
// Section 7: Auto Scroll (Category axis only)
if (isCategoryAxis && categoryAutoScrollProp != null)
{
h += space + line + space; // header
h += line + space; // categoryAutoScroll
if (categoryAutoScrollProp.boolValue)
{
h += line + space; // categorySmoothScroll
h += line + space; // categoryScrollInterval
h += line + space; // categoryScrollStep
}
}
return h;
}
}
}