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(); }
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); } } } }