SignalReceiverTreeView.cs 5.48 KB
using System;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using UnityEngine.Timeline;

namespace UnityEditor.Timeline.Signals
{
    class SignalReceiverTreeView : TreeView
    {
        public bool dirty { private get; set; }

        SerializedProperty signals { get; set; }
        SerializedProperty events { get; set; }

        readonly SignalReceiver m_Target;

        const float k_VerticalPadding = 5;
        const float k_HorizontalPadding = 5;

        public SignalReceiverTreeView(TreeViewState state, MultiColumnHeader multiColumnHeader, SignalReceiver receiver, SerializedObject serializedObject)
            : base(state, multiColumnHeader)
        {
            m_Target = receiver;
            useScrollView = true;
            SetSerializedProperties(serializedObject);
            getNewSelectionOverride = (item, selection, shift) => new List<int>(); // Disable Selection
        }

        SignalAsset signalAssetContext { get; set; }
        public bool readonlySignals { get; set; }

        public void SetSignalContext(SignalAsset assetContext = null)
        {
            signalAssetContext = assetContext;
            dirty = true;
        }

        void SetSerializedProperties(SerializedObject serializedObject)
        {
            signals = SignalReceiverUtility.FindSignalsProperty(serializedObject);
            events = SignalReceiverUtility.FindEventsProperty(serializedObject);
            Reload();
        }

        public void Draw()
        {
            var rect = EditorGUILayout.GetControlRect(true, GetTotalHeight());
            OnGUI(rect);
        }

        public void RefreshIfDirty()
        {
            var signalsListSizeHasChanged = signals.arraySize != GetRows().Count;
            if (dirty || signalsListSizeHasChanged)
                Reload();
            dirty = false;
        }

        public static MultiColumnHeaderState.Column[] GetColumns()
        {
            return new[]
            {
                new MultiColumnHeaderState.Column
                {
                    headerContent = EditorGUIUtility.TrTextContent("Signal"),
                    contextMenuText = "",
                    headerTextAlignment = TextAlignment.Center,
                    width = 50, minWidth = 50,
                    autoResize = true,
                    allowToggleVisibility = false,
                    canSort = false
                },
                new MultiColumnHeaderState.Column
                {
                    headerContent = EditorGUIUtility.TrTextContent("Reaction"),
                    contextMenuText = "",
                    headerTextAlignment = TextAlignment.Center,
                    width = 120, minWidth = 120,
                    autoResize = true,
                    allowToggleVisibility = false,
                    canSort = false
                }
            };
        }

        protected override TreeViewItem BuildRoot()
        {
            var root = new TreeViewItem(-1, -1) { children = new List<TreeViewItem>() };

            var matchingId = signalAssetContext != null && readonlySignals ? FindIdForSignal(signals, signalAssetContext) : -1;
            if (matchingId >= 0)
                AddItem(root, matchingId);

            for (var i = 0; i < signals.arraySize; ++i)
            {
                if (i == matchingId) continue;
                AddItem(root, i, !readonlySignals);
            }

            return root;
        }

        protected override void RowGUI(RowGUIArgs args)
        {
            var item = (SignalReceiverItem)args.item;
            for (var i = 0; i < args.GetNumVisibleColumns(); ++i)
            {
                var rect = args.GetCellRect(i);
                rect.y += k_VerticalPadding;
                item.Draw(rect, args.GetColumn(i), args.row, k_HorizontalPadding, m_Target);
            }
        }

        protected override float GetCustomRowHeight(int row, TreeViewItem treeItem)
        {
            var item = treeItem as SignalReceiverItem;
            return item.GetHeight() + k_VerticalPadding;
        }

        void AddItem(TreeViewItem root, int id, bool enabled = true)
        {
            var signal = signals.GetArrayElementAtIndex(id);
            var evt = events.GetArrayElementAtIndex(id);
            root.children.Add(new SignalReceiverItem(signal, evt, id, readonlySignals, enabled, this));
        }

        float GetTotalHeight()
        {
            var height = 0.0f;
            foreach (var item in GetRows())
            {
                var signalListItem = item as SignalReceiverItem;
                height += signalListItem.GetHeight() + k_VerticalPadding;
            }

            var scrollbarPadding = showingHorizontalScrollBar ? GUI.skin.horizontalScrollbar.fixedHeight : k_VerticalPadding;
            return height + multiColumnHeader.height + scrollbarPadding;
        }

        static int FindIdForSignal(SerializedProperty signals, SignalAsset signalToFind)
        {
            for (var i = 0; i < signals.arraySize; ++i)
            {
                //signal in the receiver that matches the current signal asset will be displayed first
                var serializedProperty = signals.GetArrayElementAtIndex(i);
                var signalReferenceValue = serializedProperty.objectReferenceValue;
                var signalToFindRefValue = signalToFind;
                if (signalReferenceValue != null && signalReferenceValue == signalToFindRefValue)
                    return i;
            }
            return -1;
        }
    }
}