398 lines
11 KiB
C#
398 lines
11 KiB
C#
|
|
using UnityEditor;
|
|||
|
|
using UnityEditor.IMGUI.Controls;
|
|||
|
|
using UnityEngine;
|
|||
|
|
#if UNITY_6000_2_OR_NEWER
|
|||
|
|
using TreeView = UnityEditor.IMGUI.Controls.TreeView<int>;
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
namespace Unity.PlasticSCM.Editor.UI.Tree
|
|||
|
|
{
|
|||
|
|
internal static class DrawTreeViewItem
|
|||
|
|
{
|
|||
|
|
internal enum TextTrimming
|
|||
|
|
{
|
|||
|
|
None,
|
|||
|
|
Path,
|
|||
|
|
}
|
|||
|
|
internal static void InitializeStyles()
|
|||
|
|
{
|
|||
|
|
if (EditorStyles.label == null)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
TreeView.DefaultStyles.label = UnityStyles.Tree.Label;
|
|||
|
|
TreeView.DefaultStyles.boldLabel = UnityStyles.Tree.BoldLabel;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static void ForIndentedItem(
|
|||
|
|
Rect rowRect,
|
|||
|
|
int depth,
|
|||
|
|
string label,
|
|||
|
|
string infoLabel,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused)
|
|||
|
|
{
|
|||
|
|
float indent = GetIndent(depth);
|
|||
|
|
|
|||
|
|
rowRect.x += indent;
|
|||
|
|
rowRect.width -= indent;
|
|||
|
|
|
|||
|
|
//add a little indentation
|
|||
|
|
rowRect.x += 5;
|
|||
|
|
rowRect.width -= 5;
|
|||
|
|
|
|||
|
|
TreeView.DefaultGUI.Label(rowRect, label, isSelected, isFocused);
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrEmpty(infoLabel))
|
|||
|
|
DrawInfolabel(rowRect, label, infoLabel);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static void ForIndentedItemWithIcon(
|
|||
|
|
Rect rowRect,
|
|||
|
|
float rowHeight,
|
|||
|
|
int depth,
|
|||
|
|
string label,
|
|||
|
|
string infoLabel,
|
|||
|
|
Texture icon,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused)
|
|||
|
|
{
|
|||
|
|
float indent = GetIndent(depth);
|
|||
|
|
|
|||
|
|
rowRect.x += indent;
|
|||
|
|
rowRect.width -= indent;
|
|||
|
|
|
|||
|
|
rowRect = DrawIconLeft(
|
|||
|
|
rowRect, rowHeight, icon, null, null);
|
|||
|
|
|
|||
|
|
TreeView.DefaultGUI.Label(rowRect, label, isSelected, isFocused);
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrEmpty(infoLabel))
|
|||
|
|
DrawInfolabel(rowRect, label, infoLabel);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static bool ForCheckableIndentedItem(
|
|||
|
|
Rect rowRect,
|
|||
|
|
int depth,
|
|||
|
|
string label,
|
|||
|
|
string infoLabel,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused,
|
|||
|
|
bool wasChecked,
|
|||
|
|
bool hadCheckedChildren,
|
|||
|
|
bool hadPartiallyCheckedChildren)
|
|||
|
|
{
|
|||
|
|
float indent = GetIndent(depth);
|
|||
|
|
|
|||
|
|
rowRect.x += indent;
|
|||
|
|
rowRect.width -= indent;
|
|||
|
|
|
|||
|
|
Rect checkRect = GetCheckboxRect(rowRect);
|
|||
|
|
|
|||
|
|
if (!wasChecked && (hadCheckedChildren || hadPartiallyCheckedChildren))
|
|||
|
|
EditorGUI.showMixedValue = true;
|
|||
|
|
|
|||
|
|
bool isChecked = EditorGUI.Toggle(checkRect, wasChecked);
|
|||
|
|
EditorGUI.showMixedValue = false;
|
|||
|
|
|
|||
|
|
rowRect.x = checkRect.xMax - 4;
|
|||
|
|
rowRect.width -= checkRect.width;
|
|||
|
|
|
|||
|
|
//add a little indentation
|
|||
|
|
rowRect.x += 5;
|
|||
|
|
rowRect.width -= 5;
|
|||
|
|
|
|||
|
|
TreeView.DefaultGUI.Label(rowRect, label, isSelected, isFocused);
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrEmpty(infoLabel))
|
|||
|
|
DrawInfolabel(rowRect, label, infoLabel);
|
|||
|
|
|
|||
|
|
return isChecked;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static void ForItemCell(
|
|||
|
|
Rect rect,
|
|||
|
|
float rowHeight,
|
|||
|
|
int depth,
|
|||
|
|
Texture icon,
|
|||
|
|
string iconTooltip,
|
|||
|
|
Texture overlayIcon,
|
|||
|
|
string label,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused,
|
|||
|
|
bool isBoldText,
|
|||
|
|
bool isSecondaryLabel,
|
|||
|
|
TextTrimming textTrimming = TextTrimming.None)
|
|||
|
|
{
|
|||
|
|
float indent = GetIndent(depth);
|
|||
|
|
|
|||
|
|
rect.x += indent;
|
|||
|
|
rect.width -= indent;
|
|||
|
|
|
|||
|
|
rect = DrawIconLeft(
|
|||
|
|
rect, rowHeight, icon, iconTooltip, overlayIcon);
|
|||
|
|
|
|||
|
|
if (isSecondaryLabel)
|
|||
|
|
{
|
|||
|
|
ForSecondaryLabel(rect, label, isSelected, isFocused, isBoldText, textTrimming);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ForLabel(rect, label, isSelected, isFocused, isBoldText, textTrimming);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static bool ForCheckableItemCell(
|
|||
|
|
Rect rect,
|
|||
|
|
float rowHeight,
|
|||
|
|
int depth,
|
|||
|
|
Texture icon,
|
|||
|
|
string iconTooltip,
|
|||
|
|
Texture overlayIcon,
|
|||
|
|
string label,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused,
|
|||
|
|
bool isHighlighted,
|
|||
|
|
bool wasChecked,
|
|||
|
|
DrawTreeViewItem.TextTrimming textTrimming = TextTrimming.None)
|
|||
|
|
{
|
|||
|
|
float indent = GetIndent(depth);
|
|||
|
|
|
|||
|
|
rect.x += indent;
|
|||
|
|
rect.width -= indent;
|
|||
|
|
|
|||
|
|
Rect checkRect = GetCheckboxRect(rect);
|
|||
|
|
|
|||
|
|
bool isChecked = EditorGUI.Toggle(checkRect, wasChecked);
|
|||
|
|
|
|||
|
|
rect.x = checkRect.xMax;
|
|||
|
|
rect.width -= checkRect.width;
|
|||
|
|
|
|||
|
|
rect = DrawIconLeft(
|
|||
|
|
rect, rowHeight, icon, iconTooltip, overlayIcon);
|
|||
|
|
|
|||
|
|
GUIStyle style = isHighlighted ?
|
|||
|
|
UnityStyles.Tree.BoldLabel :
|
|||
|
|
UnityStyles.Tree.Label;
|
|||
|
|
|
|||
|
|
if (Event.current.type != UnityEngine.EventType.Repaint)
|
|||
|
|
return isChecked;
|
|||
|
|
|
|||
|
|
GUIContent content = GetGUIContent(label, style, rect, textTrimming);
|
|||
|
|
|
|||
|
|
DrawLabel(
|
|||
|
|
content,
|
|||
|
|
style,
|
|||
|
|
rect,
|
|||
|
|
false,
|
|||
|
|
true,
|
|||
|
|
isSelected,
|
|||
|
|
isFocused);
|
|||
|
|
|
|||
|
|
return isChecked;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static Rect DrawIconLeft(
|
|||
|
|
Rect rect,
|
|||
|
|
float rowHeight,
|
|||
|
|
Texture icon,
|
|||
|
|
string iconTooltip,
|
|||
|
|
Texture overlayIcon)
|
|||
|
|
{
|
|||
|
|
if (icon == null)
|
|||
|
|
return rect;
|
|||
|
|
|
|||
|
|
float iconWidth = UnityConstants.TREEVIEW_ICON_SIZE * ((float)icon.width / icon.height);;
|
|||
|
|
|
|||
|
|
Rect iconRect = new Rect(rect.x, rect.y, iconWidth, rowHeight);
|
|||
|
|
|
|||
|
|
EditorGUI.LabelField(iconRect, new GUIContent(icon, iconTooltip), UnityStyles.Tree.IconStyle);
|
|||
|
|
|
|||
|
|
if (overlayIcon != null)
|
|||
|
|
{
|
|||
|
|
Rect overlayIconRect = GetOverlayRect.ForPendingChanges(iconRect);
|
|||
|
|
|
|||
|
|
GUI.DrawTexture(
|
|||
|
|
overlayIconRect, overlayIcon,
|
|||
|
|
ScaleMode.ScaleToFit);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
rect.x += iconRect.width;
|
|||
|
|
rect.width -= iconRect.width;
|
|||
|
|
|
|||
|
|
return rect;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void DrawInfolabel(
|
|||
|
|
Rect rect,
|
|||
|
|
string label,
|
|||
|
|
string infoLabel)
|
|||
|
|
{
|
|||
|
|
Vector2 labelSize = ((GUIStyle)UnityStyles.Tree.Label)
|
|||
|
|
.CalcSize(new GUIContent(label));
|
|||
|
|
|
|||
|
|
rect.x += labelSize.x;
|
|||
|
|
|
|||
|
|
GUI.Label(rect, infoLabel, UnityStyles.Tree.InfoLabel);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static Rect GetCheckboxRect(Rect rect)
|
|||
|
|
{
|
|||
|
|
return new Rect(
|
|||
|
|
rect.x,
|
|||
|
|
rect.y + UnityConstants.TREEVIEW_CHECKBOX_Y_OFFSET,
|
|||
|
|
UnityConstants.TREEVIEW_CHECKBOX_SIZE,
|
|||
|
|
rect.height);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static float GetIndent(int depth)
|
|||
|
|
{
|
|||
|
|
return 16 * (depth + 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static void ForSecondaryLabelRightAligned(
|
|||
|
|
Rect rect,
|
|||
|
|
string label,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused,
|
|||
|
|
bool isBoldText,
|
|||
|
|
TextTrimming textTrimming = TextTrimming.None)
|
|||
|
|
{
|
|||
|
|
if (Event.current.type != EventType.Repaint)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
GUIStyle style = isBoldText ?
|
|||
|
|
UnityStyles.Tree.SecondaryLabelBoldRightAligned :
|
|||
|
|
UnityStyles.Tree.SecondaryLabelRightAligned;
|
|||
|
|
GUIContent content = GetGUIContent(label, style, rect, textTrimming);
|
|||
|
|
|
|||
|
|
DrawLabel(
|
|||
|
|
content,
|
|||
|
|
style,
|
|||
|
|
rect,
|
|||
|
|
false,
|
|||
|
|
true,
|
|||
|
|
isSelected,
|
|||
|
|
isFocused);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static void ForSecondaryLabel(
|
|||
|
|
Rect rect,
|
|||
|
|
string label,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused,
|
|||
|
|
bool isBoldText,
|
|||
|
|
TextTrimming textTrimming = TextTrimming.None)
|
|||
|
|
{
|
|||
|
|
if (Event.current.type != EventType.Repaint)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
GUIStyle style = isBoldText ?
|
|||
|
|
UnityStyles.Tree.SecondaryBoldLabel :
|
|||
|
|
UnityStyles.Tree.SecondaryLabel;
|
|||
|
|
|
|||
|
|
if (isBoldText)
|
|||
|
|
style.normal.textColor = Color.red;
|
|||
|
|
|
|||
|
|
GUIContent content = GetGUIContent(label, style, rect, textTrimming);
|
|||
|
|
|
|||
|
|
DrawLabel(
|
|||
|
|
content,
|
|||
|
|
style,
|
|||
|
|
rect,
|
|||
|
|
false,
|
|||
|
|
true,
|
|||
|
|
isSelected,
|
|||
|
|
isFocused);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static void ForLabel(
|
|||
|
|
Rect rect,
|
|||
|
|
GUIContent content,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused,
|
|||
|
|
bool isBoldText)
|
|||
|
|
{
|
|||
|
|
if (Event.current.type != EventType.Repaint)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
GUIStyle style = isBoldText ? UnityStyles.Tree.BoldLabel: UnityStyles.Tree.Label;
|
|||
|
|
|
|||
|
|
DrawLabel(
|
|||
|
|
content,
|
|||
|
|
style,
|
|||
|
|
rect,
|
|||
|
|
false,
|
|||
|
|
true,
|
|||
|
|
isSelected,
|
|||
|
|
isFocused);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
internal static void ForLabel(
|
|||
|
|
Rect rect,
|
|||
|
|
string label,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused,
|
|||
|
|
bool isBoldText,
|
|||
|
|
TextTrimming textTrimming = TextTrimming.None)
|
|||
|
|
{
|
|||
|
|
if (Event.current.type != EventType.Repaint)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
label = TruncateLabelIfNeeded(label);
|
|||
|
|
|
|||
|
|
GUIStyle style = isBoldText ? UnityStyles.Tree.BoldLabel: UnityStyles.Tree.Label;
|
|||
|
|
GUIContent content = GetGUIContent(label, style, rect, textTrimming);
|
|||
|
|
|
|||
|
|
DrawLabel(
|
|||
|
|
content,
|
|||
|
|
style,
|
|||
|
|
rect,
|
|||
|
|
false,
|
|||
|
|
true,
|
|||
|
|
isSelected,
|
|||
|
|
isFocused);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void DrawLabel(
|
|||
|
|
GUIContent content,
|
|||
|
|
GUIStyle style,
|
|||
|
|
Rect rect,
|
|||
|
|
bool isHover,
|
|||
|
|
bool isActive,
|
|||
|
|
bool isSelected,
|
|||
|
|
bool isFocused)
|
|||
|
|
{
|
|||
|
|
style.Draw(
|
|||
|
|
rect, content, isHover, isActive, isSelected, isFocused);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static GUIContent GetGUIContent(string label, GUIStyle style, Rect rect, TextTrimming textTrimming)
|
|||
|
|
{
|
|||
|
|
if (textTrimming == TextTrimming.Path)
|
|||
|
|
{
|
|||
|
|
string truncatedLabel = PathTrimming.TruncatePath(
|
|||
|
|
label,
|
|||
|
|
rect.width,
|
|||
|
|
CalcTextSize.FromStyle(style),
|
|||
|
|
out var wasTrimmed);
|
|||
|
|
|
|||
|
|
return new GUIContent(truncatedLabel, wasTrimmed ? label : null);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new GUIContent(label);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static string TruncateLabelIfNeeded(string label)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(label))
|
|||
|
|
return label;
|
|||
|
|
|
|||
|
|
if (label.Length <= MAX_LABEL_LENGTH)
|
|||
|
|
return label;
|
|||
|
|
|
|||
|
|
return label.Substring(0, MAX_LABEL_LENGTH) + "...";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const int MAX_LABEL_LENGTH = 1024;
|
|||
|
|
}
|
|||
|
|
}
|