- Home /
How to tackle Mismatched LayoutGroup.DragPerform?
So I've done a Drag and Drop list for a custom inspector I'm working on, but I keep getting the error "GUILayout: Mismatched LayoutGroup.DragPerform" whenever I add an object through drag and drop. Locating the error leads me to a BeginHorizontal line. I guess it's related to how unity draws the inspector, but I'm pretty clueless as to how I should proceed.
Example code of the GUI:
foldActivate = EditorGUILayout.Foldout (foldActivate, "Activate Elements: "+onTrigger.activate.Length.ToString());
if (foldActivate)
{
onTrigger.activate = DragDrop (onTrigger.activate, "Drag'n'Drop\nActivate Object");
for (int i = 0; i < onTrigger.activate.Length; i++)
{
if (onTrigger.delayActivate.Length <= i)
onTrigger.delayActivate = addFloat (onTrigger.delayActivate);
EditorGUILayout.BeginHorizontal ();
onTrigger.activate[i] = EditorGUILayout.ObjectField (onTrigger.activate[i], typeof(Object), true);
onTrigger.delayActivate[i] = EditorGUILayout.FloatField (onTrigger.delayActivate[i], GUILayout.Width(30));
if (GUILayout.Button(deleteCon, GUILayout.Width (40)))
{
onTrigger.activate = deleteObj (onTrigger.activate, i);
onTrigger.delayActivate = deleteFloat (onTrigger.delayActivate, i);
}
EditorGUILayout.EndHorizontal ();
EditorGUILayout.Space ();
}
if (GUILayout.Button ("Add Activate"))
{
onTrigger.activate = addObj (onTrigger.activate);
onTrigger.delayActivate = addFloat (onTrigger.delayActivate);
}
}
drag and drop function:
private Object[] DragDrop(Object[] objList, string boxDesc)
{
var evt = Event.current;
var dropArea = GUILayoutUtility.GetRect (0.0f, 35.0f, GUILayout.ExpandWidth (true));
GUI.Box (dropArea, boxDesc);
switch(evt.type)
{
case EventType.DragUpdated:
case EventType.DragPerform:
if (!dropArea.Contains (evt.mousePosition))
return objList;
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (evt.type == EventType.DragPerform)
{
DragAndDrop.AcceptDrag ();
foreach (var draggedObject in DragAndDrop.objectReferences)
{
var go = draggedObject as GameObject;
if (!go)
continue;
List<Object> tempObj = new List<Object>();
tempObj.AddRange(objList);
tempObj.Add (go);
return tempObj.ToArray ();
}
}
Event.current.Use ();
return objList;
}
return objList;
}
Answer by ForceMagic · May 25, 2016 at 07:10 PM
I had the exact same error as you, found that thread on Unity forum that explain everything.
I thought I could only check for Event.current.type == EventType.Layout, but there's much more thing involved, so I had to maintain a bool _draggedFrame to ensure I do not draw the dynamic GUI on the same frame I filled my list...
See the Thread reference below (just in case the post got deleted/lost)
Originaly posted by UnLogic
This is a very common conceptual misunderstanding with immediate mode gui. It derives from the fact that OnGUI and OnInspectorGUI is called multiple times per frame. You can look at Event.current to see why OnGUI is called this time.
http://docs.unity3d.com/Documentation/ScriptReference/EventType.html
So each frame Unity starts with a Layout, does some Events(this is where your button code is triggered) and a Repaint. However the number and type of controls in the Repaint doesn't match the Layout and thats the problem.
What you're doing is adding a new gui control in the middle of a GUI pass. In general you should use the EventType.Layout for adding and removing controls.
if (Event.current.type == EventType.Layout _handle != null _handle.status != RequestHandle.Status.Pending)
{
//Done...
_loaded = true;
}
So if you change _loaded(which effectively changes the gui layout) only when processing the Layout event everything should work as intended.
[2]: http://answers.unity3d.com/answers/1192419/view.html
Answer by Bunny83 · May 25, 2016 at 06:38 PM
Try putting this line:
onTrigger.activate = DragDrop (onTrigger.activate, "Drag'n'Drop\nActivate Object");
after your for loop.
Since you're going to change the content of the array you get in trouble with the processing of the events.
As you might know every event that is handled by OnGUI / OnInspectorGUI is paired with a Layout event that is issued right before the event. During the layout event Unity collects information about all controls so it can calculate the size and position of every element. When the actual event is processed you have to ensure that you process the same elements as you did during the layout step.
By applying your changes to the object list at the end everything should be fine.
edit
If you want your drag&drop field to stay at the top, just make sure you do the changes at the end. You can simply use a temp variable for this:
var newList = DragDrop (onTrigger.activate, "Drag'n'Drop\nActivate Object");
for (int i = 0; i < onTrigger.activate.Length; i++)
{
// [...]
}
onTrigger.activate = newList;
Answer by warren- · Feb 10, 2017 at 04:34 AM
I'm not sure if this would work for everyone in all scenarios.
When I was getting the error Mismatched LayoutGroup.DragPerform it was due to the fact that I was updating a the Game Object array inside the Layout Event.
In an attempt to avoid the error Argument Exception: Getting control 1's position in a group with only 1 controls when doing DragPerform Aborting
I was using this code (After my GUI Game Object array change):
if (Event.current.type == EventType.DragPerform) { return; }
This worked fine, until I tried to incorporate EditorGUILayout.BeginHorizontal(); and its corresponding EditorGUILayout.EndHorizontal();
I can't speak for everyone elses code, but I think that might be part of the issue we've been having. (As I noticed the code above also utilizes the horizontal layouts.)
So my solution, was to only use the "Begin / End horizontal" calls, in all of the events, except for the Dragperform event.
if (Event.current.type != EventType.DragPerform) { EditorGUILayout.BeginHorizontal(); }
// Your Code to change GUI Content
if (Event.current.type != EventType.DragPerform) { EditorGUILayout.EndHorizontal(); }
if (Event.current.type == EventType.DragPerform) {
// Use this if you started your code with BeginVertical
// EditorGUILayout.EndVertical();
return;
}
This seemed to work fine for me, and I didn't have to store anything in arrays. Perhaps with more complicated drag/drop features though, you might have to do it differently.
Your answer