using UnityEditor; using UnityEngine; namespace Flexalon.Editor { [CustomEditor(typeof(FlexalonObject)), CanEditMultipleObjects] public class FlexalonObjectEditor : FlexalonComponentEditor { private SerializedProperty _width; private SerializedProperty _widthType; private SerializedProperty _widthOfParent; private SerializedProperty _height; private SerializedProperty _heightType; private SerializedProperty _heightOfParent; private SerializedProperty _depth; private SerializedProperty _depthType; private SerializedProperty _depthOfParent; private SerializedProperty _minWidth; private SerializedProperty _minWidthType; private SerializedProperty _minWidthOfParent; private SerializedProperty _minHeight; private SerializedProperty _minHeightType; private SerializedProperty _minHeightOfParent; private SerializedProperty _minDepth; private SerializedProperty _minDepthType; private SerializedProperty _minDepthOfParent; private SerializedProperty _maxWidth; private SerializedProperty _maxWidthType; private SerializedProperty _maxWidthOfParent; private SerializedProperty _maxHeight; private SerializedProperty _maxHeightType; private SerializedProperty _maxHeightOfParent; private SerializedProperty _maxDepth; private SerializedProperty _maxDepthType; private SerializedProperty _maxDepthOfParent; private SerializedProperty _offset; private SerializedProperty _rotation; private SerializedProperty _scale; private SerializedProperty _marginLeft; private SerializedProperty _marginRight; private SerializedProperty _marginTop; private SerializedProperty _marginBottom; private SerializedProperty _marginFront; private SerializedProperty _marginBack; private SerializedProperty _paddingLeft; private SerializedProperty _paddingRight; private SerializedProperty _paddingTop; private SerializedProperty _paddingBottom; private SerializedProperty _paddingFront; private SerializedProperty _paddingBack; private SerializedProperty _skipLayout; private static readonly int ValueWidth = 50; [MenuItem("GameObject/Flexalon/Flexalon Object")] public static void Create(MenuCommand command) { FlexalonComponentEditor.Create("Flexalon Object", command.context); } void OnEnable() { _width = serializedObject.FindProperty("_width"); _widthType = serializedObject.FindProperty("_widthType"); _widthOfParent = serializedObject.FindProperty("_widthOfParent"); _height = serializedObject.FindProperty("_height"); _heightType = serializedObject.FindProperty("_heightType"); _heightOfParent = serializedObject.FindProperty("_heightOfParent"); _depth = serializedObject.FindProperty("_depth"); _depthType = serializedObject.FindProperty("_depthType"); _depthOfParent = serializedObject.FindProperty("_depthOfParent"); _minWidth = serializedObject.FindProperty("_minWidth"); _minWidthType = serializedObject.FindProperty("_minWidthType"); _minWidthOfParent = serializedObject.FindProperty("_minWidthOfParent"); _minHeight = serializedObject.FindProperty("_minHeight"); _minHeightType = serializedObject.FindProperty("_minHeightType"); _minHeightOfParent = serializedObject.FindProperty("_minHeightOfParent"); _minDepth = serializedObject.FindProperty("_minDepth"); _minDepthType = serializedObject.FindProperty("_minDepthType"); _minDepthOfParent = serializedObject.FindProperty("_minDepthOfParent"); _maxWidth = serializedObject.FindProperty("_maxWidth"); _maxWidthType = serializedObject.FindProperty("_maxWidthType"); _maxWidthOfParent = serializedObject.FindProperty("_maxWidthOfParent"); _maxHeight = serializedObject.FindProperty("_maxHeight"); _maxHeightType = serializedObject.FindProperty("_maxHeightType"); _maxHeightOfParent = serializedObject.FindProperty("_maxHeightOfParent"); _maxDepth = serializedObject.FindProperty("_maxDepth"); _maxDepthType = serializedObject.FindProperty("_maxDepthType"); _maxDepthOfParent = serializedObject.FindProperty("_maxDepthOfParent"); _offset = serializedObject.FindProperty("_offset"); _rotation = serializedObject.FindProperty("_rotation"); _scale = serializedObject.FindProperty("_scale"); _marginLeft = serializedObject.FindProperty("_marginLeft"); _marginRight = serializedObject.FindProperty("_marginRight"); _marginTop = serializedObject.FindProperty("_marginTop"); _marginBottom = serializedObject.FindProperty("_marginBottom"); _marginFront = serializedObject.FindProperty("_marginFront"); _marginBack = serializedObject.FindProperty("_marginBack"); _paddingLeft = serializedObject.FindProperty("_paddingLeft"); _paddingRight = serializedObject.FindProperty("_paddingRight"); _paddingTop = serializedObject.FindProperty("_paddingTop"); _paddingBottom = serializedObject.FindProperty("_paddingBottom"); _paddingFront = serializedObject.FindProperty("_paddingFront"); _paddingBack = serializedObject.FindProperty("_paddingBack"); _skipLayout = serializedObject.FindProperty("_skipLayout"); _sizeFoldout = EditorPrefs.GetBool("FlexalonSizeFoldout", true); _minMaxFoldout = EditorPrefs.GetBool("FlexalonMinMaxFoldout", false); _marginFoldout = EditorPrefs.GetBool("FlexalonMarginFoldout", false); _paddingFoldout = EditorPrefs.GetBool("FlexalonPaddingFoldout", false); _transformFoldout = EditorPrefs.GetBool("FlexalonTransformFoldout", false); } void OnDisable() { EditorPrefs.SetBool("FlexalonSizeFoldout", _sizeFoldout); EditorPrefs.SetBool("FlexalonMinMaxFoldout", _minMaxFoldout); EditorPrefs.SetBool("FlexalonMarginFoldout", _marginFoldout); EditorPrefs.SetBool("FlexalonPaddingFoldout", _paddingFoldout); EditorPrefs.SetBool("FlexalonTransformFoldout", _transformFoldout); } private static bool _sizeFoldout; private static bool _minMaxFoldout; private static bool _marginFoldout; private static bool _paddingFoldout; private static bool _transformFoldout; public override void OnInspectorGUI() { serializedObject.Update(); ForceUpdateButton(); _sizeFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(_sizeFoldout, "Size"); if (_sizeFoldout) { CreateSizeProperty("Width", _widthType, _width, _widthOfParent); CreateSizeProperty("Height", _heightType, _height, _heightOfParent); CreateSizeProperty("Depth", _depthType, _depth, _depthOfParent); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); _minMaxFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(_minMaxFoldout, "Min / Max"); if (_minMaxFoldout) { CreateMinMaxSizeProperty("Width", _minWidthType, _minWidth, _minWidthOfParent, _maxWidthType, _maxWidth, _maxWidthOfParent); CreateMinMaxSizeProperty("Height", _minHeightType, _minHeight, _minHeightOfParent, _maxHeightType, _maxHeight, _maxHeightOfParent); CreateMinMaxSizeProperty("Depth", _minDepthType, _minDepth, _minDepthOfParent, _maxDepthType, _maxDepth, _maxDepthOfParent); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); _marginFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(_marginFoldout, "Margin"); if (_marginFoldout) { CreateSpacingProperty("Left", "Right", _marginLeft, _marginRight); CreateSpacingProperty("Top", "Bottom", _marginTop, _marginBottom); CreateSpacingProperty("Front", "Back", _marginFront, _marginBack); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); _paddingFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(_paddingFoldout, "Padding"); if (_paddingFoldout) { CreateSpacingProperty("Left", "Right", _paddingLeft, _paddingRight); CreateSpacingProperty("Top", "Bottom", _paddingTop, _paddingBottom); CreateSpacingProperty("Front", "Back", _paddingFront, _paddingBack); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); _transformFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(_transformFoldout, "Transform"); if (_transformFoldout) { EditorGUILayout.PropertyField(_offset); EditorGUILayout.PropertyField(_rotation); EditorGUILayout.PropertyField(_scale); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); EditorGUILayout.PropertyField(_skipLayout); ApplyModifiedProperties(); } private void CreateSizeProperty(string label, SerializedProperty typeProperty, SerializedProperty fixedProperty, SerializedProperty ofParentProperty) { EditorGUILayout.BeginHorizontal(); bool showTypeLabel = true; if (typeProperty.enumValueIndex == (int)SizeType.Fixed) { EditorGUILayout.PropertyField(fixedProperty, new GUIContent(label)); showTypeLabel = false; } else if (typeProperty.enumValueIndex == (int)SizeType.Fill) { EditorGUILayout.PropertyField(ofParentProperty, new GUIContent(label)); showTypeLabel = false; } EditorGUILayout.PropertyField(typeProperty, showTypeLabel ? new GUIContent(label) : GUIContent.none); EditorGUILayout.EndHorizontal(); } private void CreateMinMaxSizeProperty(string label, SerializedProperty minTypeProperty, SerializedProperty minFixedProperty, SerializedProperty minOfParentProperty, SerializedProperty maxTypeProperty, SerializedProperty maxFixedProperty, SerializedProperty maxOfParentProperty) { EditorGUILayout.BeginHorizontal(); var labelWidth = EditorGUIUtility.labelWidth; if (minTypeProperty.enumValueIndex == (int)MinMaxSizeType.Fixed) { EditorGUILayout.PropertyField(minFixedProperty, new GUIContent(label), GUILayout.Width(EditorGUIUtility.labelWidth + ValueWidth + 3)); } else if (minTypeProperty.enumValueIndex == (int)MinMaxSizeType.Fill) { EditorGUILayout.PropertyField(minOfParentProperty, new GUIContent(label), GUILayout.Width(EditorGUIUtility.labelWidth + ValueWidth + 3)); } else { EditorGUILayout.LabelField(label, GUILayout.Width(EditorGUIUtility.labelWidth)); EditorGUI.BeginDisabledGroup(true); EditorGUILayout.TextField("-", GUILayout.Width(ValueWidth)); EditorGUI.EndDisabledGroup(); } EditorGUIUtility.labelWidth = 20; EditorGUILayout.PropertyField(minTypeProperty, GUIContent.none); if (maxTypeProperty.enumValueIndex == (int)MinMaxSizeType.Fixed) { EditorGUILayout.PropertyField(maxFixedProperty, new GUIContent(" "), GUILayout.Width(EditorGUIUtility.labelWidth + ValueWidth + 3)); } else if (maxTypeProperty.enumValueIndex == (int)MinMaxSizeType.Fill) { EditorGUILayout.PropertyField(maxOfParentProperty, new GUIContent(" "), GUILayout.Width(EditorGUIUtility.labelWidth + ValueWidth + 3)); } else { EditorGUI.BeginDisabledGroup(true); EditorGUILayout.LabelField(" ", GUILayout.Width(EditorGUIUtility.labelWidth)); EditorGUILayout.TextField("-", GUILayout.Width(ValueWidth)); EditorGUI.EndDisabledGroup(); } EditorGUILayout.PropertyField(maxTypeProperty, GUIContent.none); EditorGUIUtility.labelWidth = labelWidth; EditorGUILayout.EndHorizontal(); } private void CreateSpacingProperty(string label1, string label2, SerializedProperty property1, SerializedProperty property2) { EditorGUILayout.BeginHorizontal(); var labelWidth = EditorGUIUtility.labelWidth; EditorGUILayout.PropertyField(property1, new GUIContent(label1)); EditorGUIUtility.labelWidth = 50; EditorGUILayout.Space(); EditorGUILayout.PropertyField(property2, new GUIContent(label2)); EditorGUIUtility.labelWidth = labelWidth; EditorGUILayout.EndHorizontal(); } private void CreateSizeProperty2(SerializedProperty typeProperty, SerializedProperty fixedProperty, SerializedProperty ofParentProperty, SerializedProperty minTypeProperty, SerializedProperty minFixedProperty, SerializedProperty minOfParentProperty, SerializedProperty maxTypeProperty, SerializedProperty maxFixedProperty, SerializedProperty maxOfParentProperty, SerializedProperty margin1, SerializedProperty margin2, SerializedProperty padding1, SerializedProperty padding2) { EditorGUILayout.BeginHorizontal(); GUILayout.Space(EditorGUIUtility.labelWidth - 54); EditorGUILayout.LabelField("Min/Max", GUILayout.Width(54)); if (minTypeProperty.enumValueIndex == (int)MinMaxSizeType.Fixed) { EditorGUILayout.PropertyField(minFixedProperty, GUIContent.none); } else if (minTypeProperty.enumValueIndex == (int)MinMaxSizeType.Fill) { EditorGUILayout.PropertyField(minOfParentProperty, GUIContent.none); } else { EditorGUI.BeginDisabledGroup(true); EditorGUILayout.TextField("-"); EditorGUI.EndDisabledGroup(); } EditorGUILayout.PropertyField(minTypeProperty, GUIContent.none); if (maxTypeProperty.enumValueIndex == (int)MinMaxSizeType.Fixed) { EditorGUILayout.PropertyField(maxFixedProperty, GUIContent.none); } else if (maxTypeProperty.enumValueIndex == (int)MinMaxSizeType.Fill) { EditorGUILayout.PropertyField(maxOfParentProperty, GUIContent.none); } else { EditorGUI.BeginDisabledGroup(true); EditorGUILayout.TextField("-"); EditorGUI.EndDisabledGroup(); } EditorGUILayout.PropertyField(maxTypeProperty, GUIContent.none); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Space(EditorGUIUtility.labelWidth - 54); EditorGUILayout.LabelField("Margin", GUILayout.Width(54)); EditorGUILayout.PropertyField(margin1, GUIContent.none); EditorGUILayout.PropertyField(margin2, GUIContent.none); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Space(EditorGUIUtility.labelWidth - 54); EditorGUILayout.LabelField("Padding", GUILayout.Width(54)); EditorGUILayout.PropertyField(padding1, GUIContent.none); EditorGUILayout.PropertyField(padding2, GUIContent.none); EditorGUILayout.EndHorizontal(); } void OnSceneGUI() { // Draw a box at the transforms position var script = target as FlexalonObject; var node = Flexalon.GetNode(script.gameObject); if (node == null || node.Result == null) { return; } var r = node.Result; if (node.Parent != null) { var layoutBoxScale = node.GetWorldBoxScale(false); var layoutRotation = script.transform.parent != null ? script.transform.parent.rotation * r.LayoutRotation : r.LayoutRotation; // Box used to layout this object, plus margins. Handles.color = new Color(1f, 1f, .2f, 1.0f); Handles.matrix = Matrix4x4.TRS(script.transform.position, layoutRotation, layoutBoxScale); Handles.DrawWireCube(r.RotatedAndScaledBounds.center + node.Margin.Center, r.RotatedAndScaledBounds.size + node.Margin.Size); // Box used to layout this object. Handles.color = new Color(.2f, 1f, .5f, 1.0f); Handles.matrix = Matrix4x4.TRS(script.transform.position, layoutRotation, layoutBoxScale); Handles.DrawWireCube(r.RotatedAndScaledBounds.center, r.RotatedAndScaledBounds.size); } // Box in which children are layed out. This is the box with handles on it. Handles.color = Color.cyan; var worldBoxScale = node.GetWorldBoxScale(true); Handles.matrix = Matrix4x4.TRS(node.GetWorldBoxPosition(worldBoxScale, false), script.transform.rotation, worldBoxScale); Handles.DrawWireCube(Vector3.zero, r.AdapterBounds.size); var id = 0; float result; if (script.WidthType == SizeType.Fixed) { if (CreateSizeHandles(id++, id++, r.AdapterBounds.size, 0, script, out result)) { Record(script); script.Width = result; MarkDirty(script); } } if (script.HeightType == SizeType.Fixed) { if (CreateSizeHandles(id++, id++, r.AdapterBounds.size, 1, script, out result)) { Record(script); script.Height = result; MarkDirty(script); } } if (script.DepthType == SizeType.Fixed) { if (CreateSizeHandles(id++, id++, r.AdapterBounds.size, 2, script, out result)) { Record(script); script.Depth = result; MarkDirty(script); } } } private bool CreateSizeHandles(int id1, int id2, Vector3 size, int axis, FlexalonObject script, out float result) { bool changed = false; result = 0; if (CreateSizeHandleOnSide(id1, size, axis, 1, script, out float r1)) { result = r1; changed = true; } if (CreateSizeHandleOnSide(id2, size, axis, -1, script, out float r2)) { result = r2; changed = true; } return changed; } private bool CreateSizeHandleOnSide(int id, Vector3 size, int axis, int positive, FlexalonObject script, out float result) { var cid = GUIUtility.GetControlID(id, FocusType.Passive); var p = new Vector3(); p[axis] = size[axis] / 2 * positive; EditorGUI.BeginChangeCheck(); #if UNITY_2022_1_OR_NEWER Vector3 newPos = Handles.FreeMoveHandle(cid, p, HandleUtility.GetHandleSize(p) * 0.2f, Vector3.one * 0.1f, Handles.SphereHandleCap); #else Vector3 newPos = Handles.FreeMoveHandle(cid, p, Quaternion.identity, HandleUtility.GetHandleSize(p) * 0.2f, Vector3.one * 0.1f, Handles.SphereHandleCap); #endif if (EditorGUI.EndChangeCheck()) { result = newPos[axis] * 2 * positive; return true; } result = 0; return false; } } }