public void Init(Rect buttonRect)
        {
            m_ButtonRectScreenPos = EditorGUIUtility.GUIToScreenRect(buttonRect);
            if (m_State == null)
            {
                m_State = new AdvancedDropdownState();
            }
            if (m_DataSource == null)
            {
                m_DataSource = new MultiLevelDataSource();
            }
            if (m_Gui == null)
            {
                m_Gui = new AdvancedDropdownGUI(m_DataSource);
            }
            m_Gui.state = m_State;

            // Has to be done before calling Show / ShowWithMode
            buttonRect = GUIUtility.GUIToScreenRect(buttonRect);
            OnDirtyList();
            m_CurrentlyRenderedTree = hasSearch ? m_DataSource.searchTree : m_DataSource.mainTree;
            ShowAsDropDown(buttonRect, CalculateWindowSize(buttonRect), GetLocationPriority());
            if (setInitialSelectionPosition)
            {
                m_InitialSelectionPosition = m_Gui.GetSelectionHeight(m_DataSource, buttonRect);
            }
            wantsMouseMove = true;
            SetSelectionFromState();
        }
Example #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);
                    }
                }
            }
        }