#if UNITY_EDITOR using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.UIElements; namespace GSpawn { public class CurveObjectSpawnUI : PluginUI { [NonSerialized] private ProfileSelectionUI _curveCreationSettingsProfileSelectionUI; [SerializeField] private ListViewState _curveViewState; [NonSerialized] private ListView _curveView; [NonSerialized] private EntitySearchField _curveSearchField; [NonSerialized] private Button _useDefaultsBtn; [SerializeField] private UISection _curveCreationSettingsSection; [SerializeField] private UISection _curvesSection; [NonSerialized] private VisualElement _createCurveContainer; [NonSerialized] private bool _deleteCurveObjects; [NonSerialized] private List _curveBuffer = new List(); [NonSerialized] private List _curveIdBuffer = new List(); [NonSerialized] private List _curveSpawnSettingsBuffer = new List(); public static CurveObjectSpawnUI instance { get { return GSpawn.active.curveObjectSpawnUI; } } public void getVisibleSelectedCurves(List curves) { if (_curveView == null) return; curves.Clear(); var selectedCurves = new List(); _curveView.getVisibleSelectedItemData(selectedCurves); foreach (var itemData in selectedCurves) curves.Add(itemData); } public void getSelectedCurves(List curves) { if (_curveView == null) return; curves.Clear(); var selectedCurves = new List(); _curveView.getSelectedItemData(selectedCurves); foreach (var itemData in selectedCurves) curves.Add(itemData); } public void setSelectedCurve(ObjectSpawnCurve curve) { if (_curveView == null) return; _curveView.setAllItemsSelected(false, false, false); _curveView.setItemSelected(curve.guid, true, false); } public void setSelectedCurves(List curves) { if (_curveView == null) return; _curveView.setAllItemsSelected(false, false, false); UIObjectSpawnCurveItem.getItemIds(curves, _curveIdBuffer); _curveView.setItemsSelected(_curveIdBuffer, true, false, false); } protected override void onBuild() { contentContainer.style.flexGrow = 1.0f; _curveCreationSettingsSection.build("Curve Creation", TexturePool.instance.settings, true, contentContainer); _curveCreationSettingsProfileSelectionUI = new ProfileSelectionUI(); _curveCreationSettingsProfileSelectionUI.build(CurveObjectSpawnSettingsProfileDb.instance, "curve object spawn settings", _curveCreationSettingsSection.contentContainer); createCreateCurveUI(_curveCreationSettingsSection.contentContainer); UI.createUISectionRowSeparator(contentContainer); _curvesSection.build("Curves", TexturePool.instance.curveSpawn, true, contentContainer); createSearchToolbar(_curvesSection.contentContainer); createCurveViewToolbar(_curvesSection.contentContainer); createCurveView(_curvesSection.contentContainer); populateCurveView(); createCurveSettingsControls(_curvesSection.contentContainer); } protected override void onRefresh() { if (_curveCreationSettingsProfileSelectionUI != null) _curveCreationSettingsProfileSelectionUI.refresh(); createCreateCurveUI(_curveCreationSettingsSection.contentContainer); populateCurveView(); } protected override void onEnabled() { if (_curveViewState == null) { _curveViewState = ScriptableObject.CreateInstance(); _curveViewState.name = GetType().Name + "_CurveViewState"; } if (_curveCreationSettingsSection == null) _curveCreationSettingsSection = ScriptableObject.CreateInstance(); if (_curvesSection == null) _curvesSection = ScriptableObject.CreateInstance(); if (FileSystem.folderExists(PluginFolders.curveObjectSpawnSettingsProfiles)) CurveObjectSpawnSettingsProfileDb.instance.activeProfileChanged += onActiveCurveCreationSettingsProfileChanged; } protected override void onDisabled() { if (FileSystem.folderExists(PluginFolders.curveObjectSpawnSettingsProfiles)) CurveObjectSpawnSettingsProfileDb.instance.activeProfileChanged -= onActiveCurveCreationSettingsProfileChanged; } protected override void onUndoRedo() { if (_curveCreationSettingsProfileSelectionUI != null) _curveCreationSettingsProfileSelectionUI.refresh(); populateCurveView(); } protected override void onDestroy() { ScriptableObjectEx.destroyImmediate(_curvesSection); ScriptableObjectEx.destroyImmediate(_curveCreationSettingsSection); ScriptableObjectEx.destroyImmediate(_curveViewState); } private void createCreateCurveUI(VisualElement parent) { if (_createCurveContainer != null && parent.Contains(_createCurveContainer)) { parent.Remove(_createCurveContainer); } _createCurveContainer = new VisualElement(); parent.Add(_createCurveContainer); CurveObjectSpawnSettingsProfileDb.instance.activeProfile.settings.buildUI(_createCurveContainer); var createCurveBtnAndField = new VisualElement(); _createCurveContainer.Add(createCurveBtnAndField); createCurveBtnAndField.style.flexDirection = FlexDirection.Row; TextField curveObjectNameField = new TextField(); curveObjectNameField.style.flexGrow = 1.0f; Button createNewCurveBtn = new Button(); createNewCurveBtn.text = "Create curve"; createNewCurveBtn.tooltip = "Create a new spawn curve by placing control points in the scene."; createNewCurveBtn.style.width = UIValues.useDefaultsButtonWidth; createNewCurveBtn.clicked += () => { ObjectSpawn.instance.curveObjectSpawn.createNewCurve(curveObjectNameField.text); }; createCurveBtnAndField.Add(createNewCurveBtn); createCurveBtnAndField.Add(curveObjectNameField); } private void onActiveCurveCreationSettingsProfileChanged(CurveObjectSpawnSettingsProfile newActiveProfile) { onRefresh(); } private void createSearchToolbar(VisualElement parent) { var toolbar = UI.createStylizedToolbar(parent); _curveSearchField = new EntitySearchField(toolbar, (entityNames) => { ObjectSpawnCurveDb.instance.getCurveNames(entityNames, null); }, (name) => { _curveView.filterItems(filterCurve); }); } private bool filterCurve(ObjectSpawnCurve curve) { if (!_curveSearchField.matchName(curve.curveName)) return false; return true; } private void createCurveViewToolbar(VisualElement parent) { var toolbar = UI.createStylizedToolbar(parent); var btn = UI.createToolbarButton(TexturePool.instance.refresh, UI.ButtonStyle.Push, UIValues.smallToolbarButtonSize, toolbar); btn.tooltip = "Refresh selected curves."; btn.clicked += () => { if (_curveView != null) { getVisibleSelectedCurves(_curveBuffer); foreach (var curve in _curveBuffer) curve.refresh(ObjectSpawnCurveRefreshReason.Refresh); } }; UI.useDefaultMargins(btn); btn = UI.createToolbarButton(TexturePool.instance.sync, UI.ButtonStyle.Push, UIValues.smallToolbarButtonSize, toolbar); btn.tooltip = "Sync selected curve settings with curve creation settings."; btn.clicked += () => { if (_curveView != null) { getVisibleSelectedCurves(_curveBuffer); foreach (var curve in _curveBuffer) { curve.settings.copy(CurveObjectSpawnSettingsProfileDb.instance.activeProfile.settings); } } }; UI.useDefaultMargins(btn); btn = UI.createToolbarButton(TexturePool.instance.delete, UI.ButtonStyle.Push, UIValues.smallToolbarButtonSize, toolbar); btn.tooltip = "Delete selected curves."; btn.clicked += () => { if (_curveView != null) _curveView.deleteSelectedItems(); }; UI.useDefaultMargins(btn); } private void createCurveView(VisualElement parent) { _curveView = new ListView(_curveViewState, parent); _curveView.canDelete = true; _curveView.canRenameItems = true; _curveView.canMultiSelect = true; _curveView.canDeleteSelectedItems += onCanDeleteSelectedItems; _curveView.selectedItemsWillBeDeleted += onSelectedCurveItemsWillBeDeleted; _curveView.selectionChanged += onSelectionChanged; _curveView.selectionDeleted += onSelectionDeleted; _curveView.style.setBorderWidth(1.0f); _curveView.style.setBorderColor(UIValues.listViewBorderColor); _curveView.style.flexGrow = 1.0f; _curveView.style.height = 200.0f; } private void createCurveSettingsControls(VisualElement parent) { const float labelWidth = 130.0f; IMGUIContainer imGUIContainer = UI.createIMGUIContainer(parent); imGUIContainer.style.flexGrow = 1.0f; imGUIContainer.style.marginTop = 1.0f; imGUIContainer.onGUIHandler = () => { getVisibleSelectedCurves(_curveBuffer); _curveSpawnSettingsBuffer.Clear(); foreach (var curve in _curveBuffer) _curveSpawnSettingsBuffer.Add(curve.settings); if (_curveSpawnSettingsBuffer.Count == 0) { if (_useDefaultsBtn.isDisplayVisible()) _useDefaultsBtn.setDisplayVisible(false); imGUIContainer.style.marginLeft = 0.0f; EditorGUILayout.HelpBox("No curves selected. Select curves in order to change their settings.", MessageType.Info); return; } else { if (!_useDefaultsBtn.isDisplayVisible()) _useDefaultsBtn.setDisplayVisible(true); imGUIContainer.style.marginLeft = 3.0f; var guiContent = new GUIContent(); EditorUIEx.saveLabelWidth(); EditorUIEx.saveShowMixedValue(); EditorGUIUtility.labelWidth = labelWidth; var diff = CurveObjectSpawnSettings.checkDiff(_curveSpawnSettingsBuffer); #pragma warning disable 0612 // Curve prefab profile EditorGUI.BeginChangeCheck(); string profileName = diff.curvePrefabProfileName ? string.Empty : _curveSpawnSettingsBuffer[0].curvePrefabProfileName; string newProfileName = EditorUIEx.profileNameSelectionField (CurvePrefabProfileDb.instance, "Curve prefab profile", labelWidth, profileName, diff.curvePrefabProfileName); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.curvePrefabProfileName = newProfileName; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.CurvePrefabProfileChanged); } // Curve up axis /* EditorGUILayout.Separator(); CurveObjectSpawnUpAxis curveUpAxis = diff.curveUpAxis ? CurveObjectSpawnUpAxis.UIMixed : _curveSpawnSettingsBuffer[0].curveUpAxis; EditorGUI.showMixedValue = diff.curveUpAxis; EditorGUI.BeginChangeCheck(); guiContent.text = "Up axis"; guiContent.tooltip = "The curve up axis used when spawning objects. It specifies which way is up."; CurveObjectSpawnUpAxis newCurveUpAxis = (CurveObjectSpawnUpAxis)EditorGUILayout.EnumPopup(guiContent, curveUpAxis, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.curveUpAxis = newCurveUpAxis; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); }*/ // Invert up axis /* bool invertUpAxis = _curveSpawnSettingsBuffer[0].invertUpAxis; EditorGUI.showMixedValue = diff.invertUpAxis; EditorGUI.BeginChangeCheck(); guiContent.text = "Invert axis"; guiContent.tooltip = "If this is checked, the up axis will be inverted."; bool newInvertAxis = EditorGUILayout.Toggle(guiContent, invertUpAxis, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.invertUpAxis = newInvertAxis; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); }*/ // Avoid overlaps bool avoidOverlaps = _curveSpawnSettingsBuffer[0].avoidOverlaps; EditorGUI.showMixedValue = diff.avoidOverlaps; EditorGUI.BeginChangeCheck(); guiContent.text = "Avoid overlaps"; guiContent.tooltip = "If this is checked, no objects will be created in places where they would overlap with already existing objects. " + "Note: The checks are performed against objects that are not part of the curve. Objects that are part of the curve, are not affected and may overlap."; bool newAvoidOverlaps = EditorGUILayout.Toggle(guiContent, avoidOverlaps, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.avoidOverlaps = newAvoidOverlaps; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } // Volumeless object size float vlmsObjectSize = _curveSpawnSettingsBuffer[0].volumlessObjectSize; EditorGUI.showMixedValue = diff.volumelessObjectSize; EditorGUI.BeginChangeCheck(); guiContent.text = "Volumeless object size"; guiContent.tooltip = "The size that should be used for objects that don't have a volume."; float newVlmsObjectSize = EditorGUILayout.FloatField(guiContent, vlmsObjectSize, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.volumlessObjectSize = newVlmsObjectSize; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } // Step /* float step = _curveSpawnSettingsBuffer[0].step; EditorGUI.showMixedValue = diff.step; EditorGUI.BeginChangeCheck(); guiContent.text = "Step"; guiContent.tooltip = "When spawning objects along a curve, the curve will be approximated " + "by taking sample points using this step value. The smaller the value the better the approximation."; float newStep = EditorGUILayout.FloatField(guiContent, step, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.step = newStep; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); }*/ // Object skip chance float objectSkipChance = _curveSpawnSettingsBuffer[0].objectSkipChance; EditorGUI.showMixedValue = diff.objectSkipChance; EditorGUI.BeginChangeCheck(); guiContent.text = "Object skip chance"; guiContent.tooltip = "Specifies the probability of an object being skipped during the spawn process."; float newObjectSkipChance = EditorGUILayout.FloatField(guiContent, objectSkipChance, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.objectSkipChance = newObjectSkipChance; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } // Curve padding mode EditorGUILayout.Separator(); CurveObjectSpawnPaddingMode curvePaddingMode = diff.paddingMode ? CurveObjectSpawnPaddingMode.UIMixed : _curveSpawnSettingsBuffer[0].paddingMode; EditorGUI.showMixedValue = diff.paddingMode; EditorGUI.BeginChangeCheck(); guiContent.text = "Padding mode"; guiContent.tooltip = "Allows you to select the padding mode (i.e. constant or random). " + "Padding represents the distance between successive objects in the curve."; CurveObjectSpawnPaddingMode newCurvePaddingMode = (CurveObjectSpawnPaddingMode)EditorGUILayout.EnumPopup(guiContent, curvePaddingMode, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.paddingMode = newCurvePaddingMode; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } if (newCurvePaddingMode == CurveObjectSpawnPaddingMode.Constant) { // Padding float padding = _curveSpawnSettingsBuffer[0].padding; EditorGUI.showMixedValue = diff.padding; EditorGUI.BeginChangeCheck(); guiContent.text = "Padding"; guiContent.tooltip = "The distance between successive objects in the curve."; float newPadding = EditorGUILayout.FloatField(guiContent, padding, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.padding = newPadding; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } } else if (newCurvePaddingMode == CurveObjectSpawnPaddingMode.Random) { // Min random padding float minRandomPadding = _curveSpawnSettingsBuffer[0].minRandomPadding; EditorGUI.showMixedValue = diff.minRandomPadding; EditorGUI.BeginChangeCheck(); guiContent.text = "Min padding"; guiContent.tooltip = "The minimum random padding."; float newMinRandomPadding = EditorGUILayout.FloatField(guiContent, minRandomPadding, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.minRandomPadding = newMinRandomPadding; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } // Max random padding float maxRandomPadding = _curveSpawnSettingsBuffer[0].maxRandomPadding; EditorGUI.showMixedValue = diff.maxRandomPadding; EditorGUI.BeginChangeCheck(); guiContent.text = "Max padding"; guiContent.tooltip = "The maximum random padding."; float newMaxRandomPadding = EditorGUILayout.FloatField(guiContent, maxRandomPadding, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.maxRandomPadding = newMaxRandomPadding; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } } // Try fix overlap EditorGUILayout.Separator(); bool tryFixOverlap = _curveSpawnSettingsBuffer[0].tryFixOverlap; EditorGUI.showMixedValue = diff.tryFixOverlap; EditorGUI.BeginChangeCheck(); guiContent.text = "Try fix overlap"; guiContent.tooltip = "If checked, the plugin will attempt to ensure that curve objects will not overlap. " + "Note: This applies only to the main lane."; bool newTryFixOverlap = EditorGUILayout.Toggle(guiContent, tryFixOverlap, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.tryFixOverlap = newTryFixOverlap; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } // Lane mode EditorGUILayout.Separator(); CurveObjectSpawnLaneMode laneMode = diff.laneMode ? CurveObjectSpawnLaneMode.UIMixed : _curveSpawnSettingsBuffer[0].laneMode; EditorGUI.showMixedValue = diff.laneMode; EditorGUI.BeginChangeCheck(); guiContent.text = "Lane mode"; guiContent.tooltip = "Allows you to specify the way in which the number of lanes will be generated."; CurveObjectSpawnLaneMode newLaneMode = (CurveObjectSpawnLaneMode)EditorGUILayout.EnumPopup(guiContent, laneMode, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.laneMode = newLaneMode; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } if (newLaneMode == CurveObjectSpawnLaneMode.Constant) { // Num lanes int numLanes = _curveSpawnSettingsBuffer[0].numLanes; EditorGUI.showMixedValue = diff.numLanes; EditorGUI.BeginChangeCheck(); guiContent.text = "Num lanes"; guiContent.tooltip = "The number of lanes running parallel to each other."; int newNumLanes = EditorGUILayout.IntField(guiContent, numLanes, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.numLanes = newNumLanes; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } } else if (newLaneMode == CurveObjectSpawnLaneMode.Random) { // Min num random lanes int minNumLanes = _curveSpawnSettingsBuffer[0].minRandomNumLanes; EditorGUI.showMixedValue = diff.minRandomNumLanes; EditorGUI.BeginChangeCheck(); guiContent.text = "Min num lanes"; guiContent.tooltip = "The minimum number of lanes running parallel to each other."; int newMinNumLanes = EditorGUILayout.IntField(guiContent, minNumLanes, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.minRandomNumLanes = newMinNumLanes; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } // Max num random lanes int maxNumLanes = _curveSpawnSettingsBuffer[0].maxRandomNumLanes; EditorGUI.showMixedValue = diff.maxRandomNumLanes; EditorGUI.BeginChangeCheck(); guiContent.text = "Max num lanes"; guiContent.tooltip = "The maximum number of lanes running parallel to each other."; int newMaxNumLanes = EditorGUILayout.IntField(guiContent, maxNumLanes, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.maxRandomNumLanes = newMaxNumLanes; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } } // Lane padding mode CurveObjectSpawnLanePaddingMode lanePaddingMode = diff.lanePaddingMode ? CurveObjectSpawnLanePaddingMode.UIMixed : _curveSpawnSettingsBuffer[0].lanePaddingMode; EditorGUI.showMixedValue = diff.lanePaddingMode; EditorGUI.BeginChangeCheck(); guiContent.text = "Lane padding mode"; guiContent.tooltip = "Allows you to specify the lane padding mode. Lane padding is the distance between successive lanes."; CurveObjectSpawnLanePaddingMode newLanePaddingMode = (CurveObjectSpawnLanePaddingMode)EditorGUILayout.EnumPopup(guiContent, lanePaddingMode, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.lanePaddingMode = newLanePaddingMode; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } if (newLanePaddingMode == CurveObjectSpawnLanePaddingMode.Constant) { // Lane padding float lanePadding = _curveSpawnSettingsBuffer[0].lanePadding; EditorGUI.showMixedValue = diff.lanePadding; EditorGUI.BeginChangeCheck(); guiContent.text = "Lane padding"; guiContent.tooltip = "The distance between successive lanes."; float newLanePadding = EditorGUILayout.FloatField(guiContent, lanePadding, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.lanePadding = newLanePadding; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } } else { // Min random lane padding float minRandomLanePadding = _curveSpawnSettingsBuffer[0].minRandomLanePadding; EditorGUI.showMixedValue = diff.minRandomLanePadding; EditorGUI.BeginChangeCheck(); guiContent.text = "Min lane padding"; guiContent.tooltip = "The minimum random lane padding."; float newMinRandomLanePadding = EditorGUILayout.FloatField(guiContent, minRandomLanePadding, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.minRandomLanePadding = newMinRandomLanePadding; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } // Max random lane padding float maxRandomLanePadding = _curveSpawnSettingsBuffer[0].maxRandomLanePadding; EditorGUI.showMixedValue = diff.maxRandomLanePadding; EditorGUI.BeginChangeCheck(); guiContent.text = "Max lane padding"; guiContent.tooltip = "The maximum random lane padding."; float newMaxRandomLanePadding = EditorGUILayout.FloatField(guiContent, maxRandomLanePadding, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.maxRandomLanePadding = newMaxRandomLanePadding; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } } // Projection mode EditorGUILayout.Separator(); CurveObjectSpawnProjectionMode projectionMode = diff.projectionMode ? CurveObjectSpawnProjectionMode.UIMixed : _curveSpawnSettingsBuffer[0].projectionMode; EditorGUI.showMixedValue = diff.projectionMode; EditorGUI.BeginChangeCheck(); guiContent.text = "Projection mode"; guiContent.tooltip = "Allows you to specify how the spawned objects will be projected in the scene."; CurveObjectSpawnProjectionMode newProjectionMode = (CurveObjectSpawnProjectionMode)EditorGUILayout.EnumPopup(guiContent, projectionMode, GUILayout.ExpandWidth(true)); if (EditorGUI.EndChangeCheck()) { foreach (var s in _curveSpawnSettingsBuffer) s.projectionMode = newProjectionMode; foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.Other); } #pragma warning restore 0612 EditorUIEx.restoreShowMixedValue(); EditorUIEx.restoreLabelWidth(); } }; _useDefaultsBtn = UI.createUseDefaultsButton(() => { _curveView.getSelectedItemData(_curveBuffer); foreach (var itemData in _curveBuffer) itemData.settings.useDefaults(); foreach (var c in _curveBuffer) c.refresh(ObjectSpawnCurveRefreshReason.UseDefaultSettings); }, parent); _useDefaultsBtn.setDisplayVisible(_curveView.getNumVisibleSelectedItems() != 0); } private void onSelectionChanged(ListView listView) { SceneView.RepaintAll(); } private void onSelectionDeleted(ListView listView) { SceneView.RepaintAll(); } private void populateCurveView() { if (_curveView == null) return; _curveSearchField.refreshMatchNames(); _curveView.onBeginBuild(); ObjectSpawnCurveDb.instance.getCurves(_curveBuffer); foreach (var curve in _curveBuffer) _curveView.addItem(curve, filterCurve(curve)); _curveView.onEndBuild(); } private void onCanDeleteSelectedItems(ListView listView, List itemIds, YesNoAnswer answer) { _curveView.getItemData(itemIds, _curveBuffer); if (!askDeleteCurveObjects(_curveBuffer, out _deleteCurveObjects)) { answer.no(); return; } answer.yes(); } private bool askDeleteCurveObjects(List curves, out bool deleteCurveObjects) { deleteCurveObjects = false; int numSpawnedObjects = ObjectSpawnCurve.calcNumSpawnedObjects(curves); if (numSpawnedObjects != 0) { int answerId = EditorUtility.DisplayDialogComplex("Delete Curve Objects?", "Warning: This operation can not be undone.\nWould you also like to delete the objects associated with the curve(s)?", "Yes", "No", "Cancel"); if (answerId == 2) return false; deleteCurveObjects = (answerId == 0); } return true; } private void onSelectedCurveItemsWillBeDeleted(ListView listView, List itemIds) { _curveView.getItemData(itemIds, _curveBuffer); deleteCurves(_curveBuffer, _deleteCurveObjects); } private void deleteCurves(List curves, bool deleteCurveObjects) { if (deleteCurveObjects) { foreach (var curve in curves) curve.destroySpawnedObjectsNoUndoRedo(); } ObjectSpawnCurveDb.instance.deleteCurves(curves); } } } #endif