- Home /
Handles.Button unresponsive in custom editor after custom asset serialization
I'm making a custom node editor in Unity to use as a base from which to make more specific editors for things like dialogue trees.
A key part of this editor is the ability to create connections between nodes, and also for the user to be able to modify these connections immediately, after they're created.
To modify a connection, I'm using a Handle.Button with a circle cap that the user can click on, which calls a function that deletes the existing connection and starts a new one of the same connection type.
You can see what this looks like below. I've circled two Handle.Button 's in red for clarity:
These buttons work fine initially, but when the scene is saved and the custom assets that hold these connections are serialized and Unity then reloaded, these buttons become unresponsive. Only new connections are responsive, and even then, clicking one of the Handle buttons from these new connections deletes one of the unresponsive connections.
There's too much code for me to chop out the relevant bits and paste them here, so here's a link to the public GitHub repo that you should be able to pull the project from:
https://github.com/matski53/NodeEditor
You can access the editor in Unity by going:
Window/Custom/NodeEditor.
The key scripts are the NodeConnection script, which is where the connections and Handle.Button circles are drawn:
Assets\NodeEditor\Scripts\NodeConnections
and the NodeEditor, which is the key Custom Editor script that handles most of what the editor does and looks like.
There's a bit to look through, but I would massively appreciate any help because this has stumped me.
Thanks in advance, Matt
I think this must be something to do with me manually using events (Event.Use()) and manually changing the hotcontrol elsewhere in the NodeEditor script. Could doing these things lead to an unresponsive Handles.Button?
Also, I'm struggling to find resources on GUIUtility hotcontrol and controlID out there. I'd like to $$anonymous$$ch myself how these things work, but there don't seem to be that many discussions of them avaliable. If anyone's got anything I'd appreciate it.
Thanks, $$anonymous$$att
Answer by Bunny83 · Nov 28, 2016 at 12:20 AM
You may want to laugh out loud. I tracked down the problem to the zoom slider control ^^. For some reason it doesn't work with the normal layout system. The problem is that the slider control draws it's content conditionally based on the available width. However, as you might know, during the layout event all rect allocation methods for the layout system return the rect "(0,0,1,1)" since the layouting hasn't been finished yet. Though this makes the slider use the minimal control version. At all other events however it now has more "space" available and draws the "extended" version. This results in many additional controlID allocations which messes up all control ids which are allocated after this slider ^^.
Comment that one line out and it will work again ^^. It should also work when you make your window smaller in width so the slider is hidden and only the input field stays.
That was one weird error ^^. It's really strange since the slider is also used in the terrain inspector, but since the built-in inspectors use an optimised GUI block that problem most likely doesn't show up.
So it is a bug in the EditorGUILayout.Slider implementation. To fix this Unity has to completely rewrite it. Though that auto mode-change thing can't really be implemented with normal the layout system... Maybe they remove it completely ^^.
I suggest you simply rebuild the same with a normal slider and a float field.
Btw: You have a bug inside $$anonymous$$oreConnectionsOfTypeAllowed. You can't compare the "NodeConnectionType " instances since it's a normal "Serializable" class. That means after deserialization each class that had a reference to the same instance will now have their own instance and the Equals check will fail. This allows adding the same connection again each time it gets serialized / deserialized. This even happens on hot-reload when scripts are recompiled.
If you want to continue using references the NodeConnectionType class has to be a ScriptableObject as well.
Thanks for this. I'll test it out when I have chance later today and let you know how I get on.
This has worked. That's a massive help thanks. I don't fully understand your explanation though, because I don't have a thorough understanding of controls in custom editors. Do you know of any good tutorials/guides out there I could look at?
Thanks again, $$anonymous$$att
No ^^ no other than my own over here. However it mainly covers the basics which you most likely know already. The best guide would be to download ILSpy and look into the UnityEngine.dll and UnityEditor.dll to see how most controls are implemented.
$$anonymous$$aybe one day i add some information on control-ids / keyboardControl / hotControl and other more advanced stuff ^^. The problem is on each topic you can always write 2-3 pages ^^.
I just added "a bit" more to my GUI crash course at the end about hotcontrol and control IDs in general. Also a bit more on editor scripting, sceneview and handles.
Answer by ElijahShadbolt · Nov 27, 2016 at 10:37 PM
It appears that Handle controls (Handles.Button(), Handles.PositionHandle(), etc) do not work outside of OnSceneGUI(), as it throws a Null Reference Exception. You need to use GUI.Button() instead. Just edit your code like so:
//HERE IS THE HANDLE BUTTON
Vector2 pos = midPoint - new Vector2(10f, -4f);
Vector2 size = new Vector2(8f, 8f);
Rect rect = new Rect(pos-size, size*2);
if (GUI.Button(rect, GUIContent.none, GUIStyle.none))
{
Debug.Log(outputNode.nodeName);
NodeEditor.ReAssignConnection(connectionType, outputNode);
outputNode.nodeConnections.Remove(this);
}
I usually would agree but in the case of Handle.Button that's not true. It only uses the usual GUI / EditorGUI stuff. Yes a PositionHandle only works inside the SceneView GUI since it directly refers to the active SceneView for some things which will break it.
Thanks for enlightening me on the subject! I haven't delved too deep into GUI/Handles.
Thanks for the response. I actually tried replacing the Handles.Button s with GUI.Buttons, but they too were unresponsive.
Your answer
Follow this Question
Related Questions
Increase thickness of Handles.DrawLine? 0 Answers
Scene view controls locking up > trying to make scene view generic menu on right click 0 Answers
How to create and draw custom Handles (without UnityEditor.Handles class) ? 0 Answers
custom button 2 Answers
How to draw a triangle in the center of a line using GL? 0 Answers