コード例 #1
0
        public void DoGUI(HierarchyFrameDataView frameDataView, bool fetchData, ref bool updateViewLive, ProfilerViewType viewType)
        {
            using (m_DoGUIMarker.Auto())
            {
                if (Event.current.type != EventType.Layout && m_ThreadIndexDuringLastNonLayoutEvent != threadIndexInThreadNames)
                {
                    m_ThreadIndexDuringLastNonLayoutEvent = threadIndexInThreadNames;
                    EditorGUIUtility.ExitGUI();
                }
                InitIfNeeded();

                var isSearchAllowed = string.IsNullOrEmpty(treeView.searchString) || !(m_ProfilerWindow.ProfilerWindowOverheadIsAffectingProfilingRecordingData() && ProfilerDriver.deepProfiling);

                var isDataAvailable = frameDataView != null && frameDataView.valid;

                var showDetailedView = isDataAvailable && m_DetailedViewType != DetailedViewType.None;
                if (showDetailedView)
                {
                    SplitterGUILayout.BeginHorizontalSplit(m_DetailedViewSpliterState);
                }

                // Hierarchy view area
                GUILayout.BeginVertical();

                if (isDataAvailable && (threadIndex != frameDataView.threadIndex || threadName != frameDataView.threadName))
                {
                    SetFrameDataView(frameDataView);
                }

                DrawToolbar(frameDataView, showDetailedView, ref updateViewLive, viewType);

                if (!string.IsNullOrEmpty(dataAvailabilityMessage))
                {
                    GUILayout.Label(dataAvailabilityMessage, BaseStyles.label);
                }
                else if (!isDataAvailable)
                {
                    if (!fetchData && !updateViewLive)
                    {
                        GUILayout.Label(BaseStyles.liveUpdateMessage, BaseStyles.label);
                    }
                    else
                    {
                        GUILayout.Label(BaseStyles.noData, BaseStyles.label);
                    }
                }
                else if (!isSearchAllowed)
                {
                    GUILayout.Label(BaseStyles.disabledSearchText, BaseStyles.label);
                }
                else
                {
                    var rect = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.ExpandHeight(true), GUILayout.ExpandHeight(true));

                    m_TreeView.SetFrameDataView(frameDataView);
                    m_TreeView.OnGUI(rect, updateViewLive);

                    if (m_TreeView.HasSelection() && m_TreeView.proxySelectionInfo.hasProxySelection)
                    {
                        if (m_TreeView.proxySelectionInfo.cachedDisplayContent == null)
                        {
                            var diff = Math.Abs(m_TreeView.proxySelectionInfo.pathLengthDifferenceForProxy);
                            m_TreeView.proxySelectionInfo.cachedDisplayContent = new GUIContent(
                                BaseStyles.selectionExtraInfoHierarhcyView + string.Format(
                                    BaseStyles.proxySampleMessage,
                                    m_TreeView.proxySelectionInfo.nonProxyName, diff,
                                    diff == 1 ? BaseStyles.proxySampleMessageScopeSingular : BaseStyles.proxySampleMessageScopePlural),
                                BaseStyles.warningTriangle.image);
                        }
                        GUILayout.BeginHorizontal();
                        GUILayout.Box(m_TreeView.proxySelectionInfo.cachedDisplayContent, BaseStyles.selectionExtraInfoArea);
                        var rectForSampleStackButton = GUILayoutUtility.GetRect(BaseStyles.showDetailsDropdownContent, BaseStyles.tooltipDropdown, GUILayout.ExpandHeight(false), GUILayout.ExpandHeight(false));
                        if (GUI.Button(rectForSampleStackButton, BaseStyles.showDetailsDropdownContent, BaseStyles.tooltipDropdown))
                        {
                            var selection  = m_TreeView.GetSelection();
                            var selectedId = (selection != null && selection.Count > 0) ? selection[0] : ProfilerFrameDataHierarchyView.invalidTreeViewId;
                            if (selectedId >= 0)
                            {
                                var menu = new GenericMenu();

                                // Show Sample Selection:
                                var rawSampleIndices = new List <int>(frameDataView.GetItemMergedSamplesCount(selectedId));
                                frameDataView.GetItemRawFrameDataViewIndices(selectedId, rawSampleIndices);
                                var actualMarkerIdPath = new List <int>(frameDataView.GetItemDepth(selectedId));
                                using (var iterator = new RawFrameDataView(frameDataView.frameIndex, frameDataView.threadIndex))
                                {
                                    string name     = null;
                                    var    rawIndex = ProfilerTimelineGUI.GetItemMarkerIdPath(iterator, cpuModule, rawSampleIndices[0], ref name, ref actualMarkerIdPath);
                                }

                                var actualMarkerPath = new List <string>(actualMarkerIdPath.Count);
                                foreach (var id in actualMarkerIdPath)
                                {
                                    if ((frameDataView.GetMarkerFlags(id) & Unity.Profiling.LowLevel.MarkerFlags.AvailabilityEditor) != 0)
                                    {
                                        actualMarkerPath.Add(string.Format("EditorOnly [{0}]", frameDataView.GetMarkerName(id)));
                                    }
                                    else
                                    {
                                        actualMarkerPath.Add(frameDataView.GetMarkerName(id));
                                    }
                                }

                                // admittedly, it'd be nice to only generate the text if sample selection option was chosen...
                                // however, that would need to happen in an OnGui call and not within the callback of the generic menu,
                                // to be able to calculate the needed window size and avoid glitches on first displaying it.
                                // at least the user already clicked on the dropdown for this...

                                string selectedSampleStackText = null;
                                var    sampleStackSb           = new System.Text.StringBuilder();
                                if (m_TreeView.proxySelectionInfo.nonProxySampleStack != null && m_TreeView.proxySelectionInfo.nonProxySampleStack.Count > 0)
                                {
                                    for (int i = m_TreeView.proxySelectionInfo.nonProxySampleStack.Count - 1; i >= 0; i--)
                                    {
                                        sampleStackSb.AppendLine(m_TreeView.proxySelectionInfo.nonProxySampleStack[i]);
                                    }
                                    selectedSampleStackText = sampleStackSb.ToString();
                                }
                                string actualSampleStackText = null;
                                if (actualMarkerPath != null && actualMarkerPath.Count > 0)
                                {
                                    sampleStackSb.Clear();

                                    for (int i = actualMarkerPath.Count - 1; i >= 0; i--)
                                    {
                                        sampleStackSb.AppendLine(actualMarkerPath[i]);
                                    }
                                    actualSampleStackText = sampleStackSb.ToString();
                                }

                                var selectionSampleStackContent = selectedSampleStackText != null ? new GUIContent(selectedSampleStackText) : null;
                                var actualSampleStackContent    = actualSampleStackText != null ? new GUIContent(actualSampleStackText) : null;
                                var sampleStackWindowSize       = SelectedSampleStackWindow.CalculateSize(selectionSampleStackContent, actualSampleStackContent);
                                menu.AddItem(BaseStyles.showSelectedSampleStacks, false, () =>
                                {
                                    SelectedSampleStackWindow.ShowSampleStackWindow(GUIUtility.GUIToScreenRect(rectForSampleStackButton).position, sampleStackWindowSize, selectionSampleStackContent, actualSampleStackContent);
                                });
                                menu.DropDown(rectForSampleStackButton);
                            }
                        }
                        GUILayout.EndHorizontal();
                    }
                }

                GUILayout.EndVertical();

                if (showDetailedView)
                {
                    GUILayout.BeginVertical();

                    // Detailed view area
                    EditorGUILayout.BeginHorizontal(BaseStyles.toolbar);

                    DrawDetailedViewPopup();
                    GUILayout.FlexibleSpace();

                    cpuModule.DrawOptionsMenuPopup();
                    EditorGUILayout.EndHorizontal();

                    switch (m_DetailedViewType)
                    {
                    case DetailedViewType.Objects:
                        detailedObjectsView.DoGUI(BaseStyles.header, frameDataView, m_TreeView.GetSelection());
                        break;

                    case DetailedViewType.CallersAndCallees:
                        detailedCallsView.DoGUI(BaseStyles.header, frameDataView, m_TreeView.GetSelection());
                        break;
                    }

                    GUILayout.EndVertical();

                    SplitterGUILayout.EndHorizontalSplit();
                }

                HandleKeyboardEvents();
            }
        }
コード例 #2
0
        protected void ShowLargeTooltip(Vector2 pos, Rect fullRect, GUIContent content, ReadOnlyCollection <string> selectedSampleStack,
                                        float lineHeight, int frameIndex, int threadIndex, bool hasCallstack, ref float downwardsZoomableAreaSpaceNeeded,
                                        int selectedSampleIndexIfProxySelection = -1)
        {
            // Arrow of tooltip
            var arrowRect = BaseStyles.tooltipArrowRect;

            arrowRect.position += pos;

            var style                 = BaseStyles.tooltip;
            var size                  = style.CalcSize(content);
            var copyButtonSize        = BaseStyles.tooltipButton.CalcSize(BaseStyles.tooltipCopyTooltip);
            var sampleStackButtonSize = new Vector2();

            if (selectedSampleStack != null && selectedSampleStack.Count > 0)
            {
                sampleStackButtonSize    = BaseStyles.tooltipButton.CalcSize(BaseStyles.showDetailsDropdownContent);
                sampleStackButtonSize.x += BaseStyles.magicMarginValue;
            }

            const int k_ButtonBottomMargin = BaseStyles.magicMarginValue;
            var       requiredButtonHeight = Mathf.Max(copyButtonSize.y, sampleStackButtonSize.y) + k_ButtonBottomMargin;

            // report how big the zoomable area needs to be to be able to see the entire contents if the view is big enough
            downwardsZoomableAreaSpaceNeeded = arrowRect.height + size.y + requiredButtonHeight;
            size.y += requiredButtonHeight;

            size.x = Mathf.Max(size.x, copyButtonSize.x + sampleStackButtonSize.x + k_ButtonBottomMargin * 3);

            var heightAvailableDownwards = Mathf.Max(fullRect.yMax - arrowRect.yMax, 0);
            var heightAvailableUpwards   = Mathf.Max(pos.y - lineHeight - arrowRect.height - fullRect.y, 0);

            float usedHeight = 0;
            float rectY      = 0;
            // Flip tooltip if too close to bottom and there's more space above it
            var flipped = (arrowRect.yMax + arrowRect.height + size.y > fullRect.yMax) && heightAvailableUpwards > heightAvailableDownwards;

            if (flipped)
            {
                arrowRect.y -= (lineHeight + 2 * arrowRect.height);
                usedHeight   = Mathf.Min(heightAvailableUpwards, size.y);
                rectY        = arrowRect.y + arrowRect.height - usedHeight;
            }
            else
            {
                usedHeight = Mathf.Min(heightAvailableDownwards, size.y);
                rectY      = arrowRect.yMax;
            }

            // The tooltip needs to have enough space (on line of text + buttons) to allow for us to but buttons in there without glitches
            var showButtons = usedHeight >= (requiredButtonHeight + style.CalcSize(BaseStyles.tooltipCopyTooltip).y);

            if (!showButtons)
            {
                size.y -= requiredButtonHeight;
            }

            // Label box
            var rect = new Rect(pos.x + BaseStyles.tooltipArrowRect.x, rectY, size.x, usedHeight);

            // Ensure it doesn't go too far right
            if (rect.xMax > fullRect.xMax)
            {
                rect.x = Mathf.Max(fullRect.x, fullRect.xMax - rect.width);
            }
            if (rect.xMax > fullRect.xMax)
            {
                rect.xMax = fullRect.xMax;
            }
            if (arrowRect.xMax > fullRect.xMax + 20)
            {
                arrowRect.x = fullRect.xMax - arrowRect.width + 20;
            }

            // Adjust left to we can always see giant (STL) names.
            if (rect.xMin < fullRect.xMin)
            {
                rect.x = fullRect.xMin;
            }
            if (arrowRect.xMin < fullRect.xMin - 20)
            {
                arrowRect.x = fullRect.xMin - 20;
            }

            // Draw small arrow
            GUI.BeginClip(arrowRect);
            var oldMatrix = GUI.matrix;

            if (flipped)
            {
                GUIUtility.ScaleAroundPivot(new Vector2(1.0f, -1.0f), new Vector2(arrowRect.width * 0.5f, arrowRect.height));
            }
            GUI.Label(new Rect(0, 0, arrowRect.width, arrowRect.height), GUIContent.none, BaseStyles.tooltipArrow);
            GUI.matrix = oldMatrix;
            GUI.EndClip();

            var copyButtonRect = new Rect(rect.x + k_ButtonBottomMargin, rect.yMax - copyButtonSize.y - k_ButtonBottomMargin, copyButtonSize.x, copyButtonSize.y);

            var selectableLabelTextRect = rect;

            if (showButtons)
            {
                selectableLabelTextRect.yMax = copyButtonRect.y - k_ButtonBottomMargin;
            }
            var buttonArea = rect;

            if (showButtons)
            {
                buttonArea.yMin = copyButtonRect.y;
            }

            // Draw tooltip
            if (Event.current.type == EventType.Repaint)
            {
                style.Draw(rect, false, false, false, false);
            }
            GUI.BeginClip(selectableLabelTextRect);
            selectableLabelTextRect.position = Vector2.zero;
            //var controlId = GUIUtility.GetControlID(BaseStyles.tooltipButtonAreaControlId, FocusType.Passive, buttonArea);
            EditorGUI.SelectableLabel(selectableLabelTextRect, content.text, style);
            GUI.EndClip();

            if (showButtons)
            {
                // overwrite the mouse cursor for the buttons on potential splitters underneath the buttons
                if (Event.current.type == EventType.Repaint)
                {
                    EditorGUIUtility.AddCursorRect(buttonArea, MouseCursor.Arrow);
                }
                // and steal the hot control if needed.
                var controlId = GUIUtility.GetControlID(BaseStyles.tooltipButtonAreaControlId, FocusType.Passive, buttonArea);
                var eventType = Event.current.GetTypeForControl(controlId);
                if (eventType == EventType.MouseDown && buttonArea.Contains(Event.current.mousePosition))
                {
                    GUIUtility.hotControl = controlId;
                }
                else if (GUIUtility.hotControl == controlId && eventType == EventType.MouseUp)
                {
                    GUIUtility.hotControl = 0;
                }
                // copyButton
                if (GUI.Button(copyButtonRect, BaseStyles.tooltipCopyTooltip, BaseStyles.tooltipButton))
                {
                    Clipboard.stringValue = content.text;
                }
                if (selectedSampleStack != null && selectedSampleStack.Count > 0)
                {
                    var sampleStackRect = new Rect(copyButtonRect.xMax + k_ButtonBottomMargin, copyButtonRect.y, sampleStackButtonSize.x, sampleStackButtonSize.y);
                    if (EditorGUI.DropdownButton(sampleStackRect, BaseStyles.showDetailsDropdownContent, FocusType.Passive, BaseStyles.tooltipDropdown))
                    {
                        var menu = new GenericMenu();
                        // The tooltip is already pointing to the what's currently selected, switching the view will Apply that selection in the other view
                        menu.AddItem(GetCPUProfilerViewTypeName(ProfilerViewType.Hierarchy), false, () => { viewTypeChanged(ProfilerViewType.Hierarchy); });
                        menu.AddItem(GetCPUProfilerViewTypeName(ProfilerViewType.RawHierarchy), false, () => { viewTypeChanged(ProfilerViewType.RawHierarchy); });
                        menu.AddSeparator("");
                        if (hasCallstack)
                        {
                            menu.AddItem(BaseStyles.showFullDetailsForCallStacks, showFullDetailsForCallStacks, () => showFullDetailsForCallStacks = !showFullDetailsForCallStacks);
                        }
                        else
                        {
                            menu.AddDisabledItem(BaseStyles.showFullDetailsForCallStacks, showFullDetailsForCallStacks);
                        }

                        menu.AddSeparator("");

                        var rectWindowPosition = EditorGUIUtility.GUIToScreenRect(sampleStackRect).position;

                        // Show Sample Selection :
                        // admittedly, it'd be nice to only generate the text if sample selection option was chosen...
                        // however, that would need to happen in an OnGui call and not within the callback of the generic menu,
                        // to be able to calculate the needed window size and avoid glitches on first displaying it.
                        // at least the user already clicked on the dropdown for this...
                        string selectedSampleStackText = null;
                        var    sampleStackSb           = new System.Text.StringBuilder();
                        for (int i = selectedSampleStack.Count - 1; i >= 0; i--)
                        {
                            sampleStackSb.AppendLine(selectedSampleStack[i]);
                        }
                        selectedSampleStackText = sampleStackSb.ToString();
                        string actualSampleStackText = null;
                        if (selectedSampleIndexIfProxySelection >= 0)
                        {
                            using (var frameData = ProfilerDriver.GetRawFrameDataView(frameIndex, threadIndex))
                            {
                                if (frameData.valid)
                                {
                                    sampleStackSb.Clear();
                                    string sampleName   = null;
                                    var    markerIdPath = new List <int>(selectedSampleStack != null ? selectedSampleStack.Count : 10);
                                    if (ProfilerTimelineGUI.GetItemMarkerIdPath(frameData, cpuModule, selectedSampleIndexIfProxySelection, ref sampleName, ref markerIdPath) >= 0)
                                    {
                                        for (int i = markerIdPath.Count - 1; i >= 0; i--)
                                        {
                                            sampleStackSb.AppendLine(frameData.GetMarkerName(markerIdPath[i]));
                                        }
                                        actualSampleStackText = sampleStackSb.ToString();
                                    }
                                }
                            }
                        }
                        var selectionSampleStackContent = selectedSampleStack != null ? new GUIContent(selectedSampleStackText) : null;
                        var actualSampleStackContent    = actualSampleStackText != null ? new GUIContent(actualSampleStackText) : null;
                        var sampleStackWindowSize       = SelectedSampleStackWindow.CalculateSize(selectionSampleStackContent, actualSampleStackContent);
                        menu.AddItem(BaseStyles.showSelectedSampleStacks, false, () =>
                        {
                            SelectedSampleStackWindow.ShowSampleStackWindow(rectWindowPosition, sampleStackWindowSize, selectionSampleStackContent, actualSampleStackContent);
                        });
                        menu.DropDown(sampleStackRect);
                    }
                }
            }
        }