DrawAssetOverlay.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. using System;
  2. using UnityEditor;
  3. using UnityEngine;
  4. using PlasticGui;
  5. using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
  6. using Unity.PlasticSCM.Editor.UI;
  7. namespace Unity.PlasticSCM.Editor.AssetsOverlays
  8. {
  9. internal static class DrawAssetOverlay
  10. {
  11. internal static void Initialize(
  12. IAssetStatusCache cache,
  13. Action repaintProjectWindow)
  14. {
  15. mAssetStatusCache = cache;
  16. mRepaintProjectWindow = repaintProjectWindow;
  17. EditorApplication.projectWindowItemOnGUI += OnProjectWindowItemGUI;
  18. mRepaintProjectWindow();
  19. }
  20. internal static void Dispose()
  21. {
  22. EditorApplication.projectWindowItemOnGUI -= OnProjectWindowItemGUI;
  23. if (mRepaintProjectWindow != null)
  24. mRepaintProjectWindow();
  25. }
  26. internal static void ClearCache()
  27. {
  28. mAssetStatusCache.Clear();
  29. mRepaintProjectWindow();
  30. }
  31. internal static AssetStatus GetStatusesToDraw(AssetStatus status)
  32. {
  33. if (status.HasFlag(AssetStatus.Checkout) &&
  34. status.HasFlag(AssetStatus.Locked))
  35. return status & ~AssetStatus.Checkout;
  36. if (status.HasFlag(AssetStatus.DeletedOnServer) &&
  37. status.HasFlag(AssetStatus.LockedRemote))
  38. return status & ~AssetStatus.LockedRemote;
  39. return status;
  40. }
  41. internal static string GetStatusString(AssetStatus statusValue)
  42. {
  43. switch (statusValue)
  44. {
  45. case AssetStatus.Private:
  46. return PlasticLocalization.GetString(
  47. PlasticLocalization.Name.Private);
  48. case AssetStatus.Ignored:
  49. return PlasticLocalization.GetString(
  50. PlasticLocalization.Name.StatusIgnored);
  51. case AssetStatus.Added:
  52. return PlasticLocalization.GetString(
  53. PlasticLocalization.Name.StatusAdded);
  54. case AssetStatus.Checkout:
  55. return PlasticLocalization.GetString(
  56. PlasticLocalization.Name.StatusCheckout);
  57. case AssetStatus.OutOfDate:
  58. return PlasticLocalization.GetString(
  59. PlasticLocalization.Name.StatusOutOfDate);
  60. case AssetStatus.Conflicted:
  61. return PlasticLocalization.GetString(
  62. PlasticLocalization.Name.StatusConflicted);
  63. case AssetStatus.DeletedOnServer:
  64. return PlasticLocalization.GetString(
  65. PlasticLocalization.Name.StatusDeletedOnServer);
  66. case AssetStatus.Locked:
  67. return PlasticLocalization.GetString(
  68. PlasticLocalization.Name.StatusLockedMe);
  69. case AssetStatus.LockedRemote:
  70. return PlasticLocalization.GetString(
  71. PlasticLocalization.Name.StatusLockedRemote);
  72. }
  73. return string.Empty;
  74. }
  75. internal static string GetTooltipText(
  76. AssetStatus statusValue,
  77. LockStatusData lockStatusData)
  78. {
  79. string statusText = GetStatusString(statusValue);
  80. if (lockStatusData == null)
  81. return statusText;
  82. // example:
  83. // Changed by:
  84. // * dani_pen@hotmail.com
  85. // * workspace wkLocal"
  86. char bulletCharacter = '\u25cf';
  87. string line1 = PlasticLocalization.GetString(
  88. PlasticLocalization.Name.AssetOverlayTooltipStatus, statusText);
  89. string line2 = string.Format("{0} {1}",
  90. bulletCharacter,
  91. lockStatusData.LockedBy);
  92. string line3 = string.Format("{0} {1}",
  93. bulletCharacter,
  94. PlasticLocalization.GetString(
  95. PlasticLocalization.Name.AssetOverlayTooltipWorkspace,
  96. lockStatusData.WorkspaceName));
  97. return string.Format(
  98. "{0}" + Environment.NewLine +
  99. "{1}" + Environment.NewLine +
  100. "{2}",
  101. line1,
  102. line2,
  103. line3);
  104. }
  105. static void OnProjectWindowItemGUI(string guid, Rect selectionRect)
  106. {
  107. if (string.IsNullOrEmpty(guid))
  108. return;
  109. if (Event.current.type != EventType.Repaint)
  110. return;
  111. AssetStatus statusesToDraw = GetStatusesToDraw(
  112. mAssetStatusCache.GetStatusForGuid(guid));
  113. foreach (AssetStatus status in Enum.GetValues(typeof(AssetStatus)))
  114. {
  115. if (status == AssetStatus.None)
  116. continue;
  117. if (!statusesToDraw.HasFlag(status))
  118. continue;
  119. LockStatusData lockStatusData =
  120. ClassifyAssetStatus.IsLockedRemote(status) ?
  121. mAssetStatusCache.GetLockStatusData(guid) :
  122. null;
  123. string tooltipText = GetTooltipText(
  124. status,
  125. lockStatusData);
  126. DrawOverlayIcon.ForStatus(
  127. selectionRect,
  128. status,
  129. tooltipText);
  130. }
  131. }
  132. internal static class DrawOverlayIcon
  133. {
  134. internal static void ForStatus(
  135. Rect selectionRect,
  136. AssetStatus status,
  137. string tooltipText)
  138. {
  139. Texture overlayIcon = GetOverlayIcon(status);
  140. if (overlayIcon == null)
  141. return;
  142. Rect overlayRect = GetOverlayRect(
  143. selectionRect, overlayIcon, status);
  144. GUI.DrawTexture(
  145. overlayRect, overlayIcon, ScaleMode.ScaleToFit);
  146. Rect tooltipRect = GetTooltipRect(selectionRect, overlayRect);
  147. GUI.Label(tooltipRect, new GUIContent(string.Empty, tooltipText));
  148. }
  149. internal static Texture GetOverlayIcon(AssetStatus status)
  150. {
  151. switch (status)
  152. {
  153. case AssetStatus.Ignored:
  154. return Images.GetImage(Images.Name.Ignored);
  155. case AssetStatus.Private:
  156. return Images.GetPrivatedOverlayIcon();
  157. case AssetStatus.Added:
  158. return Images.GetAddedOverlayIcon();
  159. case AssetStatus.Checkout:
  160. return Images.GetCheckedOutOverlayIcon();
  161. case AssetStatus.OutOfDate:
  162. return Images.GetOutOfSyncOverlayIcon();
  163. case AssetStatus.Conflicted:
  164. return Images.GetConflictedOverlayIcon();
  165. case AssetStatus.DeletedOnServer:
  166. return Images.GetDeletedRemoteOverlayIcon();
  167. case AssetStatus.Locked:
  168. return Images.GetLockedLocalOverlayIcon();
  169. case AssetStatus.LockedRemote:
  170. return Images.GetLockedRemoteOverlayIcon();
  171. }
  172. return null;
  173. }
  174. static Rect Inflate(Rect rect, float width, float height)
  175. {
  176. return new Rect(
  177. rect.x - width,
  178. rect.y - height,
  179. rect.width + 2 * width,
  180. rect.height + 2 * height);
  181. }
  182. static Rect GetOverlayRect(
  183. Rect selectionRect,
  184. Texture overlayIcon,
  185. AssetStatus status)
  186. {
  187. OverlayAlignment alignment = GetIconPosition(status);
  188. if (selectionRect.width > selectionRect.height)
  189. return GetOverlayRectForSmallestSize(
  190. selectionRect, overlayIcon, alignment);
  191. return GetOverlayRectForOtherSizes(
  192. selectionRect, overlayIcon, alignment);
  193. }
  194. static Rect GetTooltipRect(
  195. Rect selectionRect,
  196. Rect overlayRect)
  197. {
  198. if (selectionRect.width > selectionRect.height)
  199. {
  200. return overlayRect;
  201. }
  202. return Inflate(overlayRect, 3, 3);
  203. }
  204. static Rect GetOverlayRectForSmallestSize(
  205. Rect selectionRect,
  206. Texture overlayIcon,
  207. OverlayAlignment alignment)
  208. {
  209. float xOffset = IsLeftAligned(alignment) ? -5 : 5;
  210. float yOffset = IsTopAligned(alignment) ? -4 : 4;
  211. return new Rect(
  212. selectionRect.x + xOffset,
  213. selectionRect.y + yOffset,
  214. OVERLAY_ICON_SIZE,
  215. OVERLAY_ICON_SIZE);
  216. }
  217. static Rect GetOverlayRectForOtherSizes(
  218. Rect selectionRect,
  219. Texture overlayIcon,
  220. OverlayAlignment alignment)
  221. {
  222. float xOffset = IsLeftAligned(alignment) ?
  223. 0 : selectionRect.width - overlayIcon.width;
  224. float yOffset = IsTopAligned(alignment) ?
  225. 0 : selectionRect.height - overlayIcon.height - 12;
  226. return new Rect(
  227. selectionRect.x + xOffset,
  228. selectionRect.y + yOffset,
  229. OVERLAY_ICON_SIZE,
  230. OVERLAY_ICON_SIZE);
  231. }
  232. static OverlayAlignment GetIconPosition(AssetStatus status)
  233. {
  234. if (status == AssetStatus.Checkout ||
  235. status == AssetStatus.Locked)
  236. return OverlayAlignment.TopLeft;
  237. if (status == AssetStatus.DeletedOnServer ||
  238. status == AssetStatus.LockedRemote)
  239. return OverlayAlignment.TopRight;
  240. if (status == AssetStatus.OutOfDate)
  241. return OverlayAlignment.BottomRight;
  242. return OverlayAlignment.BottomLeft;
  243. }
  244. static bool IsLeftAligned(OverlayAlignment alignment)
  245. {
  246. return alignment == OverlayAlignment.BottomLeft ||
  247. alignment == OverlayAlignment.TopLeft;
  248. }
  249. static bool IsTopAligned(OverlayAlignment alignment)
  250. {
  251. return alignment == OverlayAlignment.TopLeft ||
  252. alignment == OverlayAlignment.TopRight;
  253. }
  254. enum OverlayAlignment
  255. {
  256. TopLeft,
  257. BottomLeft,
  258. TopRight,
  259. BottomRight
  260. }
  261. }
  262. static IAssetStatusCache mAssetStatusCache;
  263. static Action mRepaintProjectWindow;
  264. const float OVERLAY_ICON_SIZE = 16;
  265. }
  266. }