| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- #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
|