using System;
using System.IO;
using UnityEngine;
using PlasticGui.WorkspaceWindow.Items;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.CloudDrive.Workspaces.DirectoryContent
{
internal static class DrawExpandedTreeNode
{
internal const float ICON_SIZE = 66;
internal const float PADDING = 5;
internal static void Draw(
Rect rect,
ExpandedTreeNode node,
bool isSelected,
bool hasFocus,
bool isDragTarget)
{
DrawIcon(
new Rect(
rect.x + (rect.width - ICON_SIZE) / 2,
rect.y + PADDING,
ICON_SIZE,
ICON_SIZE),
GetIcon(node),
isSelected);
string fileName = Path.GetFileName(node.GetFullPath());
DrawLabel(
new Rect(
rect.x + PADDING,
rect.y + PADDING + ICON_SIZE,
rect.width - 2 * PADDING,
rect.height - ICON_SIZE - 2 * PADDING),
ExpandedTreeNode.IsDirectory(node) ? fileName : GetFileNameWithoutExtension(fileName),
fileName,
isSelected,
hasFocus,
isDragTarget);
}
internal static Texture GetIcon(ExpandedTreeNode node)
{
if (ExpandedTreeNode.IsDirectory(node))
return Images.GetFolderIcon();
return Images.GetFileIcon(node.GetFullPath());
}
static void DrawIcon(Rect rect, Texture icon, bool isSelected)
{
Color originalColor = GUI.color;
try
{
if (isSelected)
GUI.color *= UnityStyles.Colors.SelectedIcon;
GUI.DrawTexture(rect, icon);
}
finally
{
GUI.color = originalColor;
}
}
static void DrawLabel(
Rect rect,
string text,
string tooltip,
bool isSelected,
bool hasFocus,
bool isDragTarget)
{
GUIStyle normalStyle = UnityStyles.CloudDrive.ItemsListLabel;
GUIStyle focusedStyle = UnityStyles.CloudDrive.ItemsListLabelFocused;
float textWidth;
string cutText = CutText(
text, normalStyle, rect.width,
out textWidth);
Rect labelRect = new Rect(
rect.x + (rect.width - textWidth) / 2,
rect.y + (rect.height - normalStyle.lineHeight) / 2,
textWidth,
normalStyle.lineHeight);
if (isSelected)
{
Rect selectionRect = new Rect(
labelRect.x - 1, labelRect.y - 1,
labelRect.width + 2, labelRect.height + 2);
Color rectColor = hasFocus ?
UnityStyles.Colors.SelectedFocusedTextBackground :
UnityStyles.Colors.SelectedUnfocusedTextBackground;
Texture2D selectionTexture = CreateRoundedRectTexture(
selectionRect.size,
radius: 1,
borderColor: rectColor,
fillColor: rectColor,
thickness: 1);
GUI.DrawTexture(selectionRect, selectionTexture);
}
if (isDragTarget)
{
Rect dragTargetRect = new Rect(
rect.x, rect.y - 2,
rect.width, rect.height + 4);
Texture2D dragTexture = CreateRoundedRectTexture(
dragTargetRect.size,
radius: 6,
borderColor: UnityStyles.Colors.SelectedFocusedDropLineBackground,
fillColor: UnityStyles.Colors.SelectedFocusedDropLabelBackground,
thickness: 2);
GUI.DrawTexture(dragTargetRect, dragTexture);
}
GUI.Label(
labelRect,
new GUIContent(cutText, cutText == tooltip ? null : tooltip),
isSelected && hasFocus ? focusedStyle : normalStyle);
}
static string CutText(
string text,
GUIStyle style,
float availableWidth,
out float usedWidth)
{
usedWidth = 0;
availableWidth -= style.margin.horizontal + style.padding.horizontal;
float fullTextWidth = style.CalcSize(
new GUIContent(text)).x;
if (fullTextWidth <= availableWidth)
{
usedWidth = fullTextWidth;
return text;
}
string resultText = string.Empty;
foreach (char c in text)
{
float currentWidth = style.CalcSize(
new GUIContent(resultText + c + ELLIPSIS)).x;
if (currentWidth > availableWidth)
return resultText + ELLIPSIS;
usedWidth = currentWidth;
resultText += c;
}
return resultText + ELLIPSIS;
}
static string GetFileNameWithoutExtension(string fileName)
{
if (fileName.LastIndexOf(".") <= 0)
return fileName;
if (MetaPath.IsMetaPath(fileName))
fileName = MetaPath.GetPathFromMetaPath(fileName);
if (fileName.LastIndexOf(".") <= 0)
return fileName;
return Path.GetFileNameWithoutExtension(fileName);
}
static Texture2D CreateRoundedRectTexture(
Vector2 rectSize,
float radius,
Color borderColor,
Color fillColor,
float thickness)
{
int width = (int)rectSize.x;
int height = (int)rectSize.y;
radius = Math.Min(radius, Math.Min(width, height) / 2);
thickness = Math.Min(radius, thickness);
Texture2D result = new Texture2D(width, height, TextureFormat.ARGB32, false);
Color32[] pixels = new Color32[width * height];
double outerRadiusSquared = Math.Pow(radius, 2);
double innerRadiusSquared = Math.Pow(radius - thickness, 2);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int pixelIdx = y * width + x;
double distanceSquared;
if (InCorner(x, y, width, height, radius, out distanceSquared))
{
if (distanceSquared > outerRadiusSquared)
continue;
pixels[pixelIdx] =
distanceSquared >= innerRadiusSquared ?
borderColor : fillColor;
continue;
}
pixels[pixelIdx] =
IsBorder(x, y, width, height, radius, thickness) ?
borderColor : fillColor;
}
}
result.SetPixels32(pixels);
result.Apply();
return result;
}
static bool InCorner(
int x,
int y,
float width,
float height,
float radius,
out double distanceSquared)
{
bool inTop = y < radius;
bool inBottom = y >= height - radius;
bool inLeft = x < radius;
bool inRight = x >= width - radius;
if ((!inTop && !inBottom) || (!inLeft && !inRight))
{
distanceSquared = 0;
return false;
}
float centerX = inLeft ? radius : width - radius - 1;
float centerY = inTop ? radius : height - radius - 1;
float deltaX = x - centerX;
float deltaY = y - centerY;
distanceSquared = Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2);
return true;
}
static bool IsBorder(int x, int y, float width, float height, float radius, float thickness)
{
if (y < thickness && x >= radius && x < width - radius) // top border
return true;
if (y >= height - thickness && x >= radius && x < width - radius) // bottom border
return true;
if (x < thickness && y >= radius && y < height - radius) // left border
return true;
if (x >= width - thickness && y >= radius && y < height - radius) // right border
return true;
return false;
}
const string ELLIPSIS = "...";
}
}