A game about forced loneliness, made by TACStudios
at master 1558 lines 61 kB view raw
1using System; 2using UnityEngine; 3using System.Collections.Generic; 4using System.IO; 5using UnityTexture2D = UnityEngine.Texture2D; 6using System.Linq; 7using System.Reflection; 8using UnityEditor.Overlays; 9using UnityEngine.UIElements; 10 11namespace UnityEditor.U2D.Sprites 12{ 13 /// <summary> 14 /// Interface for providing a ISpriteEditorDataProvider instance. 15 /// </summary> 16 /// <typeparam name="T">The object type the implemented interface is interested in.</typeparam> 17 public interface ISpriteDataProviderFactory<T> 18 { 19 /// <summary> 20 /// Implement the method to provide an instance of ISpriteEditorDataProvider for a given object. 21 /// </summary> 22 /// <param name="obj">The object that requires an instance of ISpriteEditorDataProvider.</param> 23 /// <returns>An instance of ISpriteEditorDataProvider or null if not supported by the interface.</returns> 24 ISpriteEditorDataProvider CreateDataProvider(T obj); 25 } 26 27 [AttributeUsage(AttributeTargets.Method)] 28 internal class SpriteEditorAssetPathProviderAttribute : Attribute 29 { 30 [RequiredSignature] 31 private static string GetAssetPath(UnityEngine.Object obj) 32 { 33 return null; 34 } 35 } 36 37 [AttributeUsage(AttributeTargets.Method)] 38 internal class SpriteObjectProviderAttribute : Attribute 39 { 40 [RequiredSignature] 41 private static Sprite GetSpriteObject(UnityEngine.Object obj) 42 { 43 return null; 44 } 45 } 46 47 /// <summary> 48 /// Utility class that collects methods with SpriteDataProviderFactoryAttribute and SpriteDataProviderAssetPathProviderAttribute. 49 /// </summary> 50 public class SpriteDataProviderFactories 51 { 52 struct SpriteDataProviderFactory 53 { 54 public object instance; 55 public MethodInfo method; 56 public Type methodType; 57 } 58 59 static SpriteDataProviderFactory[] s_Factories; 60 static TypeCache.MethodCollection s_AssetPathProvider; 61 static TypeCache.MethodCollection s_SpriteObjectProvider; 62 63 static SpriteDataProviderFactory[] GetFactories() 64 { 65 CacheDataProviders(); 66 return s_Factories; 67 } 68 69 static TypeCache.MethodCollection GetAssetPathProvider() 70 { 71 CacheDataProviders(); 72 return s_AssetPathProvider; 73 } 74 75 static TypeCache.MethodCollection GetSpriteObjectProvider() 76 { 77 CacheDataProviders(); 78 return s_SpriteObjectProvider; 79 } 80 81 static void CacheDataProviders() 82 { 83 if (s_Factories != null) 84 return; 85 86 var factories = TypeCache.GetTypesDerivedFrom(typeof(ISpriteDataProviderFactory<>)); 87 var factoryList = new List<SpriteDataProviderFactory>(); 88 foreach (var factory in factories) 89 { 90 try 91 { 92 var ins = Activator.CreateInstance(factory); 93 foreach (var i in factory.GetInterfaces()) 94 { 95 var genericArguments = i.GetGenericArguments(); 96 if (genericArguments.Length == 1) 97 { 98 var s = new SpriteDataProviderFactory(); 99 s.instance = ins; 100 var method = i.GetMethod("CreateDataProvider"); 101 s.method = method; 102 s.methodType = genericArguments[0]; 103 factoryList.Add(s); 104 } 105 } 106 } 107 catch (Exception ex) 108 { 109 Debug.LogAssertion(ex); 110 } 111 } 112 s_Factories = factoryList.ToArray(); 113 s_AssetPathProvider = TypeCache.GetMethodsWithAttribute<SpriteEditorAssetPathProviderAttribute>(); 114 s_SpriteObjectProvider = TypeCache.GetMethodsWithAttribute<SpriteObjectProviderAttribute>(); 115 } 116 117 /// <summary> 118 /// Initialized and collect methods with SpriteDataProviderFactoryAttribute and SpriteDataProviderAssetPathProviderAttribute. 119 /// </summary> 120 public void Init() 121 { 122 CacheDataProviders(); 123 } 124 125 /// <summary> 126 /// Given a UnityEngine.Object, determine the ISpriteEditorDataProvider associate with the object by going 127 /// going through the methods with SpriteDataProviderFactoryAttribute. 128 /// </summary> 129 /// <remarks>When none of the methods is able to provide ISpriteEditorDataProvider for the object, the method will 130 /// try to cast the AssetImporter of the object to ISpriteEditorDataProvider.</remarks> 131 /// <param name="obj">The UnityEngine.Object to query.</param> 132 /// <returns>The ISpriteEditorDataProvider associated with the object.</returns> 133 public ISpriteEditorDataProvider GetSpriteEditorDataProviderFromObject(UnityEngine.Object obj) 134 { 135 if (obj != null) 136 { 137 var objType = obj.GetType(); 138 foreach (var factory in GetFactories()) 139 { 140 try 141 { 142 if (factory.methodType == objType) 143 { 144 var dataProvider = factory.method.Invoke(factory.instance, new[] { obj }) as ISpriteEditorDataProvider; 145 if (dataProvider != null && !dataProvider.Equals(null)) 146 return dataProvider; 147 } 148 } 149 catch (Exception ex) 150 { 151 Debug.LogAssertion(ex); 152 } 153 } 154 155 if (obj is ISpriteEditorDataProvider) 156 return (ISpriteEditorDataProvider)obj; 157 // now we try the importer 158 var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(obj)); 159 return importer as ISpriteEditorDataProvider; 160 } 161 162 return null; 163 } 164 165 /// <summary> 166 /// Given a UnityEngine.Object, determine the asset path associate with the object by going 167 /// going through the methods with SpriteDataProviderAssetPathProviderAttribute. 168 /// </summary> 169 /// <remarks>When none of the methods is able to provide the asset path for the object, the method will return null</remarks> 170 /// <param name="obj">The UnityEngine.Object to query</param> 171 /// <returns>The asset path for the object</returns> 172 internal string GetAssetPath(UnityEngine.Object obj) 173 { 174 foreach (var assetPathProvider in GetAssetPathProvider()) 175 { 176 try 177 { 178 var path = assetPathProvider.Invoke(null, new object[] { obj }) as string; 179 if (!string.IsNullOrEmpty(path)) 180 return path; 181 } 182 catch (Exception ex) 183 { 184 Debug.LogException(ex); 185 } 186 } 187 return null; 188 } 189 190 /// <summary> 191 /// Given a UnityEngine.Object, determine the Sprite object associate with the object by going 192 /// going through the methods with SpriteObjectProviderAttribute. 193 /// </summary> 194 /// <remarks>When none of the methods is able to provide a Sprite object, the method will return null</remarks> 195 /// <param name="obj">The UnityEngine.Object to query</param> 196 /// <returns>The Sprite object</returns> 197 internal Sprite GetSpriteObject(UnityEngine.Object obj) 198 { 199 if (obj is Sprite) 200 return (Sprite)obj; 201 foreach (var spriteObjectProvider in GetSpriteObjectProvider()) 202 { 203 try 204 { 205 var sprite = spriteObjectProvider.Invoke(null, new object[] { obj }) as Sprite; 206 if (sprite != null && !sprite.Equals(null)) 207 return sprite; 208 } 209 catch (Exception ex) 210 { 211 Debug.LogException(ex); 212 } 213 } 214 return null; 215 } 216 } 217 218 [InitializeOnLoad] 219 internal class SpriteEditorWindow : SpriteUtilityWindow, ISpriteEditor, ISupportsOverlays 220 { 221 static SpriteEditorWindow() 222 { 223 UnityEditor.SpriteUtilityWindow.SetShowSpriteEditorWindowWithObject((x) => 224 { 225 SpriteEditorWindow.GetWindow(x); 226 return true; 227 }); 228 } 229 230 private class SpriteEditorWindowStyles 231 { 232 public static readonly GUIContent editingDisableMessageBecausePlaymodeLabel = EditorGUIUtility.TrTextContent("Editing is disabled during play mode"); 233 public static readonly GUIContent editingDisableMessageBecauseNonEditableLabel = EditorGUIUtility.TrTextContent("Editing is disabled because the asset is not editable."); 234 public static readonly GUIContent revertButtonLabel = EditorGUIUtility.TrTextContent("Revert"); 235 public static readonly GUIContent applyButtonLabel = EditorGUIUtility.TrTextContent("Apply"); 236 237 public static readonly GUIContent pendingChangesDialogContent = EditorGUIUtility.TrTextContent("The asset was modified outside of Sprite Editor Window.\nDo you want to apply pending changes?"); 238 239 public static readonly GUIContent applyRevertDialogTitle = EditorGUIUtility.TrTextContent("Sprite Editor Window"); 240 public static readonly GUIContent applyRevertDialogContent = EditorGUIUtility.TrTextContent("'{0}' has unapplied changes.\nDo you want to apply or revert them?"); 241 242 public static readonly GUIContent noSelectionWarning = EditorGUIUtility.TrTextContent("No Texture or Sprite selected.\nPlease select one from your project to start."); 243 public static readonly GUIContent selectionNotEditableBySpriteEditor = EditorGUIUtility.TrTextContent("Selected object is not supported by Sprite Editor Window."); 244 public static readonly GUIContent noModuleWarning = EditorGUIUtility.TrTextContent("No Sprite Editor module available"); 245 public static readonly GUIContent applyRevertModuleDialogTitle = EditorGUIUtility.TrTextContent("Sprite Editor Window"); 246 public static readonly GUIContent applyRevertModuleDialogContent = EditorGUIUtility.TrTextContent("You have unapplied changes from the current module. Do you want to apply or revert them?"); 247 248 public static readonly GUIContent revertConfirmationDialogTitle = EditorGUIUtility.TrTextContent("Revert Changes"); 249 public static readonly GUIContent revertConfirmationDialogContent = EditorGUIUtility.TrTextContent("Are you sure you want to revert the changes?"); 250 public static readonly GUIContent applyConfirmationDialogTitle = EditorGUIUtility.TrTextContent("Apply Changes"); 251 public static readonly GUIContent applyConfirmationDialogContent = EditorGUIUtility.TrTextContent("Are you sure you want to apply the changes?"); 252 public static readonly GUIContent yesLabel = EditorGUIUtility.TrTextContent("Yes"); 253 public static readonly GUIContent noLabel = EditorGUIUtility.TrTextContent("No"); 254 public static readonly string styleSheetPath = "Packages/com.unity.2d.sprite/Editor/UI/SpriteEditor/SpriteEditor.uss"; 255 public static readonly string toolBarStyleSheetPath = "Packages/com.unity.2d.sprite/Editor/UI/SpriteEditor/SpriteEditorToolbar.uss"; 256 } 257 258 class CurrentResetContext 259 { 260 public string assetPath; 261 } 262 263 private const float k_MarginForFraming = 0.05f; 264 private const float k_WarningMessageWidth = 250f; 265 private const float k_WarningMessageHeight = 40f; 266 private const float k_ModuleListWidth = 90f; 267 private const string k_RefreshOnNextRepaintCommandEvent = "RefreshOnNextRepaintCommand"; 268 bool m_ResetOnNextRepaint; 269 bool m_ResetCommandSent; 270 271 private List<SpriteRect> m_RectsCache; 272 ISpriteEditorDataProvider m_SpriteDataProvider; 273 274 private bool m_RequestRepaint = false; 275 276 public static bool s_OneClickDragStarted = false; 277 string m_SelectedAssetPath; 278 bool m_AssetNotEditable; 279 280 private IEventSystem m_EventSystem; 281 private IUndoSystem m_UndoSystem; 282 private IAssetDatabase m_AssetDatabase; 283 private IGUIUtility m_GUIUtility; 284 private UnityTexture2D m_OutlineTexture; 285 private UnityTexture2D m_ReadableTexture; 286 private Dictionary<Type, RequireSpriteDataProviderAttribute> m_ModuleRequireSpriteDataProvider = new (); 287 private Dictionary<Type, List<Type>> m_ModuleMode = new (); 288 289 VisualElement m_ToolbarContainer; 290 VisualElement m_ModuleToolbarContainer; 291 VisualElement m_AlphaZoomToolbarElement; 292 VisualElement m_ModuleDropDownUI; 293 private IMGUIContainer m_ModuleToolbarIMGUIElement; 294 private IMGUIContainer m_MainViewIMGUIElement; 295 private VisualElement m_ModuleViewElement; 296 private VisualElement m_MainViewElement; 297 SpriteDataProviderFactories m_SpriteDataProviderFactories; 298 299 [SerializeField] 300 private UnityEngine.Object m_SelectedObject; 301 302 [SerializeField] 303 private string m_SelectedSpriteRectGUID; 304 305 internal Func<string, string, bool> onHandleApplyRevertDialog = ShowHandleApplyRevertDialog; 306 307 private CurrentResetContext m_CurrentResetContext = null; 308 309 EditorGUIUtility.EditorLockTracker m_LockTracker = new EditorGUIUtility.EditorLockTracker(); 310 311 public static void GetWindow(UnityEngine.Object obj) 312 { 313 var window = EditorWindow.GetWindow<SpriteEditorWindow>(); 314 window.selectedObject = obj; 315 } 316 317 public SpriteEditorWindow() 318 { 319 m_EventSystem = new EventSystem(); 320 m_UndoSystem = new UndoSystem(); 321 m_AssetDatabase = new AssetDatabaseSystem(); 322 m_GUIUtility = new GUIUtilitySystem(); 323 } 324 325 void ModifierKeysChanged() 326 { 327 if (EditorWindow.focusedWindow == this) 328 { 329 Repaint(); 330 } 331 } 332 333 private void OnFocus() 334 { 335 if (selectedObject != Selection.activeObject) 336 OnSelectionChange(); 337 if (selectedProviderChanged) 338 RefreshSpriteEditorWindow(); 339 } 340 341 internal UnityEngine.Object selectedObject 342 { 343 get { return m_SelectedObject; } 344 set 345 { 346 m_SelectedObject = value; 347 RefreshSpriteEditorWindow(); 348 } 349 } 350 351 string selectedAssetPath 352 { 353 get => m_SelectedAssetPath; 354 set 355 { 356 m_SelectedAssetPath = value; 357 m_AssetNotEditable = !AssetDatabase.IsOpenForEdit(m_SelectedAssetPath); 358 } 359 } 360 361 public void RefreshPropertiesCache() 362 { 363 Undo.ClearUndo(this); 364 m_Texture = null; 365 var obj = AssetDatabase.LoadMainAssetAtPath(selectedAssetPath); 366 m_SpriteDataProvider = spriteDataProviderFactories.GetSpriteEditorDataProviderFromObject(obj); 367 if (!IsSpriteDataProviderValid()) 368 { 369 selectedAssetPath = ""; 370 var s = m_SpriteDataProviderFactories.GetSpriteObject(Selection.activeObject); 371 if(s != null) 372 { 373 var t = SpriteInspector.BuildPreviewTexture(s, null, false, (int)s.rect.width, (int)s.rect.height); 374 SetPreviewTexture(t, t.width, t.height); 375 } 376 return; 377 } 378 379 380 m_SpriteDataProvider.InitSpriteEditorDataProvider(); 381 382 var textureProvider = m_SpriteDataProvider.GetDataProvider<ITextureDataProvider>(); 383 if (textureProvider != null) 384 { 385 int width = 0, height = 0; 386 textureProvider.GetTextureActualWidthAndHeight(out width, out height); 387 m_Texture = textureProvider.previewTexture == null ? null : new PreviewTexture2D(textureProvider.previewTexture, width, height); 388 } 389 } 390 391 internal string GetSelectionAssetPath() 392 { 393 var path = spriteDataProviderFactories.GetAssetPath(selectedObject); 394 if (string.IsNullOrEmpty(path)) 395 path = m_AssetDatabase.GetAssetPath(selectedObject); 396 return path; 397 } 398 399 public void InvalidatePropertiesCache() 400 { 401 spriteRects = null; 402 m_SpriteDataProvider = null; 403 } 404 405 private Rect spriteEditorMessageRect 406 { 407 get 408 { 409 return new Rect( 410 k_InspectorWindowMargin, 411 k_InspectorWindowMargin, 412 k_WarningMessageWidth, 413 k_WarningMessageHeight); 414 } 415 } 416 417 public SpriteImportMode spriteImportMode 418 { 419 get { return !IsSpriteDataProviderValid() ? SpriteImportMode.None : m_SpriteDataProvider.spriteImportMode; } 420 } 421 422 bool activeDataProviderSelected 423 { 424 get { return m_SpriteDataProvider != null; } 425 } 426 427 public bool textureIsDirty 428 { 429 get 430 { 431 return hasUnsavedChanges; 432 } 433 set 434 { 435 hasUnsavedChanges = value; 436 } 437 } 438 439 public bool selectedProviderChanged 440 { 441 get 442 { 443 var assetPath = GetSelectionAssetPath(); 444 var dataProvider = spriteDataProviderFactories.GetSpriteEditorDataProviderFromObject(selectedObject); 445 return dataProvider != null && selectedAssetPath != assetPath; 446 } 447 } 448 449 void OnSelectionChange() 450 { 451 if(m_LockTracker.isLocked) 452 return; 453 454 selectedObject = Selection.activeObject; 455 RefreshSpriteEditorWindow(); 456 } 457 458 void RefreshSpriteEditorWindow() 459 { 460 // In case of changed of texture/sprite or selected on non texture object 461 bool updateModules = false; 462 var selectedSprite = spriteDataProviderFactories.GetSpriteObject(selectedObject); 463 var assetPath = GetSelectionAssetPath(); 464 var dataProvider = spriteDataProviderFactories.GetSpriteEditorDataProviderFromObject(selectedObject); 465 if ((dataProvider != null && selectedAssetPath != assetPath) || 466 (dataProvider == null && selectedSprite !=null)) 467 { 468 HandleApplyRevertDialog(SpriteEditorWindowStyles.applyRevertDialogTitle.text, 469 String.Format(SpriteEditorWindowStyles.applyRevertDialogContent.text, selectedAssetPath)); 470 selectedAssetPath = assetPath; 471 ResetWindow(); 472 ResetZoomAndScroll(); 473 RefreshPropertiesCache(); 474 RefreshRects(); 475 updateModules = true; 476 } 477 478 if (m_RectsCache != null) 479 { 480 UpdateSelectedSpriteRectFromSelection(); 481 } 482 483 // We only update modules when data provider changed 484 if (updateModules) 485 UpdateAvailableModules(); 486 if (m_ModuleDropDownUI != null) 487 m_ModuleDropDownUI.style.display = m_Texture == null || m_RegisteredModules?.Count <= 0 ? DisplayStyle.None : DisplayStyle.Flex; 488 Repaint(); 489 } 490 491 private void UpdateSelectedSpriteRectFromSelection() 492 { 493 if (Selection.activeObject is UnityEngine.Sprite) 494 { 495 UpdateSelectedSpriteRect(Selection.activeObject as UnityEngine.Sprite); 496 } 497 else 498 { 499 var sprite = spriteDataProviderFactories.GetSpriteObject(Selection.activeObject); 500 UpdateSelectedSpriteRect(sprite); 501 } 502 } 503 504 public void ResetWindow() 505 { 506 InvalidatePropertiesCache(); 507 textureIsDirty = false; 508 saveChangesMessage = SpriteEditorWindowStyles.applyRevertModuleDialogContent.text; 509 } 510 511 public void ResetZoomAndScroll() 512 { 513 m_Zoom = -1; 514 m_ScrollPosition = Vector2.zero; 515 } 516 517 SpriteDataProviderFactories spriteDataProviderFactories 518 { 519 get 520 { 521 if (m_SpriteDataProviderFactories == null) 522 { 523 m_SpriteDataProviderFactories = new SpriteDataProviderFactories(); 524 m_SpriteDataProviderFactories.Init(); 525 } 526 return m_SpriteDataProviderFactories; 527 } 528 } 529 530 protected void SetTitleContent(string windowTitle, string windowIconPath) 531 { 532 if (string.IsNullOrEmpty(windowTitle)) 533 return; 534 535 Texture2D iconTex = null; 536 if (!string.IsNullOrEmpty(windowIconPath)) 537 { 538 if (EditorGUIUtility.isProSkin) 539 { 540 var newName = "d_" + Path.GetFileName(windowIconPath); 541 var iconDirName = Path.GetDirectoryName(windowIconPath); 542 if (!string.IsNullOrEmpty(iconDirName)) 543 newName = $"{iconDirName}/{newName}"; 544 545 windowIconPath = newName; 546 } 547 548 if (EditorGUIUtility.pixelsPerPoint > 1) 549 windowIconPath = $"{windowIconPath}@2x"; 550 551 iconTex = EditorGUIUtility.Load(windowIconPath + ".png") as Texture2D; 552 } 553 554 titleContent = new GUIContent(windowTitle, iconTex); 555 } 556 557 void OnEnable() 558 { 559 name = "SpriteEditorWindow"; 560 SetTitleContent(L10n.Tr("Sprite Editor"), "Packages/com.unity.2d.sprite/Editor/Assets/SpriteEditor"); 561 selectedObject = Selection.activeObject; 562 minSize = new Vector2(360, 200); 563 m_UndoSystem.RegisterUndoCallback(UndoRedoPerformed); 564 EditorApplication.modifierKeysChanged += ModifierKeysChanged; 565 EditorApplication.playModeStateChanged += OnPlayModeStateChanged; 566 EditorApplication.quitting += OnEditorApplicationQuit; 567 AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload; 568 569 if (selectedProviderChanged) 570 selectedAssetPath = GetSelectionAssetPath(); 571 572 ResetWindow(); 573 RefreshPropertiesCache(); 574 bool noSelectedSprite = string.IsNullOrEmpty(m_SelectedSpriteRectGUID); 575 RefreshRects(); 576 if (noSelectedSprite) 577 UpdateSelectedSpriteRectFromSelection(); 578 UnityEditor.SpriteUtilityWindow.SetApplySpriteEditorWindow(RebuildCache); 579 } 580 581 void CreateGUI() 582 { 583 if (m_MainViewElement == null) 584 { 585 if (SetupVisualElements()) 586 InitModules(); 587 } 588 } 589 590 private void ShowButton(Rect r) 591 { 592 EditorGUI.BeginChangeCheck(); 593 this.m_LockTracker.ShowButton(r, (GUIStyle) "IN LockButton", false); 594 if (!EditorGUI.EndChangeCheck()) 595 return; 596 OnSelectionChange(); 597 } 598 599 private bool SetupVisualElements() 600 { 601 var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>(SpriteEditorWindowStyles.styleSheetPath); 602 if (styleSheet != null && rootVisualElement != null && rootVisualElement.styleSheetList != null) 603 { 604 m_ToolbarContainer = new VisualElement() 605 { 606 name = "spriteEditorWindowToolbarContainer" 607 }; 608 m_ModuleToolbarContainer = new VisualElement() 609 { 610 name = "spriteEditorWindowModuleToolbarContainer" 611 }; 612 m_ModuleDropDownUI = new IMGUIContainer(DoModuleDropDownGUI) 613 { 614 name = "spriteEditorWindowModuleDropDown", 615 }; 616 m_ModuleDropDownUI.style.display = m_Texture == null || m_RegisteredModules?.Count <= 0 ? DisplayStyle.None : DisplayStyle.Flex; 617 var moduleApplyRevertGUI = new IMGUIContainer(DoApplyRevertGUI) 618 { 619 name = "spriteEditorWindowApplyRevert" 620 }; 621 m_AlphaZoomToolbarElement = new IMGUIContainer(DoAlphaZoomToolbarGUI) 622 { 623 name = "spriteEditorWindowAlphaZoom" 624 }; 625 m_ModuleToolbarIMGUIElement = new IMGUIContainer(DoToolbarGUI) 626 { 627 name = "spriteEditorWindowModuleToolbarIMGUI", 628 }; 629 m_ToolbarContainer.Add(m_ModuleDropDownUI); 630 m_ToolbarContainer.Add(m_ModuleToolbarIMGUIElement); 631 m_ToolbarContainer.Add(m_ModuleToolbarContainer); 632 m_ToolbarContainer.Add(moduleApplyRevertGUI); 633 m_ToolbarContainer.Add(m_AlphaZoomToolbarElement); 634 m_MainViewIMGUIElement = new IMGUIContainer(DoTextureAndModulesGUI) 635 { 636 name = "mainViewIMGUIElement" 637 }; 638 m_MainViewElement = new VisualElement() 639 { 640 name = "spriteEditorWindowMainView", 641 }; 642 m_ModuleViewElement = new VisualElement() 643 { 644 name = "moduleViewElement", 645 pickingMode = PickingMode.Ignore 646 }; 647 m_MainViewElement.Add(m_MainViewIMGUIElement); 648 m_MainViewElement.Add(m_ModuleViewElement); 649 var root = rootVisualElement; 650 root.styleSheetList.Add(styleSheet); 651 m_ToolbarContainer.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(SpriteEditorWindowStyles.toolBarStyleSheetPath)); 652 baseRootVisualElement.Insert(0, m_ToolbarContainer); 653 root.Add(m_MainViewElement); 654 655 TryGetOverlay("Overlays/OverlayMenu", out Overlay overlay); 656 if(overlay != null) 657 overlay.displayed = false; 658 return true; 659 } 660 return false; 661 } 662 663 private void UndoRedoPerformed() 664 { 665 // Was selected texture changed by undo? 666 if (selectedProviderChanged) 667 RefreshSpriteEditorWindow(); 668 669 InitSelectedSpriteRect(); 670 671 Repaint(); 672 } 673 674 private void InitSelectedSpriteRect() 675 { 676 SpriteRect newSpriteRect = null; 677 if (m_RectsCache != null && m_RectsCache.Count > 0) 678 { 679 if (selectedSpriteRect != null) 680 newSpriteRect = m_RectsCache.FirstOrDefault(x => x.spriteID == selectedSpriteRect.spriteID) != null ? selectedSpriteRect : m_RectsCache[0]; 681 else 682 newSpriteRect = m_RectsCache[0]; 683 } 684 685 selectedSpriteRect = newSpriteRect; 686 } 687 688 void OnGUI() 689 { 690 CreateGUI(); 691 } 692 693 public override void SaveChanges() 694 { 695 var oldDelegate = onHandleApplyRevertDialog; 696 onHandleApplyRevertDialog = (x, y) => true; 697 HandleApplyRevertDialog(SpriteEditorWindowStyles.applyRevertDialogTitle.text, 698 String.Format(SpriteEditorWindowStyles.applyRevertDialogContent.text, selectedAssetPath)); 699 onHandleApplyRevertDialog = oldDelegate; 700 base.SaveChanges(); 701 } 702 703 private void OnDisable() 704 { 705 Undo.undoRedoPerformed -= UndoRedoPerformed; 706 InvalidatePropertiesCache(); 707 EditorApplication.modifierKeysChanged -= ModifierKeysChanged; 708 EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; 709 EditorApplication.quitting -= OnEditorApplicationQuit; 710 AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload; 711 712 if (m_OutlineTexture != null) 713 { 714 DestroyImmediate(m_OutlineTexture); 715 m_OutlineTexture = null; 716 } 717 718 if (m_ReadableTexture) 719 { 720 DestroyImmediate(m_ReadableTexture); 721 m_ReadableTexture = null; 722 } 723 724 if (m_CurrentModule != null) 725 m_CurrentModule.OnModuleDeactivate(); 726 UnityEditor.SpriteUtilityWindow.SetApplySpriteEditorWindow(null); 727 if (m_MainViewElement != null && rootVisualElement.Contains(m_MainViewElement)) 728 { 729 rootVisualElement.Remove(m_MainViewElement); 730 m_MainViewElement = null; 731 } 732 } 733 734 void OnPlayModeStateChanged(PlayModeStateChange playModeState) 735 { 736 if (PlayModeStateChange.EnteredPlayMode == playModeState || PlayModeStateChange.EnteredEditMode == playModeState) 737 { 738 RebuildCache(); 739 } 740 } 741 742 void OnEditorApplicationQuit() 743 { 744 HandleApplyRevertDialog(SpriteEditorWindowStyles.applyRevertDialogTitle.text, 745 String.Format(SpriteEditorWindowStyles.applyRevertDialogContent.text, selectedAssetPath)); 746 } 747 748 void OnBeforeAssemblyReload() 749 { 750 HandleApplyRevertDialog(SpriteEditorWindowStyles.applyRevertDialogTitle.text, 751 String.Format(SpriteEditorWindowStyles.applyRevertDialogContent.text, selectedAssetPath)); 752 } 753 754 static bool ShowHandleApplyRevertDialog(string dialogTitle, string dialogContent) 755 { 756 return EditorUtility.DisplayDialog(dialogTitle, dialogContent, 757 SpriteEditorWindowStyles.applyButtonLabel.text, SpriteEditorWindowStyles.revertButtonLabel.text); 758 } 759 760 void HandleApplyRevertDialog(string dialogTitle, string dialogContent) 761 { 762 if (textureIsDirty && IsSpriteDataProviderValid()) 763 { 764 if (onHandleApplyRevertDialog(dialogTitle, dialogContent)) 765 DoApply(); 766 else 767 DoRevert(); 768 769 SetupModule(m_CurrentModuleIndex); 770 } 771 } 772 773 bool IsSpriteDataProviderValid() 774 { 775 return m_SpriteDataProvider != null && !m_SpriteDataProvider.Equals(null); 776 } 777 778 void RefreshRects() 779 { 780 spriteRects = null; 781 if (IsSpriteDataProviderValid()) 782 { 783 m_RectsCache = m_SpriteDataProvider.GetSpriteRects().ToList(); 784 } 785 786 InitSelectedSpriteRect(); 787 } 788 789 private void UpdateAssetSelectionChange() 790 { 791 if (selectedProviderChanged) 792 { 793 ResetOnNextRepaint(); 794 } 795 796 if (m_ResetCommandSent || (UnityEngine.Event.current.type == EventType.ExecuteCommand && UnityEngine.Event.current.commandName == k_RefreshOnNextRepaintCommandEvent)) 797 { 798 m_ResetCommandSent = false; 799 if (selectedProviderChanged || !IsSpriteDataProviderValid()) 800 selectedAssetPath = GetSelectionAssetPath(); 801 RebuildCache(); 802 } 803 } 804 805 internal void ResetOnNextRepaint() 806 { 807 //Because we can't show dialog in a repaint/layout event, we need to send event to IMGUI to trigger this. 808 //The event is now sent through the Update loop. 809 m_ResetOnNextRepaint = true; 810 if (textureIsDirty) 811 { 812 // We can't depend on the existing data provider to set data because a reimport might cause 813 // the data provider to be invalid. We store up the current asset path so that in DoApply() 814 // the modified data can be set correctly to correct asset. 815 if (m_CurrentResetContext != null) 816 Debug.LogError("Existing reset not completed for " + m_CurrentResetContext.assetPath); 817 m_CurrentResetContext = new CurrentResetContext() 818 { 819 assetPath = selectedAssetPath 820 }; 821 } 822 } 823 824 void Update() 825 { 826 if (m_ResetOnNextRepaint) 827 { 828 m_ResetOnNextRepaint = false; 829 m_ResetCommandSent = true; 830 var e = EditorGUIUtility.CommandEvent(k_RefreshOnNextRepaintCommandEvent); 831 this.SendEvent(e); 832 } 833 } 834 835 private void RebuildCache() 836 { 837 HandleApplyRevertDialog(SpriteEditorWindowStyles.applyRevertDialogTitle.text, SpriteEditorWindowStyles.pendingChangesDialogContent.text); 838 ResetWindow(); 839 RefreshPropertiesCache(); 840 RefreshRects(); 841 UpdateAvailableModules(); 842 } 843 844 void ShowEditorMessage(string message, MessageType messageType) 845 { 846 GUILayout.BeginArea(spriteEditorMessageRect); 847 EditorGUILayout.HelpBox(message, messageType); 848 GUILayout.EndArea(); 849 } 850 851 private void DoTextureAndModulesGUI() 852 { 853 // Don't do anything until reset event is sent 854 if (m_ResetOnNextRepaint) 855 return; 856 InitStyles(); 857 UpdateAssetSelectionChange(); 858 if (m_ResetCommandSent) 859 return; 860 textureViewRect = new Rect(0f, 0f, m_MainViewIMGUIElement.layout.width - k_ScrollbarMargin, m_MainViewIMGUIElement.layout.height - k_ScrollbarMargin); 861 if (!activeDataProviderSelected) 862 { 863 if (m_Texture != null) 864 { 865 DoTextureGUI(); 866 ShowEditorMessage(SpriteEditorWindowStyles.selectionNotEditableBySpriteEditor.text, MessageType.Info); 867 } 868 else 869 { 870 ShowEditorMessage(SpriteEditorWindowStyles.noSelectionWarning.text, MessageType.Info); 871 } 872 return; 873 } 874 if (m_CurrentModule == null) 875 { 876 using (new EditorGUI.DisabledScope(true)) 877 { 878 GUILayout.Label(SpriteEditorWindowStyles.noModuleWarning); 879 } 880 return; 881 } 882 textureViewRect = new Rect(0f, 0f, m_MainViewIMGUIElement.layout.width - k_ScrollbarMargin, m_MainViewIMGUIElement.layout.height - k_ScrollbarMargin); 883 Matrix4x4 oldHandlesMatrix = Handles.matrix; 884 DoTextureGUI(); 885 // Warning message if applicable 886 DoEditingDisabledMessage(); 887 m_CurrentModule.DoPostGUI(); 888 Handles.matrix = oldHandlesMatrix; 889 if (m_RequestRepaint) 890 { 891 Repaint(); 892 m_RequestRepaint = false; 893 } 894 } 895 896 protected override void DoTextureGUIExtras() 897 { 898 if (activeDataProviderSelected) 899 { 900 HandleFrameSelected(); 901 902 if (m_EventSystem.current.type == EventType.Repaint) 903 { 904 SpriteEditorUtility.BeginLines(new Color(1f, 1f, 1f, 0.5f)); 905 var selectedRect = selectedSpriteRect != null ? selectedSpriteRect.spriteID : new GUID(); 906 for (int i = 0; i < m_RectsCache.Count; i++) 907 { 908 if (m_RectsCache[i].spriteID != selectedRect) 909 SpriteEditorUtility.DrawBox(m_RectsCache[i].rect); 910 } 911 912 SpriteEditorUtility.EndLines(); 913 } 914 915 m_CurrentModule.DoMainGUI(); 916 } 917 } 918 919 private void DoModuleDropDownGUI() 920 { 921 InitStyles(); 922 923 if (!activeDataProviderSelected || m_CurrentModule == null) 924 return; 925 926 if (m_RegisteredModules.Count > 1) 927 { 928 int module = EditorGUILayout.Popup(m_CurrentModuleIndex, m_RegisteredModuleNames, EditorStyles.toolbarPopup); 929 if (module != m_CurrentModuleIndex) 930 { 931 if (textureIsDirty) 932 { 933 // Have pending module edit changes. Ask user if they want to apply or revert 934 if (EditorUtility.DisplayDialog(SpriteEditorWindowStyles.applyRevertModuleDialogTitle.text, 935 SpriteEditorWindowStyles.applyRevertModuleDialogContent.text, 936 SpriteEditorWindowStyles.applyButtonLabel.text, SpriteEditorWindowStyles.revertButtonLabel.text)) 937 DoApply(); 938 else 939 DoRevert(); 940 } 941 SetupModule(module); 942 } 943 } 944 } 945 946 private void DoApplyRevertGUI() 947 { 948 InitStyles(); 949 GUILayout.BeginHorizontal(); 950 using (new EditorGUI.DisabledScope(!textureIsDirty)) 951 { 952 if (GUILayout.Button(SpriteEditorWindowStyles.applyButtonLabel, EditorStyles.toolbarButton)) 953 { 954 var apply = true; 955 if (SpriteEditorWindowSettings.showApplyConfirmation) 956 { 957 apply = EditorUtility.DisplayDialog(SpriteEditorWindowStyles.applyConfirmationDialogTitle.text, SpriteEditorWindowStyles.applyConfirmationDialogContent.text, 958 SpriteEditorWindowStyles.yesLabel.text, SpriteEditorWindowStyles.noLabel.text); 959 } 960 if (apply) 961 { 962 DoApply(); 963 SetupModule(m_CurrentModuleIndex); 964 } 965 } 966 967 if (GUILayout.Button(SpriteEditorWindowStyles.revertButtonLabel, EditorStyles.toolbarButton)) 968 { 969 var revert = true; 970 if (SpriteEditorWindowSettings.showRevertConfirmation) 971 { 972 revert = EditorUtility.DisplayDialog(SpriteEditorWindowStyles.revertConfirmationDialogTitle.text, SpriteEditorWindowStyles.revertConfirmationDialogContent.text, 973 SpriteEditorWindowStyles.yesLabel.text, SpriteEditorWindowStyles.noLabel.text); 974 } 975 if (revert) 976 { 977 DoRevert(); 978 SetupModule(m_CurrentModuleIndex); 979 } 980 } 981 } 982 GUILayout.EndHorizontal(); 983 } 984 985 void DoAlphaZoomToolbarGUI() 986 { 987 InitStyles(); 988 Rect toolbarRect = new Rect(0, 0, m_AlphaZoomToolbarElement.resolvedStyle.width, m_AlphaZoomToolbarElement.resolvedStyle.height); 989 DoAlphaZoomToolbarGUI(toolbarRect); 990 } 991 992 private void DoToolbarGUI() 993 { 994 InitStyles(); 995 Rect toolbarRect = new Rect(0, 0, m_ModuleToolbarIMGUIElement.resolvedStyle.width, m_ModuleToolbarIMGUIElement.resolvedStyle.height); 996 m_CurrentModule?.DoToolbarGUI(toolbarRect); 997 } 998 999 private void DoEditingDisabledMessage() 1000 { 1001 if (editingDisabled) 1002 { 1003 var disableMessage = m_AssetNotEditable ? SpriteEditorWindowStyles.editingDisableMessageBecauseNonEditableLabel.text : SpriteEditorWindowStyles.editingDisableMessageBecausePlaymodeLabel.text; 1004 ShowEditorMessage(disableMessage, MessageType.Warning); 1005 } 1006 } 1007 1008 private void DoApply() 1009 { 1010 textureIsDirty = false; 1011 bool reimport = true; 1012 var dataProvider = m_SpriteDataProvider; 1013 if (m_CurrentResetContext != null) 1014 { 1015 m_SpriteDataProvider = 1016 m_SpriteDataProviderFactories.GetSpriteEditorDataProviderFromObject( 1017 AssetDatabase.LoadMainAssetAtPath(m_CurrentResetContext.assetPath)); 1018 m_SpriteDataProvider.InitSpriteEditorDataProvider(); 1019 m_CurrentResetContext = null; 1020 } 1021 1022 if (m_SpriteDataProvider != null) 1023 { 1024 if (m_CurrentModule != null) 1025 reimport = m_CurrentModule.ApplyRevert(true); 1026 m_SpriteDataProvider.Apply(); 1027 } 1028 1029 m_SpriteDataProvider = dataProvider; 1030 // Do this so that asset change save dialog will not show 1031 var originalValue = EditorPrefs.GetBool("VerifySavingAssets", false); 1032 EditorPrefs.SetBool("VerifySavingAssets", false); 1033 AssetDatabase.ForceReserializeAssets(new[] {selectedAssetPath}, ForceReserializeAssetsOptions.ReserializeMetadata); 1034 EditorPrefs.SetBool("VerifySavingAssets", originalValue); 1035 1036 if (reimport) 1037 DoTextureReimport(selectedAssetPath); 1038 Repaint(); 1039 RefreshRects(); 1040 } 1041 1042 private void DoRevert() 1043 { 1044 textureIsDirty = false; 1045 RefreshRects(); 1046 GUI.FocusControl(""); 1047 if (m_CurrentModule != null) 1048 m_CurrentModule.ApplyRevert(false); 1049 } 1050 1051 public bool HandleSpriteSelection() 1052 { 1053 bool changed = false; 1054 1055 if (m_EventSystem.current.type == EventType.MouseDown && m_EventSystem.current.button == 0 && GUIUtility.hotControl == 0 && !m_EventSystem.current.alt) 1056 { 1057 var oldSelected = selectedSpriteRect; 1058 1059 var triedRect = TrySelect(m_EventSystem.current.mousePosition); 1060 if (triedRect != oldSelected) 1061 { 1062 Undo.RegisterCompleteObjectUndo(this, "Sprite Selection"); 1063 1064 selectedSpriteRect = triedRect; 1065 changed = true; 1066 } 1067 1068 if (selectedSpriteRect != null) 1069 s_OneClickDragStarted = true; 1070 else 1071 RequestRepaint(); 1072 1073 if (changed && selectedSpriteRect != null) 1074 { 1075 m_EventSystem.current.Use(); 1076 } 1077 } 1078 1079 return changed; 1080 } 1081 1082 private void HandleFrameSelected() 1083 { 1084 var evt = m_EventSystem.current; 1085 1086 if ((evt.type == EventType.ValidateCommand || evt.type == EventType.ExecuteCommand) 1087 && evt.commandName == EventCommandNames.FrameSelected) 1088 { 1089 if (evt.type == EventType.ExecuteCommand) 1090 { 1091 // Do not do frame if there is none selected 1092 if (selectedSpriteRect == null) 1093 return; 1094 1095 Rect rect = selectedSpriteRect.rect; 1096 1097 // Calculate the require pixel to display the frame, then get the zoom needed. 1098 float targetZoom = m_Zoom; 1099 if (rect.width < rect.height) 1100 targetZoom = textureViewRect.height / (rect.height + textureViewRect.height * k_MarginForFraming); 1101 else 1102 targetZoom = textureViewRect.width / (rect.width + textureViewRect.width * k_MarginForFraming); 1103 1104 // Apply the zoom 1105 zoomLevel = targetZoom; 1106 1107 // Calculate the scroll values to center the frame 1108 m_ScrollPosition.x = (rect.center.x - (m_Texture.width * 0.5f)) * m_Zoom; 1109 m_ScrollPosition.y = (rect.center.y - (m_Texture.height * 0.5f)) * m_Zoom * -1.0f; 1110 1111 Repaint(); 1112 } 1113 1114 evt.Use(); 1115 } 1116 } 1117 1118 void UpdateSelectedSpriteRect(UnityEngine.Sprite sprite) 1119 { 1120 if (m_RectsCache == null || sprite == null || sprite.Equals(null)) 1121 return; 1122 1123 var spriteGUID = sprite.GetSpriteID(); 1124 for (int i = 0; i < m_RectsCache.Count; i++) 1125 { 1126 if (spriteGUID == m_RectsCache[i].spriteID) 1127 { 1128 selectedSpriteRect = m_RectsCache[i]; 1129 return; 1130 } 1131 } 1132 selectedSpriteRect = null; 1133 } 1134 1135 private SpriteRect TrySelect(Vector2 mousePosition) 1136 { 1137 float selectedSize = float.MaxValue; 1138 SpriteRect currentRect = null; 1139 mousePosition = Handles.inverseMatrix.MultiplyPoint(mousePosition); 1140 1141 for (int i = 0; i < m_RectsCache.Count; i++) 1142 { 1143 var sr = m_RectsCache[i]; 1144 if (sr.rect.Contains(mousePosition)) 1145 { 1146 // If we clicked inside an already selected spriterect, always persist that selection 1147 if (sr == selectedSpriteRect) 1148 return sr; 1149 1150 float width = sr.rect.width; 1151 float height = sr.rect.height; 1152 float newSize = width * height; 1153 if (width > 0f && height > 0f && newSize < selectedSize) 1154 { 1155 currentRect = sr; 1156 selectedSize = newSize; 1157 } 1158 } 1159 } 1160 1161 return currentRect; 1162 } 1163 1164 public void DoTextureReimport(string path) 1165 { 1166 if (m_SpriteDataProvider != null) 1167 { 1168 try 1169 { 1170 AssetDatabase.StartAssetEditing(); 1171 AssetDatabase.ImportAsset(path); 1172 } 1173 finally 1174 { 1175 AssetDatabase.StopAssetEditing(); 1176 } 1177 } 1178 } 1179 1180 GUIContent[] m_RegisteredModuleNames; 1181 List<SpriteEditorModuleBase> m_AllRegisteredModules; 1182 List<SpriteEditorModuleBase> m_RegisteredModules; 1183 SpriteEditorModuleBase m_CurrentModule = null; 1184 int m_CurrentModuleIndex = 0; 1185 [SerializeField] 1186 string m_LastUsedModuleTypeName; 1187 1188 internal void SetupModule(int newModuleIndex) 1189 { 1190 if (m_CurrentModule != null) 1191 m_CurrentModule.OnModuleDeactivate(); 1192 1193 m_CurrentModule = null; 1194 m_ModuleViewElement.Clear(); 1195 m_ModuleToolbarContainer.Clear(); 1196 1197 if (m_RegisteredModules.Count > newModuleIndex && newModuleIndex >= 0) 1198 { 1199 m_CurrentModuleIndex = newModuleIndex; 1200 m_CurrentModule = m_RegisteredModules[newModuleIndex]; 1201 // if there are any modes for the module 1202 List<Type> modes; 1203 if (m_CurrentModule is SpriteEditorModuleModeSupportBase moduleWithModes && 1204 m_ModuleMode.TryGetValue(moduleWithModes.GetType(), out modes)) 1205 { 1206 moduleWithModes.SetModuleModes(modes); 1207 } 1208 m_LastUsedModuleTypeName = m_CurrentModule.GetType().FullName; 1209 m_CurrentModule.OnModuleActivate(); 1210 } 1211 1212 if (m_MainViewElement != null) 1213 m_MainViewElement.MarkDirtyRepaint(); 1214 if (m_ModuleViewElement != null) 1215 m_ModuleViewElement.MarkDirtyRepaint(); 1216 } 1217 1218 void UpdateAvailableModules() 1219 { 1220 if (m_AllRegisteredModules == null) 1221 return; 1222 m_RegisteredModules = new List<SpriteEditorModuleBase>(); 1223 int lastUsedModuleIndex = -1; 1224 if (activeDataProviderSelected) 1225 { 1226 foreach (var module in m_AllRegisteredModules) 1227 { 1228 if (module.CanBeActivated()) 1229 { 1230 RequireSpriteDataProviderAttribute attribute = null; 1231 m_ModuleRequireSpriteDataProvider.TryGetValue(module.GetType(), out attribute); 1232 if (attribute == null || attribute.ContainsAllType(m_SpriteDataProvider)) 1233 { 1234 m_RegisteredModules.Add(module); 1235 } 1236 } 1237 } 1238 1239 lastUsedModuleIndex = 0; 1240 m_RegisteredModuleNames = new GUIContent[m_RegisteredModules.Count]; 1241 for (int i = 0; i < m_RegisteredModules.Count; i++) 1242 { 1243 m_RegisteredModuleNames[i] = new GUIContent(m_RegisteredModules[i].moduleName); 1244 if (m_RegisteredModules[i].GetType().FullName.Equals(m_LastUsedModuleTypeName)) 1245 { 1246 lastUsedModuleIndex = i; 1247 } 1248 } 1249 } 1250 1251 if (m_ModuleDropDownUI != null) 1252 { 1253 m_ModuleDropDownUI.style.display = m_RegisteredModuleNames?.Length > 1 ? DisplayStyle.Flex : DisplayStyle.None; 1254 m_ModuleDropDownUI.style.position = m_RegisteredModuleNames?.Length > 1 ? Position.Relative : Position.Absolute; 1255 } 1256 1257 SetupModule(lastUsedModuleIndex); 1258 } 1259 1260 void InitModules() 1261 { 1262 m_AllRegisteredModules = new List<SpriteEditorModuleBase>(); 1263 m_ModuleRequireSpriteDataProvider.Clear(); 1264 m_ModuleMode.Clear(); 1265 1266 if (m_OutlineTexture == null) 1267 { 1268 m_OutlineTexture = new UnityTexture2D(1, 16, TextureFormat.RGBA32, false); 1269 m_OutlineTexture.SetPixels(new Color[] 1270 { 1271 new Color(0.5f, 0.5f, 0.5f, 0.5f), new Color(0.5f, 0.5f, 0.5f, 0.5f), new Color(0.8f, 0.8f, 0.8f, 0.8f), new Color(0.8f, 0.8f, 0.8f, 0.8f), 1272 Color.white, Color.white, Color.white, Color.white, 1273 new Color(.8f, .8f, .8f, 1f), new Color(.5f, .5f, .5f, .8f), new Color(0.3f, 0.3f, 0.3f, 0.5f), new Color(0.3f, .3f, 0.3f, 0.5f), 1274 new Color(0.3f, .3f, 0.3f, 0.3f), new Color(0.3f, .3f, 0.3f, 0.3f), new Color(0.1f, 0.1f, 0.1f, 0.1f), new Color(0.1f, .1f, 0.1f, 0.1f) 1275 }); 1276 m_OutlineTexture.Apply(); 1277 m_OutlineTexture.hideFlags = HideFlags.HideAndDontSave; 1278 } 1279 var outlineTexture = new Texture2DWrapper(m_OutlineTexture); 1280 1281 // Add your modules here 1282 RegisterModule(new SpriteFrameModule(this, m_EventSystem, m_UndoSystem, m_AssetDatabase)); 1283 RegisterModule(new SpritePolygonModeModule(this, m_EventSystem, m_UndoSystem, m_AssetDatabase)); 1284 RegisterModule(new SpriteOutlineModule(this, m_EventSystem, m_UndoSystem, m_AssetDatabase, m_GUIUtility, new ShapeEditorFactory(), outlineTexture)); 1285 RegisterModule(new SpritePhysicsShapeModule(this, m_EventSystem, m_UndoSystem, m_AssetDatabase, m_GUIUtility, new ShapeEditorFactory(), outlineTexture)); 1286 RegisterCustomModules(); 1287 UpdateAvailableModules(); 1288 } 1289 1290 void RegisterModule(SpriteEditorModuleBase module) 1291 { 1292 var type = module.GetType(); 1293 bool showAsModule = true; 1294 if (module is SpriteEditorModeBase) 1295 { 1296 var moduleMode = type.GetCustomAttributes(typeof(SpriteEditorModuleModeAttribute), false); 1297 if (moduleMode.Length == 1) 1298 { 1299 var modeAttribute = (SpriteEditorModuleModeAttribute)moduleMode[0]; 1300 showAsModule = modeAttribute.showAsModule; 1301 foreach (var modeForModule in modeAttribute.GetModuleTypes()) 1302 { 1303 List<Type> modulesList; 1304 if (!m_ModuleMode.TryGetValue(modeForModule, out modulesList)) 1305 modulesList = new List<Type>(); 1306 modulesList.Add(module.GetType()); 1307 m_ModuleMode[modeForModule] = modulesList; 1308 } 1309 } 1310 } 1311 1312 if(showAsModule) 1313 { 1314 var attributes = type.GetCustomAttributes(typeof(RequireSpriteDataProviderAttribute), false); 1315 if (attributes.Length == 1) 1316 m_ModuleRequireSpriteDataProvider.Add(type, (RequireSpriteDataProviderAttribute)attributes[0]); 1317 m_AllRegisteredModules.Add(module); 1318 } 1319 } 1320 1321 void RegisterCustomModules() 1322 { 1323 foreach (var moduleClassType in TypeCache.GetTypesDerivedFrom<SpriteEditorModuleBase>()) 1324 { 1325 if (!moduleClassType.IsAbstract) 1326 { 1327 bool moduleFound = false; 1328 foreach (var module in m_AllRegisteredModules) 1329 { 1330 if (module.GetType() == moduleClassType) 1331 { 1332 moduleFound = true; 1333 break; 1334 } 1335 } 1336 if (!moduleFound) 1337 { 1338 var constructorType = new Type[0]; 1339 // Get the public instance constructor that takes ISpriteEditorModule parameter. 1340 var constructorInfoObj = moduleClassType.GetConstructor( 1341 BindingFlags.Instance | BindingFlags.Public, null, 1342 CallingConventions.HasThis, constructorType, null); 1343 if (constructorInfoObj != null) 1344 { 1345 try 1346 { 1347 var newInstance = constructorInfoObj.Invoke(new object[0]) as SpriteEditorModuleBase; 1348 if (newInstance != null) 1349 { 1350 newInstance.spriteEditor = this; 1351 RegisterModule(newInstance); 1352 } 1353 } 1354 catch (Exception ex) 1355 { 1356 Debug.LogWarning("Unable to instantiate custom module " + moduleClassType.FullName + ". Exception:" + ex); 1357 } 1358 } 1359 else 1360 Debug.LogWarning(moduleClassType.FullName + " does not have a parameterless constructor"); 1361 } 1362 } 1363 } 1364 } 1365 1366 internal List<SpriteEditorModuleBase> activatedModules 1367 { 1368 get { return m_RegisteredModules; } 1369 } 1370 1371 public List<SpriteRect> spriteRects 1372 { 1373 set 1374 { 1375 m_RectsCache = value; 1376 m_CachedSelectedSpriteRect = null; 1377 } 1378 } 1379 1380 private SpriteRect m_CachedSelectedSpriteRect; 1381 1382 public SpriteRect selectedSpriteRect 1383 { 1384 get 1385 { 1386 // Always return null if editing is disabled to prevent all possible action to selected frame. 1387 if (editingDisabled || m_RectsCache == null || string.IsNullOrEmpty(m_SelectedSpriteRectGUID)) 1388 return null; 1389 1390 var guid = new GUID(m_SelectedSpriteRectGUID); 1391 if (m_CachedSelectedSpriteRect == null || m_CachedSelectedSpriteRect.spriteID != guid) 1392 { 1393 m_CachedSelectedSpriteRect = m_RectsCache.FirstOrDefault(x => x.spriteID == guid); 1394 } 1395 return m_CachedSelectedSpriteRect; 1396 } 1397 set 1398 { 1399 if (editingDisabled) 1400 return; 1401 1402 var oldSelected = m_SelectedSpriteRectGUID; 1403 m_SelectedSpriteRectGUID = value != null ? value.spriteID.ToString() : new GUID().ToString(); 1404 if (oldSelected != m_SelectedSpriteRectGUID) 1405 { 1406 if (m_MainViewIMGUIElement != null) 1407 m_MainViewIMGUIElement.MarkDirtyRepaint(); 1408 if (m_MainViewElement != null) 1409 { 1410 m_MainViewElement.MarkDirtyRepaint(); 1411 using (var e = SpriteSelectionChangeEvent.GetPooled()) 1412 { 1413 e.target = m_ModuleViewElement; 1414 m_MainViewElement.SendEvent(e); 1415 } 1416 } 1417 } 1418 } 1419 } 1420 1421 public ISpriteEditorDataProvider spriteEditorDataProvider 1422 { 1423 get { return m_SpriteDataProvider; } 1424 } 1425 1426 public bool enableMouseMoveEvent 1427 { 1428 set { wantsMouseMove = value; } 1429 } 1430 1431 public void RequestRepaint() 1432 { 1433 if (focusedWindow != this) 1434 Repaint(); 1435 else 1436 m_RequestRepaint = true; 1437 } 1438 1439 public void SetDataModified() 1440 { 1441 textureIsDirty = true; 1442 } 1443 1444 public Rect windowDimension 1445 { 1446 get { return textureViewRect; } 1447 } 1448 1449 public ITexture2D previewTexture 1450 { 1451 get { return m_Texture; } 1452 } 1453 1454 public bool editingDisabled => EditorApplication.isPlayingOrWillChangePlaymode || m_AssetNotEditable; 1455 1456 public void SetPreviewTexture(UnityTexture2D texture, int width, int height) 1457 { 1458 m_Texture = new PreviewTexture2D(texture, width, height); 1459 } 1460 1461 public void ApplyOrRevertModification(bool apply) 1462 { 1463 if (apply) 1464 DoApply(); 1465 else 1466 DoRevert(); 1467 } 1468 1469 internal class PreviewTexture2D : Texture2DWrapper 1470 { 1471 private int m_ActualWidth = 0; 1472 private int m_ActualHeight = 0; 1473 1474 public PreviewTexture2D(UnityTexture2D t, int width, int height) 1475 : base(t) 1476 { 1477 m_ActualWidth = width; 1478 m_ActualHeight = height; 1479 } 1480 1481 public override int width 1482 { 1483 get { return m_ActualWidth; } 1484 } 1485 1486 public override int height 1487 { 1488 get { return m_ActualHeight; } 1489 } 1490 } 1491 1492 public T GetDataProvider<T>() where T : class 1493 { 1494 return m_SpriteDataProvider != null ? m_SpriteDataProvider.GetDataProvider<T>() : null; 1495 } 1496 1497 public VisualElement GetMainVisualContainer() 1498 { 1499 return m_ModuleViewElement; 1500 } 1501 1502 public VisualElement GetToolbarRootElement() 1503 { 1504 return m_ModuleToolbarContainer; 1505 } 1506 1507 static internal void OnTextureReimport(SpriteEditorWindow win, string path) 1508 { 1509 if (win.selectedAssetPath == path) 1510 { 1511 win.ResetOnNextRepaint(); 1512 } 1513 } 1514 1515 [MenuItem("Window/2D/Sprite Editor", priority = 0)] 1516 static private void OpenSpriteEditorWindow() 1517 { 1518 SpriteEditorWindow.GetWindow(Selection.activeObject); 1519 } 1520 } 1521 1522 internal class SpriteEditorTexturePostprocessor : AssetPostprocessor 1523 { 1524 public override int GetPostprocessOrder() 1525 { 1526 return 1; 1527 } 1528 1529 static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) 1530 { 1531 UnityEngine.Object[] wins = Resources.FindObjectsOfTypeAll(typeof(SpriteEditorWindow)); 1532 SpriteEditorWindow win = wins.Length > 0 ? (EditorWindow)(wins[0]) as SpriteEditorWindow : null; 1533 if (win != null) 1534 { 1535 foreach (var deletedAsset in deletedAssets) 1536 SpriteEditorWindow.OnTextureReimport(win, deletedAsset); 1537 1538 bool rebuildTracker = false; 1539 var assetPaths = ActiveEditorTracker.sharedTracker.activeEditors.Where(x => x.target is AssetImporter).Select(y => ((AssetImporter)y.target).assetPath); 1540 foreach (var importedAsset in importedAssets) 1541 { 1542 SpriteEditorWindow.OnTextureReimport(win, importedAsset); 1543 if (!rebuildTracker) 1544 { 1545 rebuildTracker = assetPaths.Contains(importedAsset); 1546 } 1547 } 1548 // Since Inspector Window doesn't rebuild anymore, we need to do it manually (https://github.cds.internal.unity3d.com/unity/unity/pull/13828) 1549 if(rebuildTracker) 1550 ActiveEditorTracker.sharedTracker.ForceRebuild(); 1551 } 1552 } 1553 } 1554 1555 internal class SpriteSelectionChangeEvent : EventBase<SpriteSelectionChangeEvent> 1556 { 1557 } 1558}