// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved. // This code can only be used under the standard Unity Asset Store End User License Agreement // A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms using System; using System.Collections.Generic; using System.Linq; using Doozy.Editor.Common.Extensions; using Doozy.Editor.EditorUI; using Doozy.Editor.EditorUI.Components; using Doozy.Editor.EditorUI.Utils; using Doozy.Runtime.UIElements.Extensions; using Doozy.Runtime.UIManager; using UnityEditor; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; namespace Doozy.Editor.UIManager.Drawers { [CustomPropertyDrawer(typeof(UIBehaviours), true)] public class UIBehavioursDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {} private static IEnumerable emptyPlaceholderTextures => EditorSpriteSheets.EditorUI.Placeholders.Empty; private static string drawerTitle => "Available Behaviours"; public override VisualElement CreatePropertyGUI(SerializedProperty property) { var uiBehaviours = property.GetTargetObjectOfProperty() as UIBehaviours; var drawer = new VisualElement(); FluidButton addBehaviourButton = FluidButton.Get() .SetIcon(EditorSpriteSheets.EditorUI.Icons.Plus) .SetAccentColor(DesignUtils.callbackSelectableColor) .SetLabelText("Add Behaviour") .SetButtonStyle(ButtonStyle.Contained) .SetElementSize(ElementSize.Tiny); var availableBehaviours = new List(Enum.GetValues(typeof(UIBehaviour.Name)).Cast()); var availableBehavioursPopupField = new PopupField(availableBehaviours, UIBehaviour.Name.PointerClick); FluidField availableBehavioursField = FluidField.Get(drawerTitle); FluidPlaceholder placeholder = FluidPlaceholder.Get().SetIcon(emptyPlaceholderTextures).ResizeToHeight(35); FluidField placeholderField = FluidField.Get().AddFieldContent(placeholder); placeholderField.AddManipulator(new Clickable(() => placeholder?.Play())); SerializedProperty signalSourceProperty = property.FindPropertyRelative("SignalSource"); SerializedProperty behavioursProperty = property.FindPropertyRelative("Behaviours"); availableBehavioursPopupField.RegisterValueChangedCallback(evt => { var behaviourName = evt.newValue; availableBehavioursField.SetIcon(UIBehaviourDrawer.GetBehaviourTextures(behaviourName)); availableBehavioursField.iconReaction.Play(); addBehaviourButton.SetEnabled(uiBehaviours != null && !uiBehaviours.HasBehaviour(behaviourName)); UpdateAddBehaviourButtonTooltip(behaviourName); }); availableBehavioursPopupField.schedule.Execute(() => UpdateAddBehaviourButtonTooltip(availableBehavioursPopupField.value)); addBehaviourButton.SetEnabled(uiBehaviours != null && !uiBehaviours.HasBehaviour(availableBehavioursPopupField.value)); availableBehavioursField .SetIcon(UIBehaviourDrawer.GetBehaviourTextures(availableBehavioursPopupField.value)) .AddFieldContent(availableBehavioursPopupField) .AddInfoElement(DesignUtils.flexibleSpace) .AddInfoElement(addBehaviourButton); FluidAnimatedContainer behavioursContainer = new FluidAnimatedContainer("Behaviours", false).Show(false) .SetStyleMarginTop(DesignUtils.k_Spacing) .SetStyleMarginBottom(DesignUtils.k_Spacing); var minusButtons = new List(); Refresh(); void Refresh() { foreach (FluidButton minusButton in minusButtons) minusButton.Recycle(); minusButtons.Clear(); availableBehaviours.Clear(); availableBehaviours.AddRange(Enum.GetValues(typeof(UIBehaviour.Name)).Cast()); behavioursContainer.ClearContent(); for (int i = 0; i < behavioursProperty.arraySize; i++) { SerializedProperty behaviourProperty = behavioursProperty.GetArrayElementAtIndex(i); var behaviourName = (UIBehaviour.Name)behaviourProperty.FindPropertyRelative("BehaviourName").enumValueIndex; availableBehaviours.Remove(behaviourName); minusButtons.Add ( GetMinusButton() .SetTooltip($"Remove '{ObjectNames.NicifyVariableName(behaviourName.ToString())}' Behaviour") .SetOnClick(() => { if (property.serializedObject == null) return; if (uiBehaviours == null) return; Undo.RecordObject(property.serializedObject.targetObject, $"Remove Behaviour"); uiBehaviours.RemoveBehaviour(behaviourName); Refresh(); property.serializedObject.ApplyModifiedPropertiesWithoutUndo(); }) ); behavioursContainer.AddContent ( DesignUtils.row .SetStyleMarginBottom(DesignUtils.k_Spacing) .AddChild(DesignUtils.NewPropertyField(behaviourProperty)) .AddSpaceBlock() .AddChild(minusButtons[minusButtons.Count - 1]) ); } behavioursContainer.Bind(property.serializedObject); placeholderField.SetStyleDisplay(availableBehaviours.Count == 0 ? DisplayStyle.Flex : DisplayStyle.None); placeholder.Toggle(availableBehaviours.Count == 0); availableBehavioursField.SetStyleDisplay(availableBehaviours.Count == 0 ? DisplayStyle.None : DisplayStyle.Flex); if (availableBehaviours.Count > 0) availableBehavioursPopupField.value = availableBehaviours.First(); addBehaviourButton.SetEnabled(!uiBehaviours.HasBehaviour(availableBehavioursPopupField.value)); } addBehaviourButton .SetOnClick(() => { if (property.serializedObject == null) return; if (uiBehaviours == null) return; Undo.RecordObject(property.serializedObject.targetObject, "Add Behaviour"); uiBehaviours.AddBehaviour(availableBehavioursPopupField.value); Refresh(); property.serializedObject.ApplyModifiedPropertiesWithoutUndo(); }); void UpdateAddBehaviourButtonTooltip(UIBehaviour.Name behaviourName) => addBehaviourButton.SetTooltip($"Add the '{ObjectNames.NicifyVariableName(behaviourName.ToString())}' behaviour and remove it from the {drawerTitle} drawer"); int arraySize = -1; drawer.schedule.Execute(() => { if (arraySize == behavioursProperty.arraySize) return; arraySize = behavioursProperty.arraySize; Refresh(); }).Every(200); drawer.RegisterCallback(evt => { availableBehavioursField?.Recycle(); addBehaviourButton?.Recycle(); behavioursContainer?.Dispose(); }); drawer .AddChild(availableBehavioursField) .AddChild(placeholderField) .AddChild(behavioursContainer); return drawer; } private static FluidButton GetMinusButton() => FluidButton.Get() .SetIcon(EditorSpriteSheets.EditorUI.Icons.Minus) .SetAccentColor(EditorSelectableColors.Default.Remove) .SetElementSize(ElementSize.Small); } }