863 lines
32 KiB
C#
863 lines
32 KiB
C#
#if ENABLE_UIELEMENTS_MODULE && UNITY_ENABLE_CHECKS
|
|
#define ENABLE_RENDERING_DEBUGGER_UI
|
|
#endif
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
|
|
#endif
|
|
#if ENABLE_RENDERING_DEBUGGER_UI
|
|
using UnityEngine.UIElements;
|
|
#endif
|
|
|
|
namespace UnityEngine.Rendering
|
|
{
|
|
public partial class DebugUI
|
|
{
|
|
/// <summary>
|
|
/// Base class for "container" type widgets, although it can be used on its own (if a display name is set then it'll behave as a group with a header)
|
|
/// </summary>
|
|
public class Container : Widget, IContainer
|
|
{
|
|
#if ENABLE_RENDERING_DEBUGGER_UI
|
|
/// <inheritdoc/>
|
|
protected override VisualElement Create()
|
|
{
|
|
VisualElement container = new UIElements.VisualElement();
|
|
container.AddToClassList("debug-window-container");
|
|
if (!hideDisplayName)
|
|
{
|
|
var label = new Label(displayName);
|
|
label.AddToClassList("debug-window-container-displayname");
|
|
label.AddToClassList("debug-window-search-filter-target");
|
|
container.Add(label);
|
|
}
|
|
|
|
var content = new VisualElement();
|
|
content.AddToClassList("debug-window-container-content");
|
|
AddChildren(content, m_Context);
|
|
container.Add(content);
|
|
|
|
return container;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds all the children to the given container
|
|
/// </summary>
|
|
/// <param name="container">The container to insert elements</param>
|
|
/// <param name="context">The context where the widget is being added</param>
|
|
protected void AddChildren(VisualElement container, DebugUI.Context context)
|
|
{
|
|
for (int i = 0; i < children.Count; ++i)
|
|
{
|
|
var child = children[i];
|
|
|
|
if (context == Context.Editor && child.isRuntimeOnly)
|
|
continue;
|
|
if (context.IsAnyRuntimeContext() && child.isEditorOnly)
|
|
continue;
|
|
|
|
var childUIElement = child.ToVisualElement(context);
|
|
if (childUIElement != null)
|
|
container.Add(childUIElement);
|
|
}
|
|
|
|
// As the elements might change visibility, we need to update alternating background colors
|
|
if (alternateRowColors)
|
|
{
|
|
this.ScheduleTracked(container, () => container.schedule.Execute(() =>
|
|
{
|
|
int i = 0;
|
|
foreach (var child in container.Children())
|
|
{
|
|
if (child.style.display == DisplayStyle.Flex)
|
|
{
|
|
if (i % 2 != 0)
|
|
child.AddToClassList(k_AlternateRowColorClassName);
|
|
else
|
|
child.RemoveFromClassList(k_AlternateRowColorClassName);
|
|
|
|
++i;
|
|
}
|
|
}
|
|
}).Every(100));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
const string k_IDToken = "#";
|
|
internal bool hideDisplayName => string.IsNullOrEmpty(displayName) || displayName.StartsWith(k_IDToken);
|
|
|
|
/// <summary>
|
|
/// List of children.
|
|
/// </summary>
|
|
public ObservableList<Widget> children { get; private set; }
|
|
|
|
const string k_AlternateRowColorClassName = "debug-window-row-alternate";
|
|
|
|
/// <summary>
|
|
/// Set to true to alternate background colors of the rows inside the container.
|
|
/// </summary>
|
|
public bool alternateRowColors { get; set; }
|
|
|
|
/// <summary>
|
|
/// Panel the container is attached to.
|
|
/// </summary>
|
|
public override Panel panel
|
|
{
|
|
get { return m_Panel; }
|
|
internal set
|
|
{
|
|
m_Panel = value;
|
|
|
|
// Bubble down
|
|
int numChildren = children.Count;
|
|
for (int i = 0; i < numChildren; i++)
|
|
children[i].panel = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
public Container()
|
|
: this(string.Empty, new ObservableList<Widget>())
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor for a container without header
|
|
/// </summary>
|
|
/// <param name="id">The id of the container</param>
|
|
public Container(string id)
|
|
: this($"{k_IDToken}{id}", new ObservableList<Widget>())
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor.
|
|
/// </summary>
|
|
/// <param name="displayName">Display name of the container.</param>
|
|
/// <param name="children">List of attached children.</param>
|
|
public Container(string displayName, ObservableList<Widget> children)
|
|
{
|
|
this.displayName = displayName;
|
|
this.children = children;
|
|
children.ItemAdded += OnItemAdded;
|
|
children.ItemRemoved += OnItemRemoved;
|
|
|
|
// Call OnAdded callback for already existing items to ensure their panel & parent are set
|
|
for (int i = 0; i < this.children.Count; i++)
|
|
OnItemAdded(this.children, new ListChangedEventArgs<Widget>(i, this.children[i]));
|
|
}
|
|
|
|
internal override void GenerateQueryPath()
|
|
{
|
|
base.GenerateQueryPath();
|
|
|
|
int numChildren = children.Count;
|
|
for (int i = 0; i < numChildren; i++)
|
|
children[i].GenerateQueryPath();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Method called when a children is added.
|
|
/// </summary>
|
|
/// <param name="sender">Sender widget.</param>
|
|
/// <param name="e">List of added children.</param>
|
|
protected virtual void OnItemAdded(ObservableList<Widget> sender, ListChangedEventArgs<Widget> e)
|
|
{
|
|
if (e.item != null)
|
|
{
|
|
e.item.panel = m_Panel;
|
|
e.item.parent = this;
|
|
}
|
|
|
|
if (m_Panel != null)
|
|
m_Panel.SetDirty();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Method called when a children is removed.
|
|
/// </summary>
|
|
/// <param name="sender">Sender widget.</param>
|
|
/// <param name="e">List of removed children.</param>
|
|
protected virtual void OnItemRemoved(ObservableList<Widget> sender, ListChangedEventArgs<Widget> e)
|
|
{
|
|
if (e.item != null)
|
|
{
|
|
e.item.panel = null;
|
|
e.item.parent = null;
|
|
}
|
|
|
|
if (m_Panel != null)
|
|
m_Panel.SetDirty();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unity-like foldout that can be collapsed.
|
|
/// </summary>
|
|
public class Foldout : Container
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
, IValueField
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
{
|
|
|
|
#if ENABLE_RENDERING_DEBUGGER_UI
|
|
|
|
/// <inheritdoc/>
|
|
protected override VisualElement Create()
|
|
{
|
|
var container = new UIElements.Foldout { text = displayName };
|
|
if (m_Context == Context.Editor && (contextMenuItems != null || !string.IsNullOrEmpty(documentationUrl)))
|
|
{
|
|
#if UNITY_EDITOR
|
|
// Get Toggle element of the Foldout to be able to attach the help and menu buttons
|
|
var toggleHeader = container.Q<Toggle>().ElementAt(0);
|
|
if (!string.IsNullOrEmpty(documentationUrl))
|
|
{
|
|
var infoButton = new UIElements.Button((Background.FromTexture2D((Texture2D)EditorGUIUtility.TrIconContent("_Help").image )),() => Help.BrowseURL(documentationUrl));
|
|
infoButton.AddToClassList("info-button");
|
|
infoButton.tooltip = $"Open Reference for {displayName}.";
|
|
toggleHeader.Add(infoButton);
|
|
}
|
|
if (contextMenuItems != null)
|
|
{
|
|
var button = new UIElements.Button();
|
|
button.AddToClassList("more-options-button");
|
|
|
|
var contextualMenu = new GenericDropdownMenu();
|
|
foreach(var item in contextMenuItems)
|
|
{
|
|
contextualMenu.AddItem(item.displayName, false, item.action );
|
|
}
|
|
|
|
button.clicked += () =>
|
|
{
|
|
contextualMenu.DropDown(button.worldBound, button, DropdownMenuSizeMode.Auto);
|
|
};
|
|
|
|
toggleHeader.Add(button);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Add special classes for styles
|
|
// Use header style for top-level foldouts (not inside a Container), regular style for nested ones
|
|
bool isHeaderFoldout = parent is DebugUI.Panel;
|
|
container.AddToClassList(isHeaderFoldout ? "debug-window-foldout-header" : "debug-window-foldout");
|
|
container.Q(className: "unity-foldout__text").AddToClassList("debug-window-search-filter-target");
|
|
|
|
// Update UI to match object's initial state
|
|
container.SetValueWithoutNotify(GetValue());
|
|
|
|
// Sync value to object when changed in UI
|
|
container.RegisterCallback<ChangeEvent<bool>>(evt =>
|
|
{
|
|
SetValue(container.value);
|
|
});
|
|
// Sync value to object based on navigation events separately, because they don't trigger a ChangeEvent
|
|
container.RegisterCallback<NavigationMoveEvent>(evt =>
|
|
{
|
|
if (DebugManager.instance.selectedWidget == this)
|
|
{
|
|
if (evt.direction == NavigationMoveEvent.Direction.Right)
|
|
SetValue(true);
|
|
else if (evt.direction == NavigationMoveEvent.Direction.Left)
|
|
SetValue(false);
|
|
}
|
|
}, TrickleDown.TrickleDown); // Foldout internally stops propagation so must use TrickleDown to see it
|
|
|
|
// Sync opened state from object to UI
|
|
this.ScheduleTracked(container, () => container.schedule.Execute(() =>
|
|
{
|
|
container.SetValueWithoutNotify(GetValue());
|
|
}).Every(100));
|
|
|
|
if (columnLabels is { Length: > 0 })
|
|
{
|
|
var columnLabelsValues = new DebugUI.Value[columnLabels.Length];
|
|
|
|
for (int i = 0; i < columnLabels.Length; i++)
|
|
{
|
|
string value = columnLabels[i];
|
|
object Getter() => value;
|
|
columnLabelsValues[i] = new DebugUI.Value()
|
|
{
|
|
displayName = string.Empty,
|
|
getter = Getter
|
|
};
|
|
}
|
|
|
|
var header = new DebugUI.ValueTuple()
|
|
{
|
|
displayName = string.Empty,
|
|
isHeader = true,
|
|
values = columnLabelsValues
|
|
};
|
|
|
|
container.Add(header.ToVisualElement(m_Context));
|
|
|
|
container.RegisterCallback<GeometryChangedEvent>(evt =>
|
|
{
|
|
var numColumns = columnLabels.Length;
|
|
foreach (var visualElement in container.Children())
|
|
{
|
|
var width = (evt.newRect.width - ValueTuple.GetLabelWidth(m_Context)) / numColumns;
|
|
int i = 0;
|
|
foreach (var child in visualElement.Children())
|
|
{
|
|
if (i != 0)
|
|
child.style.width = width;
|
|
|
|
++i;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
AddChildren(container, m_Context);
|
|
|
|
return container;
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Context menu item.
|
|
/// </summary>
|
|
public struct ContextMenuItem
|
|
{
|
|
/// <summary>
|
|
/// Name of the item displayed in context menu dropdown.
|
|
/// </summary>
|
|
public string displayName;
|
|
|
|
/// <summary>
|
|
/// Callback when context menu item is selected.
|
|
/// </summary>
|
|
public Action action;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Always false.
|
|
/// </summary>
|
|
public bool isReadOnly { get { return false; } }
|
|
|
|
bool m_Opened;
|
|
|
|
/// <summary>
|
|
/// Opened state of the foldout.
|
|
/// </summary>
|
|
public bool opened
|
|
{
|
|
get => m_Opened;
|
|
set
|
|
{
|
|
if (opened != value)
|
|
{
|
|
#if ENABLE_RENDERING_DEBUGGER_UI
|
|
if (m_VisualElement != null)
|
|
DebugManager.instance.schedulerTracker.SetHierarchyEnabled(m_Context, this, value);
|
|
|
|
#endif
|
|
m_Opened = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw the foldout in full width using a header style.
|
|
/// </summary>
|
|
public bool isHeader;
|
|
|
|
/// <summary>
|
|
/// Optional list of context menu items. If the list is not provided, no context menu button will be displayed.
|
|
/// </summary>
|
|
public List<ContextMenuItem> contextMenuItems = null;
|
|
|
|
/// <summary>
|
|
/// Optional help URL for the editor UI
|
|
/// </summary>
|
|
public string documentationUrl { get; set; }
|
|
|
|
private bool m_Dirty;
|
|
private string[] m_ColumnLabels;
|
|
private string[] m_ColumnTooltips;
|
|
|
|
/// <summary>
|
|
/// List of columns labels.
|
|
/// </summary>
|
|
public string[] columnLabels
|
|
{
|
|
get => m_ColumnLabels;
|
|
set
|
|
{
|
|
m_ColumnLabels = value;
|
|
m_Dirty = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// List of columns label tooltips.
|
|
/// </summary>
|
|
public string[] columnTooltips
|
|
{
|
|
get => m_ColumnTooltips;
|
|
set
|
|
{
|
|
m_ColumnTooltips = value;
|
|
m_Dirty = true;
|
|
}
|
|
}
|
|
|
|
private List<GUIContent> m_RowContents = new();
|
|
internal List<GUIContent> rowContents
|
|
{
|
|
get
|
|
{
|
|
if (m_Dirty)
|
|
{
|
|
if (m_ColumnTooltips == null)
|
|
{
|
|
m_ColumnTooltips = new string[m_ColumnLabels.Length];
|
|
Array.Fill(columnTooltips, string.Empty);
|
|
}
|
|
else
|
|
{
|
|
if (m_ColumnTooltips.Length != m_ColumnLabels.Length)
|
|
throw new Exception(
|
|
$"Dimension for labels and tooltips on {nameof(DebugUI.Foldout)} - {displayName}, do not match");
|
|
}
|
|
|
|
m_RowContents.Clear();
|
|
for (int i = 0; i < m_ColumnLabels.Length; ++i)
|
|
{
|
|
string label = columnLabels[i] ?? string.Empty;
|
|
string tooltip = m_ColumnTooltips[i] ?? string.Empty;
|
|
m_RowContents.Add(
|
|
#if UNITY_EDITOR
|
|
EditorGUIUtility.TrTextContent(label, tooltip)
|
|
#else
|
|
new GUIContent(label, tooltip)
|
|
#endif
|
|
);
|
|
}
|
|
|
|
m_Dirty = false;
|
|
}
|
|
|
|
return m_RowContents;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor.
|
|
/// </summary>
|
|
public Foldout() : base() { }
|
|
/// <summary>
|
|
/// Constructor.
|
|
/// </summary>
|
|
/// <param name="displayName">Display name of the foldout.</param>
|
|
/// <param name="children">List of attached children.</param>
|
|
/// <param name="columnLabels">Optional list of column names.</param>
|
|
/// <param name="columnTooltips">Optional list of tooltips for column name labels.</param>
|
|
public Foldout(string displayName, ObservableList<Widget> children, string[] columnLabels = null, string[] columnTooltips = null)
|
|
: base(displayName, children)
|
|
{
|
|
this.columnLabels = columnLabels;
|
|
this.columnTooltips = columnTooltips;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the opened state of the foldout.
|
|
/// </summary>
|
|
/// <returns>True if the foldout is opened.</returns>
|
|
public bool GetValue() => opened;
|
|
|
|
/// <summary>
|
|
/// Get the opened state of the foldout.
|
|
/// </summary>
|
|
/// <returns>True if the foldout is opened.</returns>
|
|
object IValueField.GetValue() => GetValue();
|
|
|
|
/// <summary>
|
|
/// Set the opened state of the foldout.
|
|
/// </summary>
|
|
/// <param name="value">True to open the foldout, false to close it.</param>
|
|
[Obsolete("This method is no longer used. #from(6000.5)")]
|
|
public void SetValue(object value) => SetValue((bool)value);
|
|
|
|
/// <summary>
|
|
/// Validates the value of the widget before setting it.
|
|
/// </summary>
|
|
/// <param name="value">Input value.</param>
|
|
/// <returns>The validated value.</returns>
|
|
[Obsolete("This method is no longer used. #from(6000.5)")]
|
|
public object ValidateValue(object value) => value;
|
|
|
|
/// <summary>
|
|
/// Set the value of the widget.
|
|
/// </summary>
|
|
/// <param name="value">Input value.</param>
|
|
public void SetValue(bool value) => opened = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Horizontal Layout Container.
|
|
/// </summary>
|
|
public class HBox : Container
|
|
{
|
|
/// <summary>
|
|
/// Constructor.
|
|
/// </summary>
|
|
public HBox()
|
|
{
|
|
displayName = "HBox";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Vertical Layout Container.
|
|
/// </summary>
|
|
public class VBox : Container
|
|
{
|
|
/// <summary>
|
|
/// Constructor.
|
|
/// </summary>
|
|
public VBox()
|
|
{
|
|
displayName = "VBox";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Array Container.
|
|
/// </summary>
|
|
public class Table : Container
|
|
{
|
|
#if ENABLE_RENDERING_DEBUGGER_UI
|
|
/// <inheritdoc/>
|
|
protected override VisualElement Create()
|
|
{
|
|
var container = new UIElements.VisualElement();
|
|
container.AddToClassList("debug-window-table");
|
|
|
|
using (ListPool<string>.Get(out var tmp))
|
|
{
|
|
if (children.Count != 0 && children[0] is Row row)
|
|
{
|
|
foreach (var child in row.children)
|
|
tmp.Add(child.displayName);
|
|
}
|
|
|
|
var columnLabelsValues = new DebugUI.Value[tmp.Count];
|
|
for (int i = 0; i < columnLabelsValues.Length; i++)
|
|
{
|
|
string value = tmp[i];
|
|
object Getter() => value;
|
|
columnLabelsValues[i] = new DebugUI.Value()
|
|
{
|
|
displayName = string.Empty,
|
|
getter = Getter
|
|
};
|
|
}
|
|
|
|
var header = new DebugUI.ValueTuple()
|
|
{
|
|
displayName = string.Empty,
|
|
isHeader = true,
|
|
values = columnLabelsValues
|
|
};
|
|
|
|
var headerVisualElement = header.ToVisualElement(m_Context);
|
|
headerVisualElement.AddToClassList("debug-window-table-header-row");
|
|
|
|
foreach (var headerElement in headerVisualElement.Children())
|
|
headerElement.AddToClassList("debug-window-table-header-cell");
|
|
|
|
container.Add(headerVisualElement);
|
|
|
|
// NOTE: Current implementation constructs the table cells from individual elements, so cell width needs to be
|
|
// set manually like this. This is necessary because of the DebugUI.Table/Row structure, which is why we can't use
|
|
// a proper table.
|
|
container.RegisterCallback<GeometryChangedEvent>(evt =>
|
|
{
|
|
var numColumns = columnLabelsValues.Length;
|
|
var availableWidth = evt.newRect.width;
|
|
if (displayRowNames)
|
|
availableWidth -= ValueTuple.GetLabelWidth(m_Context);
|
|
var width = availableWidth / numColumns;
|
|
|
|
foreach (var visualElement in container.Children())
|
|
{
|
|
int i = 0;
|
|
foreach (var child in visualElement.Children())
|
|
{
|
|
if (i == 0)
|
|
child.style.display = displayRowNames ? DisplayStyle.Flex : DisplayStyle.None;
|
|
else
|
|
{
|
|
child.style.width = width;
|
|
child.style.display = DisplayStyle.Flex;
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
AddChildren(container, m_Context);
|
|
|
|
container.enabledSelf = !isReadOnly;
|
|
|
|
return container;
|
|
}
|
|
#endif
|
|
|
|
/// <summary>Row Container.</summary>
|
|
public class Row : Container
|
|
{
|
|
/// <summary>Constructor.</summary>
|
|
public Row() { displayName = "Row"; }
|
|
|
|
/// <summary>Opened state of the row. No longer used.</summary>
|
|
[Obsolete("This class no longer inherits from Foldout, but from Container. This field is kept for compatibility but it no longer does anything. #from(6000.5)")]
|
|
public bool opened { get; set; }
|
|
|
|
#if ENABLE_RENDERING_DEBUGGER_UI
|
|
/// <inheritdoc/>
|
|
protected override VisualElement Create()
|
|
{
|
|
var rowContainer = new UIElements.VisualElement();
|
|
rowContainer.AddToClassList("debug-window-table-row");
|
|
|
|
var label = new Label(displayName) { style = { width = ValueTuple.GetLabelWidth(m_Context) }, };
|
|
label.AddToClassList("debug-window-table-row-displayname");
|
|
label.AddToClassList("debug-window-search-filter-target");
|
|
rowContainer.Add(label);
|
|
|
|
foreach (var c in children)
|
|
{
|
|
c.keepLayoutWhenHidden = true;
|
|
var rowElement = c.ToVisualElement(m_Context);
|
|
rowElement.AddToClassList("debug-window-table-cell");
|
|
|
|
// In Table layout we don't want to show the labels of DebugUI.Values
|
|
var valueLabel = rowElement.Q<Label>(className: "debug-window-value-name");
|
|
if (valueLabel != null)
|
|
valueLabel.style.display = DisplayStyle.None;
|
|
|
|
rowContainer.Add(rowElement);
|
|
}
|
|
|
|
return rowContainer;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the table is read only.
|
|
/// </summary>
|
|
public bool isReadOnly = false;
|
|
|
|
/// <summary>
|
|
/// Set to false to hide the first column containing the row names
|
|
/// </summary>
|
|
public bool displayRowNames = true;
|
|
|
|
/// <summary>Constructor.</summary>
|
|
public Table() { displayName = "Array"; }
|
|
|
|
/// <summary>
|
|
/// Set column visibility.
|
|
/// </summary>
|
|
/// <param name="index">Index of the column.</param>
|
|
/// <param name="visible">True if the column should be visible.</param>
|
|
[Obsolete("This method is no longer used. #from(6000.5)")]
|
|
public void SetColumnVisibility(int index, bool visible)
|
|
{
|
|
#if UNITY_EDITOR
|
|
var header = Header;
|
|
if (index < 0 || index >= m_ColumnCount)
|
|
return;
|
|
|
|
index++;
|
|
if (header.IsColumnVisible(index) != visible)
|
|
{
|
|
var newVisibleColumns = new System.Collections.Generic.List<int>(header.state.visibleColumns);
|
|
if (newVisibleColumns.Contains(index))
|
|
{
|
|
newVisibleColumns.Remove(index);
|
|
}
|
|
else
|
|
{
|
|
newVisibleColumns.Add(index);
|
|
newVisibleColumns.Sort();
|
|
}
|
|
header.state.visibleColumns = newVisibleColumns.ToArray();
|
|
|
|
var cols = header.state.columns;
|
|
for (int i = 0; i < cols.Length; i++)
|
|
cols[i].width = 50f;
|
|
header.ResizeToFit();
|
|
}
|
|
#else
|
|
var columns = VisibleColumns;
|
|
if (index < 0 || index > columns.Length)
|
|
return;
|
|
|
|
columns[index] = visible;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get column visibility.
|
|
/// </summary>
|
|
/// <param name="index">Index of the column.</param>
|
|
/// <returns>True if the column is visible.</returns>
|
|
[Obsolete("This method is no longer used. #from(6000.5)")]
|
|
public bool GetColumnVisibility(int index)
|
|
{
|
|
#if UNITY_EDITOR
|
|
var header = Header;
|
|
if (index < 0 || index >= m_ColumnCount)
|
|
return false;
|
|
|
|
return header.IsColumnVisible(index + 1);
|
|
#else
|
|
var columns = VisibleColumns;
|
|
if (index < 0 || index > columns.Length)
|
|
return false;
|
|
|
|
return columns[index];
|
|
#endif
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
/// <summary>
|
|
/// The scroll position of the table.
|
|
/// </summary>
|
|
[Obsolete("This property is no longer used. #from(6000.5)")]
|
|
public Vector2 scroll = Vector2.zero;
|
|
|
|
int m_ColumnCount;
|
|
UnityEditor.IMGUI.Controls.MultiColumnHeader m_Header = null;
|
|
|
|
/// <summary>
|
|
/// The table header for drawing
|
|
/// </summary>
|
|
[Obsolete("This property is no longer used. #from(6000.5)")]
|
|
public UnityEditor.IMGUI.Controls.MultiColumnHeader Header
|
|
{
|
|
get
|
|
{
|
|
if (m_Header != null)
|
|
return m_Header;
|
|
|
|
if (children.Count != 0)
|
|
{
|
|
m_ColumnCount = ((Container)children[0]).children.Count;
|
|
for (int i = 1; i < children.Count; i++)
|
|
{
|
|
if (((Container)children[i]).children.Count != m_ColumnCount)
|
|
{
|
|
Debug.LogError("All rows must have the same number of children.");
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
UnityEditor.IMGUI.Controls.MultiColumnHeaderState.Column CreateColumn(string name, string tooltip)
|
|
{
|
|
var col = new UnityEditor.IMGUI.Controls.MultiColumnHeaderState.Column()
|
|
{
|
|
canSort = false,
|
|
headerTextAlignment = TextAlignment.Center,
|
|
headerContent = new GUIContent(name, tooltip ?? string.Empty)
|
|
};
|
|
|
|
//columnHeaderStyle.CalcMinMaxWidth(col.headerContent, out col.width, out float _);
|
|
col.width = Mathf.Min(col.width, 50f);
|
|
return col;
|
|
}
|
|
|
|
var cols = new UnityEditor.IMGUI.Controls.MultiColumnHeaderState.Column[m_ColumnCount + 1];
|
|
cols[0] = CreateColumn(displayName, tooltip);
|
|
cols[0].allowToggleVisibility = false;
|
|
for (int i = 0; i < m_ColumnCount; i++)
|
|
{
|
|
var elem = ((Container) children[0]).children[i];
|
|
cols[i + 1] = CreateColumn(elem.displayName, elem.tooltip);
|
|
}
|
|
|
|
var state = new UnityEditor.IMGUI.Controls.MultiColumnHeaderState(cols);
|
|
m_Header = new UnityEditor.IMGUI.Controls.MultiColumnHeader(state) { height = 23 };
|
|
m_Header.ResizeToFit();
|
|
return m_Header;
|
|
}
|
|
}
|
|
#else
|
|
bool[] m_Header = null;
|
|
|
|
/// <summary>
|
|
/// The visible columns
|
|
/// </summary>
|
|
[Obsolete("This property is no longer used. #from(6000.5)")]
|
|
public bool[] VisibleColumns
|
|
{
|
|
get
|
|
{
|
|
if (m_Header != null)
|
|
return m_Header;
|
|
|
|
int columnCount = 0;
|
|
if (children.Count != 0)
|
|
{
|
|
columnCount = ((Container)children[0]).children.Count;
|
|
for (int i = 1; i < children.Count; i++)
|
|
{
|
|
if (((Container)children[i]).children.Count != columnCount)
|
|
{
|
|
Debug.LogError("All rows must have the same number of children.");
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_Header = new bool[columnCount];
|
|
for (int i = 0; i < columnCount; i++)
|
|
m_Header[i] = true;
|
|
|
|
return m_Header;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Method called when a children is added.
|
|
/// </summary>
|
|
/// <param name="sender">Sender widget.</param>
|
|
/// <param name="e">List of added children.</param>
|
|
protected override void OnItemAdded(ObservableList<Widget> sender, ListChangedEventArgs<Widget> e)
|
|
{
|
|
base.OnItemAdded(sender, e);
|
|
m_Header = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Method called when a children is removed.
|
|
/// </summary>
|
|
/// <param name="sender">Sender widget.</param>
|
|
/// <param name="e">List of removed children.</param>
|
|
protected override void OnItemRemoved(ObservableList<Widget> sender, ListChangedEventArgs<Widget> e)
|
|
{
|
|
base.OnItemRemoved(sender, e);
|
|
m_Header = null;
|
|
}
|
|
}
|
|
}
|
|
}
|