/// ---------------------------------------------
/// 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);
}
}
}