Search Issue Tracker
Won't Fix
Votes
1
Found in
2017.1.0f3
Issue ID
933758
Regression
No
GUILayoutUtility.GetLastRect returns incorrect rect when used after EditorGUILayout.DropdownButton
Steps to reproduce:
1. Open user attached project (GetLastRectBug)
2. Open Scene "Main", select "MyComponent"
3. Click the "My Dropdown" dropdown button.
4. Notice the generic menu position is incorrect.
Expected: The generic menu position should be aligned below the dropdown button.
Actual: The menu position is at the top left corner of the inspector panel.
Reproduced in: 2017.3.0a1, 2017.2.0b4, 2017.1.0p1, 5.6.2p4, 5.6.0b11
Add comment
All about bugs
View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.
Latest issues
- Articulation Body with 'Revolute' Joint Type has erratic behavior when Upper Limit is set to above 360
- WebGL Player fails to render Scene when Terrain with Detail Mesh is added and WebGPU Graphics API is used
- Inconsistent errors are logged when different types are passed into the Query "Q<>" method in UIToolkit and the ancestor VisualElement is null
- Crash on GetMaterialPropertyByIndex when opening a specific Scene
- Discrepancies in the styling are present when using a TSS file instead of a USS file in custom EditorWindow
m4c0
Jan 29, 2018 18:21
That's a nice insight over the GUI internals. Unfortunately, that logic will become very complex as we add more dropdowns to the same GUI - for instance, if you are creating such buttons in a loop.
A shorter workaround is to give up using GenericMenu.DropDown and use GenericMenu.ShowAsContext instead. If you have a dedicated UX team, they will give you a long speech about using the proper UI elements and alignments. If you are just creating something to improve your team's productivity, nobody will notice the difference...
Perceive
Dec 16, 2017 21:37
This is because of when the DropdownButton returns true, and when you're allowed to call GUILayoutUtility.GetLastRect.
You can only call GUILayoutUtility.GetLastRect during a repaint event (Event.current.type == EventType.Repaint), otherwise it returns dummy values. (This is what you're experiencing.) The DropdownButton also only returns 'true' on the "used" event (Event.current.type == EventType.used). Because of both of these, you can't have the GetLastRect call within the if statement for the DropdownButton. This won't work:
if (EditorGUILayout.DropdownButton(new GUIContent("Click me!"), FocusType.Keyboard)) {
// GetLastRect only returns real values during Repaint
if (Event.current.type == EventType.Repaint) {
// This code is never reached, because DropdownButton only returns true on Used
Rect menuRect = GUILayoutUtility.GetLastRect();
Debug.Log("I never actually get called!" + Environment.NewLine + menuRect.ToString());
}
}
But by splitting out the GetLastRect so that it occurs regardless of the DropdownButton being pressed, it will indeed work.
private Rect menuRect;
public override void OnInspectorGUI() {
bool selected = EditorGUILayout.DropdownButton(new GUIContent("Click me!"), FocusType.Keyboard);
if (Event.current.type == EventType.Repaint) {
menuRect = GUILayoutUtility.GetLastRect();
Debug.Log("I get called now!" + Environment.NewLine + menuRect.ToString());
}
if (selected) {
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("I'm drawing in the correct position!"), false, null);
menu.DropDown(menuRect);
}
}
Hopefully this helps anyone else stumbling upon this problem.