Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[SOLVED]: Custom Editor OnSceneGUI Scripting

Discussion in 'Scripting' started by dagbud, Nov 10, 2009.

  1. dagbud

    dagbud

    Joined:
    Nov 10, 2009
    Posts:
    22
    I am currently learning how to write scripts in Unity and decided to try my hand at writing a path editor for an upcoming game I am planning. I have a path class which holds the actual path data and a custom editor for the path. Now I was trying to use the SceneView to do most of my editing work, that is adding path nodes and whatnot. I can successfully display the path nodes using PositionHandles, or FreeMoveHandles. I have been able to add nodes by clicking in the SceneView. Here is where I am getting tripped up.

    If I attach my path script to an empty GameObject, when I click the scene the SceneView will add the node, then select the object I clicked. I thought that by calling the Event.current.use (), the mouse click event would essentially not be processed anymore. This doesn't seem to be the case. I have scoured the reference docs and searched the forums to come up with a good solution and have done some tests using keyboard commands which may work, but is not optimal. Is there something I am missing being a complete noob to Unity? Or am I going about the problem wrong?

    Here is my code for those interested:
    Code (csharp):
    1.  
    2.   public void OnSceneGUI ()
    3.     {
    4.       if (Event.current.type == EventType.MouseDown)
    5.       {
    6.         if (Event.current.button == 0)
    7.         {
    8.           Ray worldRay = HandleUtility.GUIPointToWorldRay (Event.current.mousePosition);
    9.           RaycastHit hitInfo;
    10.  
    11.           if (Physics.Raycast (worldRay, out hitInfo))
    12.           {
    13.             Undo.RegisterUndo (target, "Add Path Node");
    14.             ((Path)target).AddNode (hitInfo.point);
    15.           }
    16.  
    17.           Event.current.Use ();
    18.         }
    19.       }
    20.  
    21.       for (int i = 0; i < ((Path)target).nodes.Count; i++)
    22.         ((Path)target).nodes[i] = Handles.PositionHandle(((Path)target).nodes[i], Quaternion.identity);
    23.      
    24.       Handles.DrawPolyLine (((Path)target).nodes.ToArray ());
    25.  
    26.       if (GUI.changed)
    27.           EditorUtility.SetDirty(target);
    28.     }
    29.  
    Again any help or suggestions would be greatly appreciated. Thanks.

    - Ed Weese
     
  2. dagbud

    dagbud

    Joined:
    Nov 10, 2009
    Posts:
    22
    For more clarification, I would basically like to disable object selection in the scene view when my path tools are active.

    -Ed Weese
     
    ocimum likes this.
  3. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Could you set a boolean variable whenever the path tools are active and then test for it in the "if" statement where the raycast is performed?
     
  4. dagbud

    dagbud

    Joined:
    Nov 10, 2009
    Posts:
    22
    I setup a boolean variable to tell the function if the add node tool is active. However, this still presents the problem of adding the node, then the mouse click gets used again to select or deselect the object by the Scene View.
     
    ocimum likes this.
  5. dagbud

    dagbud

    Joined:
    Nov 10, 2009
    Posts:
    22
    Taking another look at the docs reveals that calling Event.current.Use () in my OnSceneGUI function should make it so the Scene View doesn't process the event. This is not what is happening.

    I am using Unity 2.6 on a windows machine and the script is C#. Has anyone else had the same problem or am I misunderstanding the whole situation? Any help is greatly appreciated. Thanks.

    -Ed Weese
     
  6. dagbud

    dagbud

    Joined:
    Nov 10, 2009
    Posts:
    22
    After searching long and hard to no avail, I finally found what my problem was. I wasn't getting a controlID for my new control and setting it as the default. This was something that I had overlooked being so new to Unity. By doing so, the proper behavior that I was trying to achieve was obtained. All it took was some reflection. :D Below is my new code for anyone that is experiencing the same issue.

    Code (csharp):
    1.  
    2.   void OnSceneGUI()
    3.   {
    4.     Event current = Event.current;
    5.     int controlID = GUIUtility.GetControlID(mPathEditorHash, FocusType.Passive);
    6.  
    7.     switch (current.type)
    8.     {
    9.       case EventType.mouseUp:
    10.         switch (mActiveTool)
    11.         {
    12.           case Tools.toolAdd:
    13.             addNode();
    14.             break;
    15.         }
    16.  
    17.         current.Use();
    18.         break;
    19.  
    20.       case EventType.layout:
    21.         HandleUtility.AddDefaultControl(controlID);
    22.         break;
    23.     }
    24.  
    25.         for (int i = 0; i < ((Path)target).nodes.Count; i++)
    26.           ((Path)target).nodes[i] =
    27.             Handles.FreeMoveHandle(((Path)target).nodes[i],
    28.             Quaternion.identity, 0.25f, new Vector3(1.0f, 1.0f, 1.0f),
    29.             Handles.DrawRectangle);
    30.  
    31.         Handles.DrawPolyLine(((Path)target).nodes.ToArray());
    32.  
    33.         if (GUI.changed)
    34.           EditorUtility.SetDirty(target);
    35.   }
    36.  
     
  7. fellipeml

    fellipeml

    Joined:
    May 12, 2009
    Posts:
    74
    thanks, man. :)
     
  8. sujinlab

    sujinlab

    Joined:
    Jun 4, 2010
    Posts:
    7
    Thanks. man.
    I guess one.
    What means 'mPathEditorHash' variable in GetControlID(...) ?
     
  9. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    mPathEditorHash is probably just GetHashCode (). It could certainly be something else, but that one works for me.
     
  10. crotchfruit

    crotchfruit

    Joined:
    Apr 3, 2011
    Posts:
    7
    Thanks a bunch; I was pulling my hair out trying to solve a similar problem.
     
  11. JFFM

    JFFM

    Joined:
    Nov 13, 2010
    Posts:
    336
    A long time after the fact:

    Thanks for this! I've come back to this post twice to solve the same problem... many many months apart.

    -JFFM
     
  12. Veehmot

    Veehmot

    Joined:
    Oct 26, 2008
    Posts:
    27
    Thanks! I really appreciate that you shared the answer to your own problem.
     
  13. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    220
    nice code that simply dont work at all. unity doc is a joke and this code is the same.

    ... at least till anybody 'educated' takes 2 min to explain where the magical
    'mPathEditorHash' comes from
     
  14. davvilla

    davvilla

    Joined:
    Mar 28, 2012
    Posts:
    18
    After hours of googling finally found something that works. Thanks for sharing!
     
  15. Chunks

    Chunks

    Joined:
    Jul 30, 2012
    Posts:
    4
    OMG! Years later, after hours of searching, this fixes my problem. You win the Internet, sir.

    And why in blazes is this answer so well hidden?!? Is there some way I can upvote you to heaven?
     
    ocimum likes this.
  16. Wenceslao

    Wenceslao

    Joined:
    Feb 7, 2009
    Posts:
    142
    Thank you so much dagbud. I've been struggling with this lately and I thought I was doing something wrong because according to the documents, if I use the event, the editor should not use it as well (which wasn't the case). I found this in this thread: http://forum.unity3d.com/threads/99909-Hurr-EventType.MouseUp-not-working-on-Left-Clicks

    Really though, this post is 3 years old and it seems that people still run into this problem. Perhaps I'll bring it up with some people on the IRC channel tonight to if anything, add some note to the documentation.

    At least now my tool now allows me to populate waypoints quickly and the editor doesn't try to use my mouse clicks to select objects in the scene.
     
  17. Jake-L

    Jake-L

    Joined:
    Oct 17, 2009
    Posts:
    397
    For all the years I'm wondering about those strange control IDs and what they're good for, until I need to solve the Event.Use() problem and found this thread. You made my day! Thanks a lot!
     
  18. Raattis

    Raattis

    Joined:
    May 14, 2013
    Posts:
    1
    Thanks a lot for this.

    Here is the part of code needed to solve this problem:
    Code (csharp):
    1.  
    2. if (Event.current.type == EventType.layout)
    3.     HandleUtility.AddDefaultControl(GUIUtility.GetControlID(GetHashCode(), FocusType.Passive));
    4.  
    I put it in the beginning of OnSceneGUI().
     
    Xtro, McDev02 and angralon like this.
  19. Avalion

    Avalion

    Joined:
    May 2, 2012
    Posts:
    34
    Great ! It worked !

    Thanks a lot. I was wondering so long how to get Left Mouse Click Up Event !

    But there is a big issue with this 'solution' : It disables Handles and GameObjectSelection in Scene ! Given your script receive the event mouseUp, the Unity-based script for those doesn't get it anymore, and so, you can no more move or deselect your object by clicking in Scene....

    Have someone an idea to solve this ?

    Avalion
     
    Last edited: Aug 1, 2013
  20. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,369
    It fixes the MouseUp issue, but this still never triggers:
    Code (csharp):
    1.  
    2. if(Event.current.type == EventType.MouseDrag){
    3.  
    Edit: now it seems to work... You can try to use Event.current.rawType instead of Event.current.type as well.
     
    Last edited: Aug 4, 2013
  21. Spidyy

    Spidyy

    Joined:
    Mar 6, 2011
    Posts:
    184
    I use this function to block the editor, but now, I want to still be able to select object and use my GameObject's transform, but still be able to click on my custom scene handles.

    Any way to use the AddDefaultControl only when I'm handling the events within the script and don't use it if my script don't touch the event?

    I tried this, but it don't seems to work :
    Code (csharp):
    1. bool used = false;
    2.  
    3. void OnSceneGUI()
    4. {
    5.     Event evt = Event.current;
    6.     Rect rect = new Rect(0, 0, 100, 100);
    7.     switch(evt.type)
    8.     {
    9.     case EventType.MouseUp:
    10.         if(evt.button == 0  rect.Contains(evt.mousePosition))
    11.         {
    12.             // Do stuff
    13.             used = true;
    14.             evt.Use();
    15.         }
    16.         break;
    17.     }
    18.  
    19.     if(evt.type == EventType.Layout  used)
    20.     {
    21.         int id = GUIUtility.GetControlID(FocusType.Native);
    22.         HandleUtility.AddDefaultControl(id);
    23.         used = false;
    24.     }
    25. }
    Clicking on the top-left corner of the screen still deselect my object.
     
    Last edited: Sep 7, 2013
  22. Isbanan

    Isbanan

    Joined:
    Sep 12, 2012
    Posts:
    13
    No matter how much I try, I can't get this to work. Anyone, help?

    Code (csharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4.  
    5. //[CustomEditor(typeof(PlaceObjectFromCamera))]
    6. public class PlaceObjectFromCamera : EditorWindow {
    7.    
    8.    
    9.     void OnSceneGUI ()
    10.     {
    11.    
    12.         Event e = Event.current;
    13.        
    14.         if (e.type == EventType.layout)
    15.             HandleUtility.AddDefaultControl(GUIUtility.GetControlID(GetHashCode(), FocusType.Passive));
    16.        
    17.         if (e.type == EventType.mouseUp)
    18.         {
    19.             Debug.Log("Mouse Down");
    20.             Event.current.Use();
    21.         }
    22.        
    23.        
    24.         if(e.type == EventType.Layout)
    25.         {
    26.             int id = GUIUtility.GetControlID(FocusType.Native);
    27.             HandleUtility.AddDefaultControl(id);
    28.         }
    29.     }
    30. }
     
    Last edited: Sep 8, 2013
  23. Isbanan

    Isbanan

    Joined:
    Sep 12, 2012
    Posts:
    13
    zwcloud and ocimum like this.
  24. Spidyy

    Spidyy

    Joined:
    Mar 6, 2011
    Posts:
    184
    THIS TOTURIAL IS THE ANSWER TO ALL MY ISSUES§§

    You gives the control id to GUIUtility.hotControl when you start handling an event (on EventType.MouseDown) and release it with GUIUtility.hotControl = 0 when you finish handling the event (on EventType.MouseUp).

    It easily replace the AddDefaultControl and gives more power to the event management.

    Just one question : Why use the Event.GetTypeForControl() function instead of just Event.type ?
     
  25. Kirienko

    Kirienko

    Joined:
    Apr 5, 2013
    Posts:
    37
    I was looking for this like crazy. Thanks man!!! This worked for me.

    The video tutorial also worked but disabled all camera movement in the scene :(
     
  26. higekun

    higekun

    Joined:
    Nov 15, 2012
    Posts:
    2
  27. hausmaus

    hausmaus

    Joined:
    Dec 9, 2011
    Posts:
    105
    Just another word of thanks for posting this information! As powerful as the Editor is, the docs are extremely sparse and, at least to this humble fisherman, these workarounds are unnervingly cryptic.

    Thanks again!
     
  28. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    https://www.youtube.com/watch?v=NcGlsdxIJEU

    Just an example of a path/spline tool we made that way (nodes being internal to the path and not GameObjects)
    Also, in our case, we pre-cache sub-division data so that we can do point-spline projection.
     
  29. ocimum

    ocimum

    Joined:
    Apr 19, 2015
    Posts:
    12
    This tutorial made my day!
    It explains how to get the different Eventtypes work without losing the focus after clicking on the scene!

    If this tutorial helped you, press the like button to show other people it was helpful. I was searching for this a lot of time!
     
    Last edited: Oct 30, 2015
  30. DStrike

    DStrike

    Joined:
    Oct 20, 2015
    Posts:
    1
    +1 Awesome video

    I was having problems with EventType.mouseUp using an EditorWindow for the SceneView.onSceneGUIDelegate
     
    ocimum likes this.
  31. smallbit

    smallbit

    Joined:
    Oct 3, 2013
    Posts:
    60
    I found this 8 years after and still saves my time :) Genius !
     
  32. badr_douah

    badr_douah

    Joined:
    Jun 22, 2017
    Posts:
    22
    @ocimum
    the video tutorial link is dead, can you please tell me how to not lose focus on scene view after clicking , this is my issue , i can't find a fix to
     
  33. DigitalK064

    DigitalK064

    Joined:
    Jul 6, 2018
    Posts:
    8
    Oh man, I'm having the EXACT problem and the tutorial link is dead. Can anyone clear this up for me?
     
    Last edited: Aug 15, 2018
  34. ImperialDynamics

    ImperialDynamics

    Joined:
    Jun 21, 2018
    Posts:
    21
    it doesn't work in a custom GridBrushEditor :(
     
  35. RecklessGames_

    RecklessGames_

    Joined:
    Jul 30, 2010
    Posts:
    222
    Late to the Party, (You Already Know this by now) But for those who are still looking at this, the Example Text does give it away.

    You dont have an mPath Variable as the Example does, so just truncate that off
    'EditorHash'

    and use the EditorWindow Instance as your Control Id as Hash code, tie the input to your window as you most likely desire.

    Code (CSharp):
    1.  
    2. void OnSceneGUI(SceneView sceneView){
    3.   //Reference Current Event in EventSystem
    4.   Event current = Event.current;
    5.  
    6.   //Create Int Reference to ControlID (Use Editor HashCode() which is generated when the window is first instance by   //Unity.
    7.   //'this.GetHashCode()'
    8.   if(SomethingIWantHappens){
    9.     //Get Actual Control and Keep Int Ref
    10.     int controlID = GUIUtility.GetControlID(this.GetHashCode(), FocusType.Passive);
    11.      //Now here at end of Custom Input Logic, We Consume the Entire Event from the System and Unity will no longer be able to Use this. (Turning Off Scene View Native Inputs)
    12.     current.use();
    13.   }
    14. }
    15.  
    16.  
     
    Last edited: Aug 29, 2021