using UnityEditor; using UnityEngine; using System; using Perforce.P4; using System.IO; namespace P4Connect { public class Icons { private const float MinHeight = 16.0f; private const float MinWidth = 32.0f; private const float MaxWidth = 96.0f; private const float IconMinSize = 8.0f; private const float IconMaxSize = 24.0f; private const float MarginX = 1.0f; private const float MarginY = 0.0f; enum Corner { BottomRight = 0, BottomLeft, TopLeft, TopRight, Center } static Texture _iconHasLatest; static Texture _iconOutOfDate; static Texture _iconCheckedOutLocal; static Texture _iconCheckedOutOther; static Texture _iconMarkedForAddLocal; static Texture _iconMarkedForAddOther; static Texture _iconMarkedForDeleteLocal; static Texture _iconMarkedForDeleteOther; static Texture _iconMoveAdd; static Texture _iconMoveDelete; static Texture _iconMissingFile; static Texture _iconOtherFile; static Texture _iconPairFileOnly; static Texture _iconPairMetaOnly; static Texture _iconPairFileAndMeta; static Texture _iconNeedsResolve; static Texture _iconFolderMetaOutOfDate; static Texture _iconFolderMetaModifiedLocal; static Texture _iconLockedLocal; static Texture _iconLockedOther; static Texture _iconChangeOther; static Texture _iconChangeLocal; static Texture _iconChangeShelvedOther; static Texture _iconChangeShelvedLocal; static UnityEngine.Object[] _allTextures; static AssetBundle _iconbundle = null; public static string PackFile = "P4Connect.icons"; public static void Initialize() { string iconsPath = Path.Combine(Utils.GetEditorAssetFullDirectory(), PackFile); if (_iconbundle != null) { _iconbundle.Unload(true); } _iconbundle = AssetBundle.LoadFromFile(iconsPath); if (_iconbundle != null) { _allTextures = _iconbundle.LoadAllAssets(typeof(Texture)); _iconbundle.Unload(false); } else { Debug.Log("Failed to load " + iconsPath + " bundle in " + Application.unityVersion); } if (_allTextures != null) { _iconHasLatest = GetTexture("Has-Latest"); _iconOutOfDate = GetTexture("Out-of-date"); _iconCheckedOutLocal = GetTexture("Checked-out-Local"); _iconCheckedOutOther = GetTexture("Checked-out-Other"); _iconMarkedForAddLocal = GetTexture("Marked-for-add-Local"); _iconMarkedForAddOther = GetTexture("Marked-for-add-Other"); _iconMarkedForDeleteLocal = GetTexture("Marked-for-delete-Local"); _iconMarkedForDeleteOther = GetTexture("Marked-for-delete-Other"); _iconMoveAdd = GetTexture("Move-Add"); _iconMoveDelete = GetTexture("Move-Delete"); _iconMissingFile = GetTexture("missing-file"); _iconOtherFile = GetTexture("other-file"); _iconPairFileOnly = GetTexture("has-file"); _iconPairMetaOnly = GetTexture("has-meta"); _iconPairFileAndMeta = GetTexture("has-file-and-meta"); _iconNeedsResolve = GetTexture("needs-resolve"); _iconFolderMetaOutOfDate = GetTexture("foldermeta-out-of-date"); _iconFolderMetaModifiedLocal = GetTexture("foldermeta-modified-local"); _iconLockedLocal = GetTexture("locked-local"); _iconLockedOther = GetTexture("locked-other"); _iconChangeOther = GetTexture("change-other"); _iconChangeLocal = GetTexture("change-local"); _iconChangeShelvedOther = GetTexture("change-other"); // need change-shelved-other FIXME _iconChangeShelvedLocal = GetTexture("change-local"); // need change-shelved-local FIXME _lastSelection = ""; UpdateDisplay(); } } // During development icons can be placed here: Later they should get moved into the assetbundle public static string AssetIconsFolder = "Icons/"; // P4Connect/Editor/Icons/... /// /// Given an Icon name (with extension). /// See if it is in the Icon Asset we provide, and if not there, look on the filesystem for a "loose" texture. /// /// /// public static Texture GetIcon(string name) { CheckInit(); var tex = GetTexture(System.IO.Path.GetFileNameWithoutExtension(name)); if (tex == null) { try { string loosePath = Path.Combine(Utils.GetEditorAssetFullDirectory(), AssetIconsFolder); tex = AssetDatabase.LoadAssetAtPath(loosePath + name, typeof(Texture2D)) as Texture2D; if (tex == null) { Debug.Log("Couldn't find loose image: " + name + " at: " + loosePath + name); } } catch (Exception ex) { Debug.LogException(ex); } } if (tex != null) return tex; return new Texture(); // Better than returning null? } private static Texture GetTexture(string name) { Texture icon = null; foreach(var o in _allTextures) { icon = (Texture) o; if (String.Equals(icon.name, name, StringComparison.CurrentCultureIgnoreCase)) { return icon; } } return null; } // Preserve the last selection for comparison private static string _lastSelection = ""; // // Hook up the project window update callbacks into editorApplication // Called from Icons.Initialize() // public static void UpdateDisplay() { //Debug.Log("UpdateDisplay"); // Clear existing callbacks EditorApplication.projectWindowItemOnGUI -= OnProjectWindowItem; EditorApplication.update -= OnUpdate; // Assuming We are Valid and Displaying icons, set the callbacks if (Config.ValidConfiguration && Config.DisplayStatusIcons) { EditorApplication.projectWindowItemOnGUI += OnProjectWindowItem; EditorApplication.update += OnUpdate; } EditorApplication.RepaintProjectWindow(); } static void OnProjectWindowItem(String aGuid, Rect aSelectionRect) { // What kind of asset is this? string assetPath = AssetDatabase.GUIDToAssetPath(aGuid); DrawItemIcons(assetPath, aSelectionRect, aSelectionRect.height <= 16.0f); } static void OnUpdate() { // Don't update icons while in play mode if (Config.ValidConfiguration && Config.DisplayStatusIcons && Config.IsEditing()) { string lastSelection = _lastSelection; _lastSelection = Logger.StringEnumerationToString(Utils.GetSelectedAssetPaths()); if (_lastSelection != lastSelection) { // Debug.Log("Selectionchanged: " + _lastSelection); UpdateDisplay(); } } } /// /// Return the Asset Path for the current Project Window selection /// /// public static string CurrentProjectSelection() { return Utils.GetSelectedAssetPaths().ToStringNullSafe(); } public static void DrawItemIcons(String aAssetPath, Rect aSelectionRect, bool aHorizontal) { CheckInit(); // What kind of asset is this? if (aAssetPath != "" && aAssetPath != "Assets") { bool isFolder = Utils.IsDirectory(aAssetPath); AssetStatus status; if (isFolder) status = AssetStatusCache.GetCachedAssetStatusAndUpdateDefaults(Utils.MetaFromAsset(aAssetPath)); else status = AssetStatusCache.GetCachedAssetStatusAndUpdateDefaults(aAssetPath); DrawItemIcons(status, isFolder, aSelectionRect, aHorizontal); } } public static void DrawItemIcons(AssetStatus aStatus, bool aIsFolder, Rect aSelectionRect, bool aHorizontal) { Rect iconRect = GetIconRect(aSelectionRect, Corner.TopLeft, aHorizontal); switch (aStatus.LocalState) { case FileState.None: break; case FileState.InDepot: break; case FileState.MarkedForEdit: if (aIsFolder) GUI.DrawTexture(iconRect, _iconFolderMetaModifiedLocal); else GUI.DrawTexture(iconRect, _iconCheckedOutLocal); break; case FileState.MarkedForAdd: if (aIsFolder) GUI.DrawTexture(iconRect, _iconFolderMetaModifiedLocal); else GUI.DrawTexture(iconRect, _iconMarkedForAddLocal); break; case FileState.MarkedForDelete: if (aIsFolder) GUI.DrawTexture(iconRect, _iconFolderMetaModifiedLocal); else GUI.DrawTexture(iconRect, _iconMarkedForDeleteLocal); break; case FileState.MarkedForAddMove: if (aIsFolder) GUI.DrawTexture(iconRect, _iconFolderMetaModifiedLocal); else GUI.DrawTexture(iconRect, _iconMoveAdd); break; case FileState.MarkedForDeleteMove: if (aIsFolder) GUI.DrawTexture(iconRect, _iconFolderMetaModifiedLocal); else GUI.DrawTexture(iconRect, _iconMoveDelete); break; } iconRect = GetIconRect(aSelectionRect, Corner.TopRight, aHorizontal); switch (aStatus.OtherState) { case FileState.None: break; case FileState.InDepot: break; case FileState.MarkedForEdit: if (!aIsFolder) { GUI.DrawTexture(iconRect, _iconCheckedOutOther); } break; case FileState.MarkedForAdd: if (!aIsFolder) { GUI.DrawTexture(iconRect, _iconMarkedForAddOther); } break; case FileState.MarkedForDelete: if (!aIsFolder) { GUI.DrawTexture(iconRect, _iconMarkedForDeleteOther); } break; case FileState.MarkedForAddMove: if (!aIsFolder) { GUI.DrawTexture(iconRect, _iconMarkedForAddOther); } break; case FileState.MarkedForDeleteMove: if (!aIsFolder) { GUI.DrawTexture(iconRect, _iconMarkedForDeleteOther); } break; } iconRect = GetIconRect(aSelectionRect, Corner.BottomRight, aHorizontal); switch (aStatus.LocalState) { case FileState.None: break; case FileState.InDepot: switch (aStatus.RevisionState) { case RevisionState.None: break; case RevisionState.HasLatest: if (!aIsFolder) { GUI.DrawTexture(iconRect, _iconHasLatest); } break; case RevisionState.OutOfDate: if (aIsFolder) GUI.DrawTexture(iconRect, _iconFolderMetaOutOfDate); else GUI.DrawTexture(iconRect, _iconOutOfDate); break; } break; case FileState.MarkedForEdit: goto case FileState.InDepot; case FileState.MarkedForAdd: break; case FileState.MarkedForDelete: goto case FileState.InDepot; case FileState.MarkedForAddMove: if (!aIsFolder) { GUI.DrawTexture(iconRect, _iconHasLatest); } break; case FileState.MarkedForDeleteMove: goto case FileState.InDepot; } switch (aStatus.ResolvedState) { case ResolvedState.None: break; case ResolvedState.NeedsResolve: if (aIsFolder) { iconRect = GetIconRect(aSelectionRect, Corner.BottomRight, aHorizontal); GUI.DrawTexture(iconRect, _iconNeedsResolve); } else { iconRect = GetIconRect(aSelectionRect, Corner.Center, aHorizontal); GUI.DrawTexture(iconRect, _iconNeedsResolve); } break; } switch (aStatus.LockState) { case LockState.None: break; case LockState.OurLock: iconRect = GetIconRect(aSelectionRect, Corner.BottomLeft, aHorizontal); GUI.DrawTexture(iconRect, _iconLockedLocal); break; case LockState.TheirLock: iconRect = GetIconRect(aSelectionRect, Corner.BottomLeft, aHorizontal); GUI.DrawTexture(iconRect, _iconLockedOther); break; } } public static Texture GetAssetIcon(string arPath) { CheckInit(); Texture asset = AssetDatabase.GetCachedIcon(arPath); // If we still don't have an icon, use a default one if (asset == null) { if (arPath.StartsWith("Assets/",!Utils.IsCaseSensitive(),null)) { asset = _iconMissingFile; } else { asset = _iconOtherFile; } } return asset; } public static Texture GetFileAndMetaTypeIcon(FileAndMetaType aType) { CheckInit(); Texture ret = null; switch (aType) { case FileAndMetaType.FileOnly: ret = _iconPairFileOnly; break; case FileAndMetaType.MetaOnly: ret = _iconPairMetaOnly; break; case FileAndMetaType.FileAndMeta: ret = _iconPairFileAndMeta; break; } return ret; } static Rect GetIconRect(Rect aSelectionRect, Corner aCorner, bool aHorizontal) { Rect iconRect = aSelectionRect; float iconSize = 0.0f; if (aHorizontal) { // The view is in list mode iconSize = IconMinSize; switch (aCorner) { case Corner.BottomRight: iconRect.xMin += MinHeight - iconSize + MarginX; iconRect.yMin = iconRect.yMax - iconSize + MarginY; break; case Corner.BottomLeft: iconRect.xMin -= MarginX; iconRect.yMin = iconRect.yMax - iconSize + MarginY; break; case Corner.TopLeft: iconRect.xMin -= MarginX; iconRect.yMin -= MarginY; break; case Corner.TopRight: iconRect.xMin += MinHeight - iconSize + MarginX; iconRect.yMin -= MarginY; break; case Corner.Center: iconRect.xMin += 1.0f; iconRect.xMax = iconRect.xMin + MinHeight - 2.0f; iconRect.yMin += 1.0f; iconRect.yMax -= 1.0f; break; } } else { // The view is in grid mode float sizePercent = (aSelectionRect.width - MinWidth) / (MaxWidth - MinWidth); iconSize = Mathf.Round(Mathf.Lerp(IconMinSize, IconMaxSize, sizePercent)); switch (aCorner) { case Corner.BottomRight: iconRect.xMin = iconRect.xMax - iconSize + MarginX; iconRect.yMin = iconRect.yMax - MinHeight - iconSize + MarginY; break; case Corner.BottomLeft: iconRect.xMin -= MarginX; iconRect.yMin = iconRect.yMax - MinHeight - iconSize + MarginY; break; case Corner.TopLeft: iconRect.xMin -= MarginX; iconRect.yMin -= MarginY; break; case Corner.TopRight: iconRect.xMin = iconRect.xMax - iconSize + MarginX; iconRect.yMin -= MarginY; break; case Corner.Center: iconRect.yMax -= MinHeight + 1.0f; iconRect.yMin += 2.0f; iconRect.xMin += 2.0f; iconRect.xMax -= 2.0f; break; } } if (aCorner != Corner.Center) { iconRect.width = iconSize; iconRect.height = iconSize; } return iconRect; } public static Texture GetChangelistIcon(Changelist change) { CheckInit(); Texture asset; if (change.OwnerName == Config.Username && change.ClientId == Config.Workspace) { asset = change.Shelved ? _iconChangeShelvedLocal : _iconChangeLocal; } else { asset = change.Shelved ? _iconChangeShelvedOther : _iconChangeOther; } return asset; } private static void CheckInit() { if (_iconHasLatest == null) { Initialize(); } } } }