Files
GameDevTVObstacleDodge/Library/PackageCache/com.unity.cinemachine@5342685532bb/Editor/Editors/CinemachineFreeLookModifierEditor.cs

174 lines
7.7 KiB
C#
Raw Normal View History

2026-01-08 16:50:20 +00:00
using UnityEditor;
using System.Collections.Generic;
using System;
using System.Reflection;
using Unity.Cinemachine.Editor;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
namespace Unity.Cinemachine
{
[CustomEditor(typeof(CinemachineFreeLookModifier))]
class CinemachineFreeLookModifierEditor : UnityEditor.Editor
{
CinemachineFreeLookModifier Target => target as CinemachineFreeLookModifier;
public override VisualElement CreateInspectorGUI()
{
var ux = new VisualElement();
var instructionsMsg = ux.AddChild(new HelpBox("This component is optional and can be removed if you don't need it. "
+ "The modifiers you add will override settings for the top and bottom portions "
+ "of the camera's vertical orbit.",
HelpBoxMessageType.Info));
var invalidSrcMsg = ux.AddChild(
new HelpBox("This component will be ignored because no modifiable targets are present.\n"
+ "<b>You can remove this component.\n</b>Modifiable targets include: "
+ InspectorUtility.GetAssignableBehaviourNames(
typeof(CinemachineFreeLookModifier.IModifierValueSource)),
HelpBoxMessageType.Warning));
ux.Add(new PropertyField(serializedObject.FindProperty(nameof(Target.Easing))));
var controllersProperty = serializedObject.FindProperty(nameof(Target.Modifiers));
ux.Add(new Label(controllersProperty.displayName)
{ tooltip = controllersProperty.tooltip , style = { marginLeft = 3, marginTop = 6 }});
var list = ux.AddChild(new ListView()
{
reorderable = false,
showAddRemoveFooter = true,
showBorder = true,
showBoundCollectionSize = false,
showFoldoutHeader = false,
virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight,
style = { marginLeft = 3 }
});
list.BindProperty(controllersProperty);
// Convert the add button to a popup selector
var button = list.Q<Button>("unity-list-view__add-button");
var manipulator = new ContextualMenuManipulator((evt) =>
{
for (int i = 0; i < ModifierMenuItems.s_ModifierNames.Count; ++i)
{
var type = ModifierMenuItems.s_AllModifiers[i];
evt.menu.AppendAction(ModifierMenuItems.s_ModifierNames[i],
(action) =>
{
Undo.RecordObject(Target, "add modifier");
var m = (CinemachineFreeLookModifier.Modifier)Activator.CreateInstance(type);
m.RefreshCache(Target.ComponentOwner);
m.Reset(Target.ComponentOwner);
Target.Modifiers.Add(m);
},
(status) =>
{
// Enable item if not already present
for (int m = 0; m < Target.Modifiers.Count; ++m)
if (Target.Modifiers[m] != null && Target.Modifiers[m].GetType() == type)
return DropdownMenuAction.Status.Disabled;
return DropdownMenuAction.Status.Normal;
});
}
});
manipulator.activators.Clear();
manipulator.activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse });
button.AddManipulator(manipulator);
button.clickable = null;
ux.TrackAnyUserActivity(() =>
{
if (Target == null)
return;
var hasModifiableSource = Target.HasValueSource();
var hasModifiers = Target.Modifiers.Count > 0;
invalidSrcMsg.SetVisible(!hasModifiableSource);
instructionsMsg.SetVisible(hasModifiableSource && !hasModifiers);
});
return ux;
}
[CustomPropertyDrawer(typeof(CinemachineFreeLookModifier.Modifier), true)]
class FreeLookModifierItemPropertyDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
if (property.managedReferenceValue is not CinemachineFreeLookModifier.Modifier m)
return new Label("invalid item");
var warningText = "No applicable targets found. Applicable targets include: "
+ InspectorUtility.GetAssignableBehaviourNames(m.CachedComponentType);
var overlay = new VisualElement { style = { flexDirection = FlexDirection.Row, flexGrow = 1 }};
var warningSymbol = overlay.AddChild(InspectorUtility.MiniHelpIcon(warningText));
var typeName = ModifierMenuItems.GetModifierName(m.GetType());
var foldout = new Foldout() { text = typeName, tooltip = property.tooltip };
foldout.BindProperty(property);
var noComponentsMsg = foldout.AddChild(new HelpBox(warningText, HelpBoxMessageType.Warning));
var childProperty = property.Copy();
var endProperty = childProperty.GetEndProperty();
childProperty.NextVisible(true);
while (!SerializedProperty.EqualContents(childProperty, endProperty))
{
foldout.Add(new PropertyField(childProperty));
childProperty.NextVisible(false);
}
foldout.TrackAnyUserActivity(() =>
{
var showWarning = m != null && !m.HasRequiredComponent;
noComponentsMsg.SetVisible(showWarning);
warningSymbol.SetVisible(showWarning);
});
var ux = new InspectorUtility.FoldoutWithOverlay(foldout, overlay, null);
ux.style.marginLeft = 12;
ux.style.marginRight = 6;
return ux;
}
}
[InitializeOnLoad]
static class ModifierMenuItems
{
public static string GetModifierName(Type type)
{
for (int j = 0; j < s_AllModifiers.Count; ++j)
if (s_AllModifiers[j] == type)
return s_ModifierNames[j];
return "(none)"; // should never get here
}
// These lists are synchronized
public static List<Type> s_AllModifiers = new ();
public static List<string> s_ModifierNames = new ();
// This code dynamically discovers eligible classes and builds the menu data
static ModifierMenuItems()
{
// Get all Modifier types
var allTypes = ReflectionHelpers.GetTypesDerivedFrom(typeof(CinemachineFreeLookModifier.Modifier),
(t) => !t.IsAbstract && t.GetCustomAttribute<ObsoleteAttribute>() == null);
s_AllModifiers.Clear();
s_ModifierNames.Clear();
s_AllModifiers.AddRange(allTypes);
for (int i = 0; i < s_AllModifiers.Count; ++i)
{
var name = s_AllModifiers[i].Name;
var index = name.LastIndexOf("Modifier", StringComparison.OrdinalIgnoreCase);
if (index >= 0)
name = name.Remove(index);
s_ModifierNames.Add(InspectorUtility.NicifyClassName(name));
}
}
}
}
}