Rasagar/Library/PackageCache/com.unity.cinemachine/Editor/Overlays/CinemachineToolbarOverlay.cs
2024-08-26 23:07:20 +03:00

428 lines
17 KiB
C#

#if UNITY_2021_2_OR_NEWER
using System;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.Overlays;
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.UIElements;
using System.Collections.Generic;
namespace Cinemachine.Editor
{
#if UNITY_2022_1_OR_NEWER
/// <summary>
/// This is a generic Tool class for Cinemachine tools.
/// To create a new tool, inherit from CinemachineTool and implement GetIcon().
/// Your new tool will need to have the [EditorTool("tool-name", typeof(CinemachineVirtualCameraBase))] attribute.
///
/// A tool will be drawn iff it has been registered using CinemachineSceneToolUtility.RegisterTool.
/// This is generally done in the OnEnable function of the editor script of the cinemachine component
/// (CinemachineVirtualCamera, CinemachineComponentBase), for which the tool was meant.
/// To unregister, call CinemachineSceneToolUtility.UnregisterTool in the same script's OnDisable function.
///
/// To draw the handles related to the tool, you need to implement your drawing function and call it in the
/// editor script's OnSceneGUI function. An alternative for drawing handles is to override this function's
/// OnToolGUI or OnDrawHandles functions (see EditorTool or IDrawSelectedHandles docs for more information).
///
/// To check, if a tool has been enabled/disabled in the editor script, use CinemachineSceneToolUtility.IsToolActive.
/// </summary>
public abstract class CinemachineTool : EditorTool, IDrawSelectedHandles
{
GUIContent m_IconContent;
/// <summary>Implement this to set your Tool's icon and tooltip.</summary>
/// <returns>A GUIContent with an icon set.</returns>
protected abstract GUIContent GetIcon();
/// <summary>This lets the editor find the icon of the tool.</summary>
public override GUIContent toolbarIcon
{
get
{
if (m_IconContent == null || m_State.refreshIcon)
{
m_IconContent = GetIcon();
m_State.refreshIcon = false;
}
return m_IconContent;
}
}
/// <summary>This is called when the Tool is selected in the editor.</summary>
public override void OnActivated()
{
base.OnActivated();
CinemachineSceneToolUtility.SetTool(true, GetType());
m_State.refreshIcon = true;
m_State.isSelected = true;
}
/// <summary>This is called when the Tool is deselected in the editor.</summary>
public override void OnWillBeDeactivated()
{
base.OnWillBeDeactivated();
CinemachineSceneToolUtility.SetTool(false, GetType());
m_State.refreshIcon = true;
m_State.isSelected = false;
}
/// <summary>This checks whether this tool should be displayed or not.</summary>
/// <returns>True, when this tool is to be drawn. False, otherwise.</returns>
public override bool IsAvailable() => CinemachineSceneToolUtility.IsToolRequired(GetType());
/// <summary>Implement IDrawSelectedHandles to draw gizmos for this tool even if it is not the active tool.</summary>
public void OnDrawHandles()
{
}
private protected string GetIconPath()
{
m_State.refreshIcon = m_State.isProSkin != EditorGUIUtility.isProSkin;
m_State.isProSkin = EditorGUIUtility.isProSkin;
return ScriptableObjectUtility.CinemachineRealativeInstallPath + "/Editor/EditorResources/Handles/" +
(m_State.isProSkin ?
(m_State.isSelected ? "Dark-Selected" : "Dark") :
(m_State.isSelected ? "Light-Selected" : "Light")) + "/";
}
struct ToolState
{
public bool isSelected;
public bool isProSkin;
public bool refreshIcon;
}
ToolState m_State = new ToolState { refreshIcon = true };
}
[EditorTool("Field of View Tool", typeof(CinemachineVirtualCameraBase))]
class FoVTool : CinemachineTool
{
protected override GUIContent GetIcon() =>
new GUIContent
{
image = AssetDatabase.LoadAssetAtPath<Texture2D>(GetIconPath() + "FOV.png"),
tooltip = "Field of View Tool",
};
}
[EditorTool("Far-Near Clip Tool", typeof(CinemachineVirtualCameraBase))]
class FarNearClipTool : CinemachineTool
{
protected override GUIContent GetIcon() =>
new GUIContent
{
image = AssetDatabase.LoadAssetAtPath<Texture2D>(GetIconPath() + "FarNearClip.png"),
tooltip = "Far/Near Clip Tool",
};
}
[EditorTool("Follow Offset Tool", typeof(CinemachineVirtualCameraBase))]
class FollowOffsetTool : CinemachineTool
{
protected override GUIContent GetIcon() =>
new GUIContent
{
image = AssetDatabase.LoadAssetAtPath<Texture2D>(GetIconPath() + "FollowOffset.png"),
tooltip = "Follow Offset Tool",
};
}
[EditorTool("Tracked Object Offset Tool", typeof(CinemachineVirtualCameraBase))]
class TrackedObjectOffsetTool : CinemachineTool
{
protected override GUIContent GetIcon() =>
new GUIContent
{
image = AssetDatabase.LoadAssetAtPath<Texture2D>(GetIconPath() + "TrackedObjectOffset.png"),
tooltip = "Tracked Object Offset Tool",
};
}
#if false // We disable this tool window, because it has only one thing in it, which isn't so useful and is a bit confusing tbh
/// <summary>
/// To add your custom tools (EditorToolbarElement) to the Cinemachine Tool Settings toolbar,
/// set CinemachineToolSettingsOverlay.customToolbarItems with your custom tools' IDs.
///
/// By default, CinemachineToolSettingsOverlay.customToolbarItems is null.
/// </summary>
[Overlay(typeof(SceneView), "Cinemachine Tool Settings")]
[Icon("Packages/com.unity.cinemachine/Gizmos/cm_logo.png")]
public class CinemachineToolSettingsOverlay : Overlay, ICreateToolbar
{
static readonly string[] k_CmToolbarItems = { FreelookRigSelection.id };
/// <summary>
/// Override this method to return your visual element content.
/// By default, this draws the same visual element as the HorizontalToolbar
/// </summary>
/// <returns>VisualElement for the Panel conent.</returns>
public override VisualElement CreatePanelContent() => CreateContent(Layout.HorizontalToolbar);
/// <summary>Set this with your custom tools' IDs.</summary>
public static string[] customToolbarItems = null;
/// <summary>The list of tools that this toolbar is going to contain.</summary>
public IEnumerable<string> toolbarElements
{
get
{
if (customToolbarItems != null)
{
var toolbarItems = new List<string>(k_CmToolbarItems);
toolbarItems.AddRange(customToolbarItems);
return toolbarItems;
}
return k_CmToolbarItems;
}
}
}
[EditorToolbarElement(id, typeof(SceneView))]
class FreelookRigSelection : EditorToolbarDropdown
{
public const string id = "FreelookRigSelection/Dropdown";
public static int SelectedRig;
Texture2D[] m_Icons;
public FreelookRigSelection()
{
tooltip = "Freelook Rig Selection";
clicked += FreelookRigSelectionMenu;
EditorApplication.update += ShadowSelectedRigName;
EditorApplication.update += DisplayIfRequired;
m_Icons = new Texture2D[]
{
AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/FreelookRigTop.png"),
AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/FreelookRigMiddle.png"),
AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/FreelookRigBottom.png"),
};
}
~FreelookRigSelection()
{
clicked -= FreelookRigSelectionMenu;
EditorApplication.update -= ShadowSelectedRigName;
EditorApplication.update -= DisplayIfRequired;
}
Type m_FreelookRigSelectionType = typeof(FreelookRigSelection);
void DisplayIfRequired() => style.display =
CinemachineSceneToolUtility.IsToolRequired(m_FreelookRigSelectionType)
? DisplayStyle.Flex : DisplayStyle.None;
// text is currently only visibly in Panel mode due to this bug: https://jira.unity3d.com/browse/STO-2278
void ShadowSelectedRigName()
{
var index = Mathf.Clamp(SelectedRig, 0, CinemachineFreeLookEditor.RigNames.Length - 1);
text = CinemachineFreeLookEditor.RigNames[index].text;
icon = m_Icons[index];
}
void FreelookRigSelectionMenu()
{
var menu = new GenericMenu();
for (var i = 0; i < CinemachineFreeLookEditor.RigNames.Length; ++i)
{
var rigIndex = i; // vital to capture the index here for the lambda below
menu.AddItem(CinemachineFreeLookEditor.RigNames[i], false, () =>
{
SelectedRig = rigIndex;
var active = Selection.activeObject as GameObject;
if (active != null)
{
var freelook = active.GetComponent<CinemachineFreeLook>();
if (freelook != null)
CinemachineFreeLookEditor.SetSelectedRig(freelook, rigIndex);
}
});
}
menu.DropDown(worldBound);
}
}
#endif
#else
/// <summary>
/// To display a CinemachineExclusiveEditorToolbarToggle in the Cinemachine Toolbar.
/// </summary>
[Overlay(typeof(SceneView), "Cinemachine")]
[Icon("Packages/com.unity.cinemachine/Gizmos/cm_logo.png")]
class CinemachineToolbarOverlay : ToolbarOverlay
{
public CinemachineToolbarOverlay()
: base(
//FreelookRigSelection.id,
FoVTool.id,
FarNearClipTool.id,
FollowOffsetTool.id,
TrackedObjectOffsetTool.id
)
{
CinemachineSceneToolUtility.RegisterToolbarIsDisplayedHandler(() => displayed);
CinemachineSceneToolUtility.RegisterToolbarDisplayHandler(v =>
{
if (displayed == v)
{
return false;
}
displayed = v;
return true;
});
}
}
/// <summary>
/// Creates a toggle tool on the Cinemachine toolbar that is exclusive with other
/// CinemachineExclusiveEditorToolbarToggles. Meaning, that maximum one
/// CinemachineExclusiveEditorToolbarToggle can be active at any time.
/// </summary>
abstract class CinemachineExclusiveEditorToolbarToggle : EditorToolbarToggle
{
protected CinemachineExclusiveEditorToolbarToggle()
{
var type = GetType();
this.RegisterValueChangedCallback(
v => CinemachineSceneToolUtility.SetTool(v.newValue, type));
CinemachineSceneToolUtility.RegisterExclusiveToolHandlers(type, isOn => value = isOn,
display => style.display = display ? DisplayStyle.Flex : DisplayStyle.None);
}
}
[EditorToolbarElement(id, typeof(SceneView))]
class FoVTool : CinemachineExclusiveEditorToolbarToggle
{
public const string id = "FoVTool/Toggle";
public FoVTool()
{
icon = AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/Dark/FOV.png");
tooltip = "Field of View Tool";
}
}
[EditorToolbarElement(id, typeof(SceneView))]
class FarNearClipTool : CinemachineExclusiveEditorToolbarToggle
{
public const string id = "FarNearClipTool/Toggle";
public FarNearClipTool()
{
icon = AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/Dark/FarNearClip.png");
tooltip = "Far/Near Clip Tool";
}
}
[EditorToolbarElement(id, typeof(SceneView))]
class FollowOffsetTool : CinemachineExclusiveEditorToolbarToggle
{
public const string id = "FollowOffsetTool/Toggle";
public FollowOffsetTool()
{
icon = AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/Dark/FollowOffset.png");
tooltip = "Follow Offset Tool";
}
}
[EditorToolbarElement(id, typeof(SceneView))]
class TrackedObjectOffsetTool : CinemachineExclusiveEditorToolbarToggle
{
public const string id = "TrackedObjectOffsetTool/Toggle";
public TrackedObjectOffsetTool()
{
icon = AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/Dark/TrackedObjectOffset.png");
tooltip = "Tracked Object Offset Tool";
}
}
/// <summary>
/// Creates a toggle tool on the Cinemachine toolbar.
/// </summary>
abstract class CinemachineEditorToolbarToggle : EditorToolbarToggle
{
protected CinemachineEditorToolbarToggle()
{
CinemachineSceneToolUtility.RegisterToolHandlers(GetType(), isOn => value = isOn,
display => style.display = display ? DisplayStyle.Flex : DisplayStyle.None);
}
}
#if false
[EditorToolbarElement(id, typeof(SceneView))]
class FreelookRigSelection : EditorToolbarDropdown
{
public const string id = "FreelookRigSelection/Dropdown";
public static int SelectedRig;
Texture2D[] m_Icons;
public FreelookRigSelection()
{
tooltip = "Freelook Rig Selection";
clicked += FreelookRigSelectionMenu;
CinemachineSceneToolUtility.RegisterToolHandlers(GetType(), isOn => {},
display => style.display = display ? DisplayStyle.Flex : DisplayStyle.None);
EditorApplication.update += ShadowSelectedRigName;
m_Icons = new Texture2D[]
{
AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/FreelookRigTop.png"),
AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/FreelookRigMiddle.png"),
AssetDatabase.LoadAssetAtPath<Texture2D>(ScriptableObjectUtility.CinemachineRealativeInstallPath
+ "/Editor/EditorResources/Handles/FreelookRigBottom.png"),
};
}
~FreelookRigSelection()
{
clicked -= FreelookRigSelectionMenu;
EditorApplication.update -= ShadowSelectedRigName;
}
void ShadowSelectedRigName()
{
var index = Mathf.Clamp(SelectedRig, 0, CinemachineFreeLookEditor.RigNames.Length - 1);
icon = m_Icons[index];
text = CinemachineFreeLookEditor.RigNames[index].text;
}
void FreelookRigSelectionMenu()
{
var menu = new GenericMenu();
for (var i = 0; i < CinemachineFreeLookEditor.RigNames.Length; ++i)
{
var rigIndex = i; // vital to capture the index here for the lambda below
menu.AddItem(CinemachineFreeLookEditor.RigNames[i], false, () =>
{
SelectedRig = rigIndex;
var active = Selection.activeObject as GameObject;
if (active != null)
{
var freelook = active.GetComponent<CinemachineFreeLook>();
if (freelook != null)
CinemachineFreeLookEditor.SetSelectedRig(freelook, rigIndex);
}
});
}
menu.DropDown(worldBound);
}
}
#endif
#endif
}
#endif