using System; using System.Linq; using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements; namespace UnityEditor.U2D.Sprites { /// Base class the Sprite Editor Window custom module inherits from. /// Sprite Editor Window functionality can be extended by providing custom module. By inheriting from SpriteEditorModuleBase, user will be able to activate the module's functionality from Sprite Editor Window. /// public abstract class SpriteEditorModuleBase { /// The ISpriteEditor instance that instantiated the module. /// An instance of ISpriteEditor public ISpriteEditor spriteEditor { get; internal set; } /// The module name to display in Sprite Editor Window. /// String to represent the name of the module public abstract string moduleName { get; } /// Indicates if the module can be activated with the current ISpriteEditor state. /// Return true if the module can be activated. public abstract bool CanBeActivated(); /// Implement this to draw on the Sprite Editor Window. /// Called after Sprite Editor Window draws texture preview of the Asset.Use this to draw gizmos for Sprite data. public abstract void DoMainGUI(); /// Implement this to create a custom toolbar. /// Area for drawing tool bar. public abstract void DoToolbarGUI(Rect drawArea); /// This is called when the user activates the module. /// When user switches to the module via Sprite Editor Window, this method will be called for the module to setup. public abstract void OnModuleActivate(); /// This is called when user switches to another module. /// When user switches to the another module in Sprite Editor Window, this method will be called for the module to clean up. public abstract void OnModuleDeactivate(); /// Implement this to draw widgets in Sprite Editor Window. /// This method is called last to allow drawing of widgets. public abstract void DoPostGUI(); /// This is called when user clicks on the Apply or Revert button in Sprite Editor Window. /// True when user wants to apply the data, false when user wants to revert. /// Return true to trigger a reimport. public abstract bool ApplyRevert(bool apply); } /// /// Base class for having SpriteEditorModule use as a mode in another SpriteEditorModuleBase /// internal abstract class SpriteEditorModuleModeSupportBase : SpriteEditorModuleBase { List m_Modes = new(); event Action m_OnModuleActivate; /// /// Modes that the module can be activated as. /// /// Enumerable list of mode Type that can be activated public virtual void SetModuleModes(IEnumerable modes) { m_Modes.Clear(); foreach (var t in modes) { var mode = Activator.CreateInstance(t); if (mode is SpriteEditorModeBase moduleMode) { moduleMode.spriteEditor = modeSpriteEditor; if (moduleMode.CanBeActivated()) { m_Modes.Add(moduleMode); } } } } public List modes => m_Modes; public virtual ISpriteEditor modeSpriteEditor => spriteEditor; public void RegisterModuleActivate(Action onActivate) { m_OnModuleActivate += onActivate; } public void UnregisterModuleActivate(Action onActivate) { m_OnModuleActivate -= onActivate; } public void SignalModuleActivate() { m_OnModuleActivate?.Invoke(); } } /// /// Base class for having SpriteEditorModuleBase use as a mode in another SpriteEditorModuleBase /// internal abstract class SpriteEditorModeBase : SpriteEditorModuleBase { /// /// This is called when a SpriteEditorModeBase is activated as a mode. /// /// Return true if the mode is activated public abstract bool ActivateMode(); /// /// This is called when SpriteEditorModeBase is deactivated as a mode. /// public abstract void DeactivateMode(); /// /// This is called SpriteEditorModeBase is added to a module. /// /// The module that added this mode public abstract void OnAddToModule(SpriteEditorModuleModeSupportBase module); /// /// This is called SpriteEditorModeBase is removed from a module. /// /// The module that removed this mode public abstract void OnRemoveFromModule(SpriteEditorModuleModeSupportBase module); /// /// Register a callback to be called when the mode is activated. /// /// Callback delegate public abstract void RegisterOnModeRequestActivate(Action onActivate); /// /// Unregister a previously registered callback. /// /// Callback delegate public abstract void UnregisterOnModeRequestActivate(Action onActivate); /// /// Inform the mode to apply or revert data changes. /// /// True when data needs to be apply. /// List of data provider type that has data applied before. Append to the list if new data type has changed. /// /// Return true to trigger a reimport. public abstract bool ApplyModeData(bool apply, HashSet dataProviderTypes); } /// Interface that defines the functionality available for classes that inherits SpriteEditorModuleBase. /// Used by Sprite Editor Window to encapsulate functionality accessible for Sprite Editor modules when editing Sprite data. public interface ISpriteEditor { /// Sets current available Sprite rects. List spriteRects { set; } /// The current selected Sprite rect data. SpriteRect selectedSpriteRect { get; set; } /// Indicates if ISpriteEditor should be interested in mouse move events. bool enableMouseMoveEvent { set; } /// Indicates that if Sprite data editing should be disabled; for example when the Editor is in Play Mode. bool editingDisabled { get; } /// Property that defines the window's current screen position and size. Rect windowDimension { get; } /// /// Gets data provider that is supported by the current selected object. /// /// Data provider type /// Instance of the data provider T GetDataProvider() where T : class; /// The method updates ISpriteEditor.selectedSpriteRect based on current mouse down event and ISpriteEditor.spriteRects available. /// Returns true when ISpriteEditor.selectedSpriteRect is changed. bool HandleSpriteSelection(); /// Request to repaint the current view. void RequestRepaint(); /// Indicates that there has been a change of data. In Sprite Editor Window, this enables the 'Apply' and 'Revert' button. void SetDataModified(); /// The method will inform current active SpriteEditorModuleBase to apply or revert any data changes. void ApplyOrRevertModification(bool apply); /// /// Returns a VisualElement for attaching child VisualElement onto the main view of a ISpriteEditor. /// /// Root VisualElement for the main view. /// This method returns the root VisualElement for SpriteEditorModuleBase which uses the UIElement instead of IMGUI for its UI.A VisualElement that is added to this container has the same draw order as SpriteEditorModuleBase.DoPostGUI. VisualElement GetMainVisualContainer(); /// /// Returns a VisualElement for attaching child Toolbar onto the toolbar of a ISpriteEditor. /// /// Root VisualElement for the toolbar. /// This method returns the root VisualElement for SpriteEditorModuleBase which uses the UIElement instead of IMGUI for its UI. VisualElement GetToolbarRootElement() { return null; } /// Sets a custom texture to be used by the ISpriteEditor during setup of the editing space. /// The custom preview texture. /// The width dimension to render the preview texture. /// The height dimension to render the preview texture. /// When the method is called, the editing space's dimensions are set to the width and height values, affecting operations such as Zoom and Pan in the ISpriteEditor view. The preview texture is rendered as the background of the editing space. void SetPreviewTexture(Texture2D texture, int width, int height); /// Resets the zoom and scroll of the Sprite Editor Windows. void ResetZoomAndScroll(); /// Current zoom level of the ISpriteEditor view. float zoomLevel { get; set; } /// Current scroll position of the ISpriteEditor view. Determines the viewing location of the Texture displayed Vector2 scrollPosition { get; set; } /// Whether the ISpriteEditor view is visualizing the Alpha of the Texture displayed bool showAlpha { get; set; } /// The current Mip Level of the Texture displayed in ISpriteEditor view float mipLevel { get; set; } } /// Use this attribute on a class that inherits from SpriteEditorModuleBase to indicate what data provider it needs. /// When you use this attribute, Sprite Editor Window will only make the module available for selection if ISpriteEditorDataProvider.HasDataProvider returns true for all the data providers the module needs. /// /// using UnityEditor.U2D; /// using UnityEngine; /// /// [RequireSpriteDataProvider(typeof(ISpriteOutlineDataProvider), typeof(ITextureDataProvider))] /// public class MySpriteEditorCustomModule : SpriteEditorModuleBase /// { /// public override string moduleName /// { /// get { return "MySpriteEditorCustomModule"; } /// } /// public override bool ApplyRevert(bool apply) /// { /// return true; /// } /// public override bool CanBeActivated() /// { /// return true; /// } /// public override void DoMainGUI() { } /// public override void DoToolbarGUI(Rect drawArea) { } /// public override void OnModuleActivate() /// { /// var outlineProvider = spriteEditor.GetDataProvider<ISpriteOutlineDataProvider>(); /// var spriteRects = spriteEditor.GetDataProvider<ISpriteEditorDataProvider>().GetSpriteRects(); /// foreach (var spriteRect in spriteRects) /// { /// // Access outline data /// Debug.Log(outlineProvider.GetOutlines(spriteRect.spriteID)); /// } /// } /// public override void OnModuleDeactivate() { } /// public override void DoPostGUI() { } /// } /// /// [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public class RequireSpriteDataProviderAttribute : Attribute { Type[] m_Types; /// Use the attribute to indicate the custom data provider that SpriteEditorBaseModule needs. /// Data provider type. public RequireSpriteDataProviderAttribute(params Type[] types) { m_Types = types; } internal bool ContainsAllType(ISpriteEditorDataProvider provider) { return provider == null ? false : m_Types.Where(x => { return provider.HasDataProvider(x); }).Count() == m_Types.Length; } } /// /// Attribute to indicate the module that this module can be activated as a mode in. /// [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] internal class SpriteEditorModuleModeAttribute : Attribute { Type[] m_Types; bool m_ShowAsModule; /// Use the attribute to indicate the custom data provider that SpriteEditorBaseModule needs. /// Indicate if this module should still be listed as a module. /// Type of module this can be activated as mode public SpriteEditorModuleModeAttribute(bool showAsModule = false, params Type[] types) { m_Types = types; m_ShowAsModule = showAsModule; } /// /// Indicate if this module should still be listed as a module. /// internal bool showAsModule => m_ShowAsModule; /// /// Modules that this module can be activated as a mode. /// /// List of module Type. internal IEnumerable GetModuleTypes() { return m_Types; } } }