Handling Node2D Input Events Within ScrollContainer

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By theonlydvr

I have a ScrollContainer which contains a single Control node. Within the Control node are a number of Node2Ds and other Control nodes. Click events are still properly handled by the child Control nodes but no longer propagate to the Node2Ds if the ScrollContainer mouse filter is set to stop or pass. Is there a solution to allow for scrolling behavior and click events with Node2Ds?

Update with code for Node2D input handling:

func _on_Area2D_input_event(viewport, event, shape_idx):
if (event is InputEventMouseButton && event.pressed && !animating):
	var ind = get_parent().get_name().substr(4)
	emit_signal("clicked", ind)

I’m instancing many of these Node2Ds each with a unique name and sending the index as a signal to the parent if the node is clicked.

did you try to set Mouse filter to pass of Control nodes mouse filter inside ScrollContainer?

volzhs | 2021-01-20 15:20

Yes, I tried both pass and ignore. When all parent control nodes were set to ignore, I was able to process inputs on the Node2D but if even one was set to pass the events were no longer received.

theonlydvr | 2021-01-20 15:31

Can you share your code? It sounds like a complicated multi-script scene, but I think sharing your specific event handling in the Node2Ds would be helpful.

DDoop | 2021-01-20 17:54

I’ve added the event handling code as an edit!

theonlydvr | 2021-01-21 04:28

Just read here input events only propagate upwards in the node hierarchy. So looks like you’ll need some restructuring. EDIT: I may still be misunderstanding… I am sorry if this is the case

DDoop | 2021-01-21 16:15

I’m late but I have the same problem and I think I’ll be able to solve it by replacing Area2Ds with Controls (and using their _gui_input instead of collisionobject2d’s _input_event), so they get the input before their parent controls. I haven’t implemented it yet so I can’t 100% say it works well but doing a quick test it seemed to work. It didn’t seem a problem either that I have a scene like this: Control>Control>Node2D>Node2D>Control. Edit: yeah it is working well.

1234ab | 2021-03-25 18:04

:bust_in_silhouette: Reply From: exuin

If you look at the diagram here,
enter image description here
you can see that Area2D input events are handled last. I did find a solution, though.

  1. Set mouse filter to ignore on scrollcontainer
  2. add an area2d and a collisionshape2d to the scrollcontainer (the collisionshape2d will only be inside the scrollcontainer so don’t worry about getting the size exactly right)
  3. connect input_event signal from area2d to scrollcontainer
  4. put this code:

extends ScrollContainer

const SCROLL_SPEED = 12

func _on_Area2D_input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_WHEEL_DOWN:
			scroll_vertical += SCROLL_SPEED
		elif event.button_index == BUTTON_WHEEL_UP:
			scroll_vertical -= SCROLL_SPEED

If you want the scrollcontainer to be able to scroll from anywhere and not just when your mouse is over it, don’t bother with the area2d and just put the code under the _unhandled_input function. If you want a reversed scroll direction (scroll up and the scroll bar goes down) just reverse the if statements.