BITFALL/Assets/GSpawn - Level Designer/Scripts/Level Design/Object Selection/ObjectSelectionGrowSettings.cs

290 lines
20 KiB
C#
Raw Normal View History

2024-01-27 04:09:57 +08:00
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
#if UNITY_2021
using UnityEditor.UIElements;
#endif
namespace GSpawn
{
public enum ObjectSelectionGrowRotationConstraintMode
{
None = 0,
Exact,
Flexible
}
public class ObjectSelectionGrowSettings : PluginSettings<ObjectSelectionGrowSettings>
{
private const float _minDistanceThreshold = 0.0005f;
private const float _minAngleThreshold = 1e-5f;
private const float _maxAngleThreshold = 90.0f;
private const float _minPositionThreshold = 1e-5f;
[SerializeField]
private float _distanceThreshold = defaultDistanceThreshold;
[SerializeField]
private bool _xPositionConstraint = defaultXPositionConstraint;
[SerializeField]
private bool _useXPositionThreshold = defaultUseXPositionThreshold;
[SerializeField]
private float _xPositionThreshold = defaultXPositionThreshold;
[SerializeField]
private bool _growRight = defaultGrowRight;
[SerializeField]
private bool _growLeft = defaultGrowLeft;
[SerializeField]
private bool _yPositionConstraint = defaultYPositionConstraint;
[SerializeField]
private bool _useYPositionThreshold = defaultUseYPositionThreshold;
[SerializeField]
private float _yPositionThreshold = defaultYPositionThreshold;
[SerializeField]
private bool _growUp = defaultGrowUp;
[SerializeField]
private bool _growDown = defaultGrowDown;
[SerializeField]
private bool _zPositionConstraint = defaultZPositionConstraint;
[SerializeField]
private bool _useZPositionThreshold = defaultUseZPositionThreshold;
[SerializeField]
private float _zPositionThreshold = defaultZPositionThreshold;
[SerializeField]
private bool _growForward = defaultGrowForward;
[SerializeField]
private bool _growBackward = defaultGrowBackward;
[SerializeField]
private bool _prefabConstraint = defaultPrefabConstraint;
[SerializeField]
private ObjectSelectionGrowRotationConstraintMode _rotationConstraintMode = defaultRotationConstraintMode;
[SerializeField]
private float _angleThreshold = defaultAngleThreshold;
[SerializeField]
private bool _useMaxCountConstraint = defaultUseMaxCountConstraint;
[SerializeField]
private int _maxCount = defaultMaxCount;
[SerializeField]
private bool _ignoreOutOfView = defaultIgnoreOutOfView;
public float distanceThreshold { get { return _distanceThreshold; } set { UndoEx.record(this); _distanceThreshold = Mathf.Max(value, _minDistanceThreshold); EditorUtility.SetDirty(this); } }
public bool xPositionConstraint { get { return _xPositionConstraint; } set { UndoEx.record(this); _xPositionConstraint = value; EditorUtility.SetDirty(this); } }
public float xPositionThreshold { get { return _xPositionThreshold; } set { UndoEx.record(this); _xPositionThreshold = Mathf.Max(_minPositionThreshold, value); EditorUtility.SetDirty(this); } }
public bool useXPositionThreshold { get { return _useXPositionThreshold; } set { UndoEx.record(this); _useXPositionThreshold = value; EditorUtility.SetDirty(this); } }
public bool growRight { get { return _growRight; } set { UndoEx.record(this); _growRight = value; EditorUtility.SetDirty(this); } }
public bool growLeft { get { return _growLeft; } set { UndoEx.record(this); _growLeft = value; EditorUtility.SetDirty(this); } }
public bool yPositionConstraint { get { return _yPositionConstraint; } set { UndoEx.record(this); _yPositionConstraint = value; EditorUtility.SetDirty(this); } }
public bool useYPositionThreshold { get { return _useYPositionThreshold; } set { UndoEx.record(this); _useYPositionThreshold = value; EditorUtility.SetDirty(this); } }
public float yPositionThreshold { get { return _yPositionThreshold; } set { UndoEx.record(this); _yPositionThreshold = Mathf.Max(_minPositionThreshold, value); EditorUtility.SetDirty(this); } }
public bool growUp { get { return _growUp; } set { UndoEx.record(this); _growUp = value; EditorUtility.SetDirty(this); } }
public bool growDown { get { return _growDown; } set { UndoEx.record(this); _growDown = value; EditorUtility.SetDirty(this); } }
public bool zPositionConstraint { get { return _zPositionConstraint; } set { UndoEx.record(this); _zPositionConstraint = value; EditorUtility.SetDirty(this); } }
public bool useZPositionThreshold { get { return _useZPositionThreshold; } set { UndoEx.record(this); _useZPositionThreshold = value; EditorUtility.SetDirty(this); } }
public float zPositionThreshold { get { return _zPositionThreshold; } set { UndoEx.record(this); _zPositionThreshold = Mathf.Max(_minPositionThreshold, value); EditorUtility.SetDirty(this); } }
public bool growForward { get { return _growForward; } set { UndoEx.record(this); _growForward = value; EditorUtility.SetDirty(this); } }
public bool growBackward { get { return _growBackward; } set { UndoEx.record(this); _growBackward = value; EditorUtility.SetDirty(this); } }
public bool usePrefabConstraint { get { return _prefabConstraint; } set { UndoEx.record(this); _prefabConstraint = value; EditorUtility.SetDirty(this); } }
public ObjectSelectionGrowRotationConstraintMode rotationConstraintMode { get { return _rotationConstraintMode; } set { UndoEx.record(this); _rotationConstraintMode = value; EditorUtility.SetDirty(this); } }
public float angleThreshold { get { return _angleThreshold; } set { UndoEx.record(this); _angleThreshold = Mathf.Clamp(value, _minAngleThreshold, _maxAngleThreshold); } }
public bool useMaxCountConstraint { get { return _useMaxCountConstraint; } set { UndoEx.record(this); _useMaxCountConstraint = value; EditorUtility.SetDirty(this); } }
public int maxCount { get { return _maxCount; } set { UndoEx.record(this); _maxCount = Mathf.Max(value, 1); EditorUtility.SetDirty(this); } }
public bool ignoreOutOfView { get { return _ignoreOutOfView; } set { UndoEx.record(this); _ignoreOutOfView = value; EditorUtility.SetDirty(this); } }
public static float defaultDistanceThreshold { get { return _minDistanceThreshold; } }
public static bool defaultXPositionConstraint { get { return false; } }
public static bool defaultUseXPositionThreshold { get { return false; } }
public static float defaultXPositionThreshold { get { return 0.05f; } }
public static bool defaultGrowRight { get { return true; } }
public static bool defaultGrowLeft { get { return true; } }
public static bool defaultYPositionConstraint { get { return false; } }
public static bool defaultUseYPositionThreshold { get { return false; } }
public static float defaultYPositionThreshold { get { return 0.05f; } }
public static bool defaultGrowUp { get { return true; } }
public static bool defaultGrowDown { get { return true; } }
public static bool defaultZPositionConstraint { get { return false; } }
public static bool defaultUseZPositionThreshold { get { return false; } }
public static float defaultZPositionThreshold { get { return 0.05f; } }
public static bool defaultGrowForward { get { return true; } }
public static bool defaultGrowBackward { get { return true; } }
public static bool defaultPrefabConstraint { get { return false; } }
public static ObjectSelectionGrowRotationConstraintMode defaultRotationConstraintMode { get { return ObjectSelectionGrowRotationConstraintMode.None; } }
public static float defaultAngleThreshold { get { return _minAngleThreshold; } }
public static bool defaultUseMaxCountConstraint { get { return false; } }
public static int defaultMaxCount { get { return 50; } }
public static bool defaultIgnoreOutOfView { get { return false; } }
public void buildUI(VisualElement parent)
{
const float labelSize = 155.0f;
var floatField = UI.createFloatField("_distanceThreshold", serializedObject, "Distance threshold",
"The maximum allowed distance between objects.", _minDistanceThreshold, parent);
floatField.setChildLabelWidth(labelSize);
var toggle = UI.createToggle("_prefabConstraint", serializedObject, "Prefab constraint",
"If checked, the grow operation will only include objects that belong to prefabs that reside in the original selection.", parent);
toggle.setChildLabelWidth(labelSize);
// X/Y/Z position constraints
UI.createRowSeparator(parent);
createPositionConstraintControls(0, labelSize, parent);
createPositionConstraintControls(1, labelSize, parent);
createPositionConstraintControls(2, labelSize, parent);
UI.createRowSeparator(parent);
FloatField angleThresholdField = null;
var rotationConstraintModeField = UI.createEnumField(typeof(ObjectSelectionGrowRotationConstraintMode), "_rotationConstraintMode", serializedObject, "Rotation constraint mode",
"The type of rotation constraint to be applied.", parent);
rotationConstraintModeField.setChildLabelWidth(labelSize);
rotationConstraintModeField.RegisterValueChangedCallback(p =>
{
angleThresholdField.setDisplayVisible(rotationConstraintMode == ObjectSelectionGrowRotationConstraintMode.Flexible);
});
angleThresholdField = UI.createFloatField("_angleThreshold", serializedObject, "Angle threshold",
"Allows you to specify an angle threshold value in degrees used when checking alignment.", _minAngleThreshold, _maxAngleThreshold, parent);
angleThresholdField.setChildLabelWidth(labelSize);
angleThresholdField.setDisplayVisible(rotationConstraintMode == ObjectSelectionGrowRotationConstraintMode.Flexible);
IntegerField maxCountField = null;
toggle = UI.createToggle("_useMaxCountConstraint", serializedObject, "Max count constraint",
"If checked, the grow operation will stop when a maximum number of objects have been selected.", parent);
toggle.setChildLabelWidth(labelSize);
toggle.RegisterValueChangedCallback(p =>
{
maxCountField.setDisplayVisible(useMaxCountConstraint);
});
maxCountField = UI.createIntegerField("_maxCount", serializedObject, "Max count",
"The maximum number of objects that can be selected when the max count constraint is enabled.", 1, parent);
maxCountField.setChildLabelWidth(labelSize);
maxCountField.setDisplayVisible(useMaxCountConstraint);
toggle = UI.createToggle("_ignoreOutOfView", serializedObject, "Ignore out of view",
"If checked, the grow operation will not include objects that are culled from the perspective of the scene camera.", parent);
toggle.setChildLabelWidth(labelSize);
UI.createUseDefaultsButton(() => { useDefaults(); }, parent);
}
public override void useDefaults()
{
distanceThreshold = defaultDistanceThreshold;
xPositionConstraint = defaultXPositionConstraint;
useXPositionThreshold = defaultUseXPositionThreshold;
xPositionThreshold = defaultXPositionThreshold;
growRight = defaultGrowRight;
growLeft = defaultGrowLeft;
yPositionConstraint = defaultYPositionConstraint;
useYPositionThreshold = defaultUseYPositionThreshold;
yPositionThreshold = defaultYPositionThreshold;
growUp = defaultGrowUp;
growDown = defaultGrowDown;
zPositionConstraint = defaultZPositionConstraint;
useZPositionThreshold = defaultUseZPositionThreshold;
zPositionThreshold = defaultZPositionThreshold;
growForward = defaultGrowForward;
growBackward = defaultGrowBackward;
usePrefabConstraint = defaultPrefabConstraint;
rotationConstraintMode = defaultRotationConstraintMode;
useMaxCountConstraint = defaultUseMaxCountConstraint;
maxCount = defaultMaxCount;
ignoreOutOfView = defaultIgnoreOutOfView;
EditorUtility.SetDirty(this);
}
private static string[] _posConstr_PropertyNames = new string[] { "_xPositionConstraint", "_yPositionConstraint", "_zPositionConstraint" };
private static string[] _usePosThreshold_PropertyNames = new string[] { "_useXPositionThreshold", "_useYPositionThreshold", "_useZPositionThreshold" };
private static string[] _posThreshold_PropertyNames = new string[] { "_xPositionThreshold", "_yPositionThreshold", "_zPositionThreshold" };
private void createPositionConstraintControls(int axis, float labelSize, VisualElement parent)
{
const float indent = 20.0f;
string axisName = StringEx.axisIndexToAxisName(axis);
string label = axisName + " constraint";
string tooltip = string.Format("If checked, the grow operation will filter objects based on their {0} coordinates using different criteria.", axisName);
var posConstrToggle = UI.createToggle(_posConstr_PropertyNames[axis], serializedObject, label, tooltip, parent);
posConstrToggle.setChildLabelWidth(labelSize);
var ctrlContainer = new VisualElement();
parent.Add(ctrlContainer);
var thresholdContainer = new VisualElement();
ctrlContainer.Add(thresholdContainer);
thresholdContainer.style.flexDirection = FlexDirection.Row;
thresholdContainer.style.marginLeft = indent;
var thresholdToggle = UI.createToggle(_usePosThreshold_PropertyNames[axis], serializedObject, "", string.Format("Toggle {0} position threshold.", axisName), thresholdContainer);
thresholdToggle.style.marginRight = 0.0f;
thresholdToggle.style.flexGrow = 0.0f;
tooltip = string.Format("Specifies how much the object {0} coordinates can differ along the {0} axis relative to the original selection.", axisName);
var thresholdField = UI.createFloatField(_posThreshold_PropertyNames[axis], serializedObject,
string.Format("{0} threshold", axisName), tooltip, _minPositionThreshold, thresholdContainer);
thresholdField.setChildLabelWidth(labelSize - indent);
string growPstv_PropertyName = string.Empty;
string growNgtv_PropertyName = string.Empty;
string growPstv_Label = string.Empty;
string growNgtv_Label = string.Empty;
string growPstv_Dir = string.Empty;
string growNgtv_Dir = string.Empty;
if (axis == 0)
{
growPstv_PropertyName = "_growRight";
growNgtv_PropertyName = "_growLeft";
growPstv_Label = "Grow right";
growNgtv_Label = "Grow left";
growPstv_Dir = "rightward";
growNgtv_Dir = "leftward";
}
else
if (axis == 1)
{
growPstv_PropertyName = "_growUp";
growNgtv_PropertyName = "_growDown";
growPstv_Label = "Grow up";
growNgtv_Label = "Grow down";
growPstv_Dir = "upward";
growNgtv_Dir = "downward";
}
else
if (axis == 2)
{
growPstv_PropertyName = "_growForward";
growNgtv_PropertyName = "_growBackward";
growPstv_Label = "Grow forward";
growNgtv_Label = "Grow back";
growPstv_Dir = "forward";
growNgtv_Dir = "backward";
}
tooltip = string.Format("");
var growPstvField = UI.createToggle(growPstv_PropertyName, serializedObject, growPstv_Label,
string.Format("If checked, the grow operation can extend {0} relative to the original selection.", growPstv_Dir), ctrlContainer);
growPstvField.setChildLabelWidth(labelSize);
growPstvField.style.marginLeft = indent;
var growNgtvField = UI.createToggle(growNgtv_PropertyName, serializedObject, growNgtv_Label,
string.Format("If checked, the grow operation can extend {0} relative to the original selection.", growNgtv_Dir), ctrlContainer);
growNgtvField.setChildLabelWidth(labelSize);
growNgtvField.style.marginLeft = indent;
posConstrToggle.RegisterValueChangedCallback(p => { ctrlContainer.setDisplayVisible(p.newValue);});
ctrlContainer.setDisplayVisible(posConstrToggle.value);
}
}
}
#endif