ContextualMenuDispatcher.cs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. namespace UnityEditor.Rendering
  6. {
  7. static class ContextualMenuDispatcher
  8. {
  9. [MenuItem("CONTEXT/Camera/Remove Component")]
  10. static void RemoveCameraComponent(MenuCommand command)
  11. {
  12. Camera camera = command.context as Camera;
  13. string error;
  14. if (!DispatchRemoveComponent(camera))
  15. {
  16. //preserve built-in behavior
  17. if (CanRemoveComponent(camera, out error))
  18. Undo.DestroyObjectImmediate(command.context);
  19. else
  20. EditorUtility.DisplayDialog("Can't remove component", error, "Ok");
  21. }
  22. }
  23. static bool DispatchRemoveComponent<T>(T component)
  24. where T : Component
  25. {
  26. Type type = RenderPipelineEditorUtility.FetchFirstCompatibleTypeUsingScriptableRenderPipelineExtension<IRemoveAdditionalDataContextualMenu<T>>();
  27. if (type != null)
  28. {
  29. IRemoveAdditionalDataContextualMenu<T> instance = (IRemoveAdditionalDataContextualMenu<T>)Activator.CreateInstance(type);
  30. instance.RemoveComponent(component, ComponentDependencies(component));
  31. return true;
  32. }
  33. return false;
  34. }
  35. static IEnumerable<Component> ComponentDependencies(Component component)
  36. => component.gameObject
  37. .GetComponents<Component>()
  38. .Where(c => c != component
  39. && c.GetType()
  40. .GetCustomAttributes(typeof(RequireComponent), true)
  41. .Count(att => att is RequireComponent rc
  42. && (rc.m_Type0 == component.GetType()
  43. || rc.m_Type1 == component.GetType()
  44. || rc.m_Type2 == component.GetType())) > 0);
  45. static bool CanRemoveComponent(Component component, out string error)
  46. {
  47. var dependencies = ComponentDependencies(component);
  48. if (dependencies.Count() == 0)
  49. {
  50. error = null;
  51. return true;
  52. }
  53. Component firstDependency = dependencies.First();
  54. error = $"Can't remove {component.GetType().Name} because {firstDependency.GetType().Name} depends on it.";
  55. return false;
  56. }
  57. }
  58. /// <summary>
  59. /// Interface that should be used with [ScriptableRenderPipelineExtension(type))] attribute to dispatch ContextualMenu calls on the different SRPs
  60. /// </summary>
  61. /// <typeparam name="T">This must be a component that require AdditionalData in your SRP</typeparam>
  62. public interface IRemoveAdditionalDataContextualMenu<T>
  63. where T : Component
  64. {
  65. /// <summary>
  66. /// Remove the given component
  67. /// </summary>
  68. /// <param name="component">The component to remove</param>
  69. /// <param name="dependencies">Dependencies.</param>
  70. void RemoveComponent(T component, IEnumerable<Component> dependencies);
  71. }
  72. }