/// --------------------------------------------- /// Movement Pack for Behavior Designer Pro /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.BehaviorDesigner.AddOns.SensesPack.Editor { using Opsive.BehaviorDesigner.AddOns.SensesPack.Runtime.Sensors; using Opsive.BehaviorDesigner.Editor; using Opsive.Shared.Editor.UIElements; using Opsive.Shared.Editor.UIElements.Controls; using Opsive.Shared.Editor.UIElements.Controls.Attributes; using Opsive.Shared.Utility; using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.UIElements; /// /// Implements AttributeControlBase for the CastDetectionModeListAttribute type. /// [ControlType(typeof(CastDetectionModeListAttribute))] public class CastDetectionModesAttributeControl : AttributeControlBase { /// /// The CastDetectionModeView displays the contents of the CastDetectionMode. /// public class CastDetectionModeView : VisualElement { protected UnityEngine.Object m_UnityObject; protected CastDetectionMode[] m_CastDetectionModes; protected Func m_OnChangeEvent; private ReorderableList m_ReorderableList; private int m_SelectedIndex = 0; private VisualElement m_CastDetectionModeContainer; /// /// CastDetectionModeView constructor. /// /// A reference to the owning Unity Object. /// The CastDetectionModes being drawn. /// An event that is sent when the value changes. Returns false if the control cannot be changed. public CastDetectionModeView(UnityEngine.Object unityObject, CastDetectionMode[] castDetectionModes, Func onChangeEvent) { m_UnityObject = unityObject; m_CastDetectionModes = castDetectionModes; m_OnChangeEvent = onChangeEvent; var graphWindow = BehaviorDesignerWindow.Instance; m_ReorderableList = new ReorderableList(m_CastDetectionModes, (VisualElement parent, int index) => { parent.Add(new Label()); }, (VisualElement parent, int index) => { (parent.ElementAt(0) as Label).text = m_CastDetectionModes[index].GetType().Name; }, (VisualElement parent) => { parent.Add(new Label("Cast Detection Modes")); }, (int index) => { ShowSelectedCastDetectionMode(index); }, () => // Add. { FilterWindow.ShowFilterWindow(graphWindow, new SearchWindowContext(graphWindow.position.position + m_ReorderableList.AddButton.worldBound.position), new Type[] { typeof(CastDetectionMode) }, FilterWindow.FilterType.Class, "Detection Mode", false, null, OnAdd, (Type type) => { return typeof(CastDetectionMode).IsAssignableFrom(type); }); }, (int index) => // Remove. { ArrayUtility.RemoveAt(ref m_CastDetectionModes, index); m_ReorderableList.EnableRemove = m_CastDetectionModes.Length > 1 && !Application.isPlaying; m_ReorderableList.Refresh(m_CastDetectionModes); m_OnChangeEvent(m_CastDetectionModes); m_SelectedIndex = Mathf.Clamp(m_SelectedIndex - 1, 0, m_CastDetectionModes.Length - 1); ShowSelectedCastDetectionMode(m_SelectedIndex); }, (int fromIndex, int toIndex) => // Reorder. { m_OnChangeEvent(m_CastDetectionModes); if (m_SelectedIndex == fromIndex) { ShowSelectedCastDetectionMode(toIndex); } }); m_ReorderableList.EnableAdd = m_ReorderableList.EnableReorder = !Application.isPlaying; m_ReorderableList.EnableRemove = (m_CastDetectionModes != null && m_CastDetectionModes.Length > 1) && !Application.isPlaying; Add(m_ReorderableList); // Show any detection mode fields. m_CastDetectionModeContainer = new VisualElement(); m_CastDetectionModeContainer.style.marginBottom = 4; m_CastDetectionModeContainer.style.display = DisplayStyle.Flex; Add(m_CastDetectionModeContainer); ShowSelectedCastDetectionMode(m_SelectedIndex); if (m_CastDetectionModes != null && m_SelectedIndex < m_CastDetectionModes.Length) { m_ReorderableList.SelectedIndex = m_SelectedIndex; } } /// /// Adds a new detection mode to the array. /// /// The selected task type. /// The base type that was used to find the element. /// The position of the FilterWindow. private void OnAdd(object selectedObject, Type baseType, Vector2 windowPosition) { if (selectedObject == null) { return; } if (m_CastDetectionModes == null) { m_CastDetectionModes = new CastDetectionMode[1]; } else { Array.Resize(ref m_CastDetectionModes, m_CastDetectionModes.Length + 1); } m_CastDetectionModes[m_CastDetectionModes.Length - 1] = Activator.CreateInstance((Type)selectedObject) as CastDetectionMode; m_ReorderableList.Refresh(m_CastDetectionModes); m_ReorderableList.SelectedIndex = m_CastDetectionModes.Length - 1; m_ReorderableList.EnableRemove = m_CastDetectionModes.Length > 1 && !Application.isPlaying; m_OnChangeEvent(m_CastDetectionModes); } /// /// Shows the selected detection mode. /// /// The index of the detection mode within the detection mode array. private void ShowSelectedCastDetectionMode(int index) { m_SelectedIndex = index; m_CastDetectionModeContainer.Clear(); if (m_CastDetectionModes == null || m_CastDetectionModes.Length <= m_SelectedIndex) { return; } var label = new Label(); label.enableRichText = true; label.style.marginLeft = 3; label.style.unityTextAlign = TextAnchor.MiddleCenter; label.text = $"{m_CastDetectionModes[index].GetType().Name}"; label.tooltip = m_CastDetectionModes[index].GetType().FullName; m_CastDetectionModeContainer.Add(label); FieldInspectorView.AddFields(m_UnityObject, m_CastDetectionModes[index], MemberVisibility.Public, m_CastDetectionModeContainer, (object obj) => { m_CastDetectionModes[index] = obj as CastDetectionMode; m_OnChangeEvent?.Invoke(m_CastDetectionModes); }); } } /// /// Does the control use a label? /// public override bool UseLabel { get { return false; } } /// /// Does the attribute override the type control? /// public override bool OverrideTypeControl => true; /// /// Returns the control that should be used for the specified AttributeControlType. /// /// The input to the control. /// The created control. protected override VisualElement GetControl(AttributeControlInput input) { return new CastDetectionModeView(input.UnityObject, input.Value as CastDetectionMode[], input.OnChangeEvent); } } }