Search code examples
c#unity-game-enginegame-developmentunity-editor

How to keep multiple editor tool enabled at once in Unity GUI?


I have created a simple custom editor tool, which allows me to keep mouse position in a straight line. I require this to draw texture on a terrain in a straight line. Unfortunately, when I enable "Paint texture" tool in the terrain editor in inspector, my custom tool gets disabled and vice-versa. How can I keep both my custom tool and terrain paint tool enabled at once?

Custom tool selected but paint texture is deactivated- Custom tool selected but paint texture is deactivated

Custom tool got deselected on paint texture selection- Custom tool got deselected on paint texture selection

Following is the OnToolGUI method

    public override void OnToolGUI(EditorWindow window)
    {
        HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
        Event e = Event.current;
        if (!(window is SceneView))
            return;

        if (!ToolManager.IsActiveTool(this))
            return;

        if (e.shift)
        {
            if (e.type == EventType.MouseDown)
            {
                if (e.button == 0)
                {
                    downY = e.mousePosition.y;
                }
            }
            if (e.type == EventType.MouseDrag)
            {
                if (e.button == 0)
                {
                    e.mousePosition = new Vector2(e.mousePosition.x, downY);
                    Debug.Log("Mouse Position: " + e.mousePosition);
                }
            }
        }

Solution

  • As mentioned in the comments I guess it simply is the nature of the tools that they are exclusive and you can only have one active at a time.

    As alternative I would rather simply

    • enable/disable this via a general header menu entry
    • (optionally) store that decision persistent in EditorPrefs (pretty much like PlayerPrefs but for the editor itself)
    • and accordingly attach a listener to SceneView.duringSceneGui

    This could look somewhat like e.g.

    public static class StraightLineTool
    {
        // Used for the displayed menu labels 
        // and also simply (ab)used as the unique key for the EditorPrefs
        private const string k_MenuName = "My Tools/Straight Line Tool";
    
        private static float downY;
    
        // Property for simplifying access and setting more centralized
        private static bool IsEnabled
        {
            get => EditorPrefs.GetBool(k_MenuName, false);
            set => EditorPrefs.SetBool(k_MenuName, value);
        }
    
        // method to be called when clicking the menu button
        [MenuItem(k_MenuName)]
        private static void ToggleEnabled()
        {
            IsEnabled = !IsEnabled;
    
            ApplySettings();
        }
    
        // adding a checkmark when is enabled and simply always allow to click it
        [MenuItem(k_MenuName, true)]
        private static bool ToggleEnabledValidate()
        {
            Menu.SetChecked(k_MenuName, IsEnabled);
            return true;
        }
    
        // Called on every project loading or code recompilation
        [InitializeOnLoadMethod]
        private static void Initialize()
        {
            EditorApplication.delayCall -= ApplySettings;
            EditorApplication.delayCall += ApplySettings;
        }
    
        private static void ApplySettings()
        {
            // remove so only happening once
            EditorApplication.delayCall -= ApplySettings;
    
            SceneView.duringSceneGui -= OnSceneGUI;
    
            if (IsEnabled)
            {
                // if enabled start listening
                SceneView.duringSceneGui += OnSceneGUI;
            }
        }
    
        // Callback listening to any SceneView.duringSceneGui
        private static void OnSceneGUI(SceneView sceneView)
        {
            // Not sure tbh what this does or if you need it still in this approach
            // HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
            var currentEvent = Event.current;
    
            if (currentEvent.shift)
            {
                if (currentEvent.type == EventType.MouseDown)
                {
                    if (currentEvent.button == 0)
                    {
                        downY = currentEvent.mousePosition.y;
                    }
                }
    
                if (currentEvent.type == EventType.MouseDrag)
                {
                    if (currentEvent.button == 0)
                    {
                        currentEvent.mousePosition = new Vector2(currentEvent.mousePosition.x, downY);
                        Debug.Log("Mouse Position: " + currentEvent.mousePosition);
                    }
                }
            }
        }
    }
    

    => using this the tool will be enabled/disabled persistent even when restarting Unity

    enter image description here


    Then using this as start point you can probably still try to somehow integrate this somewhere more nicely into the SceneView menus - but maybe that is also overkill ;)