Aspekt
Aspekt

Reputation: 78

Unity3D Draggable GUI.Box with GUI controls

I'm constructing a custom node editor window in Unity, and I've had a look at various resources such as this one, which uses GUI.Box to construct node windows.

This works great, and I'm able to drag these windows around the way I want, however once I add controls to the GUI.Box, I want them to override the Drag() function I've written.

Here's an example of the issue - When I move the vertical slider up, the entire box drags with it.

Vertical Slider issues

Is there a way to fix this behavior using GUI.Box, or should I go back to GUI.Window with its built-in GUI.DragWindow()?

Here's a simplified version of the code I'm using:

EditorMouseInput.cs:

private bool ActionLeftMouseDown()
{
    mouseDownNode = editor.GetSelectedNode(Input.current.mousePosition);

    if (mouseDownNode == null)
        editor.StartMovingEditorCanvas();
    else
        mouseDownNode.IsSelected = true;
}

BaseNodeEditor.cs:

public BaseNode GetSelectedNode(Vector2 mousePos)
{
    foreach (BaseNode node in Nodes)
    {
        if (node.WindowRect.Contains(mousePos))
            return node;
    }
    return null;
}

public void Drag(Vector2 delta)
{
    if (!MoveEditorMode && !ConnectionMode)
    {
        foreach (BaseNode node in Nodes)
        {
            node.Drag(delta);
        }
    }

BaseNode.cs:

public void Drag(Vector2 delta)
{
    if (IsSelected)
        draggedDistance += delta;
}

The vertical slider is added in the derived JumpNode class. Extract of the helper class that constructs the slider:

Vector2 pos = node.WindowRect.position + rect.position * GridSpacing;
value = GUI.VerticalSlider(new Rect(pos, rect.size * GridSpacing), value, maxValue, minValue);

I can see why this doesn't do what I want, but I don't know how to go about it given the GUI controls aren't part of the GUI.Box.

Any help or suggestions, even a nudge towards another source would be greatly appreciated - I feel I've used all the search terms that exist in my head!

Edit - Solved: Thanks to Kleber for solving this one for me. In case anyone else runs into this or a similar issue, the solution for me was in realising that GUI controls consume left mousedown events automatically, so clicking a slider means there's no propagation to the Box to check if it was clicked.

What I needed to do was separate the IsSelected and IsDragged flags in the Node class, and clear IsDragged on mouseUp. I originally used IsSelected to flag both drag enabled, and selected (multiple nodes could be selected and dragged at once).

Upvotes: 1

Views: 3237

Answers (1)

Kleber
Kleber

Reputation: 1065

It's quite a complex tutorial so I didn't read it entirely, but the problem seems to be the MouseDrag detection. Well, basically you want to stop the event propagation when you click on a GUI element inside the Box, right? To do so, you call:

Event.current.Use()

every time the user drags the mouse on one of your components.

Using the resource you've mentioned, I altered the Node class and added a slider inside the Draw() method, ending like this:

public void Draw() {
    inPoint.Draw();
    outPoint.Draw();
    GUI.Box(rect, title, style);
    GUI.BeginGroup(rect);
    _value = GUI.HorizontalSlider(new Rect(20, 0, 50, 20), _value, 100, -100);
    GUI.EndGroup();
}

First example

Another thing you can do is change how you draw your window. Here it's a simple example that I've tested on the latest Unity version (5.6):

private void OnGUI() {
    GUI.Box(_rect, string.Empty);
    GUI.BeginGroup(_rect);

    _value = GUI.VerticalSlider(new Rect(145, 100, 20, 100), _value, 100, -100);
    GUI.EndGroup();

    var e = Event.current;
    if (e.type == EventType.MouseDrag && _rect.Contains(e.mousePosition)) {
        _rect.x += e.delta.x;
        _rect.y += e.delta.y;
        Repaint();
    }
}

As you can see, this example doesn't need an Event.current.Use() to work properly.

Second example

Upvotes: 2

Related Questions