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();
}
}
}
}