extends ScrollContainer class_name TouchVerticalContainer const POINTER_VELOCITY_DECAYING_FACTOR: float = 2.5 var is_pointer_dragging := false var pointer_drag_velocity := 0.0 var exclude_controls := [] func _ready(): for it in get_node("controls").get_children(): it = it as Control if exclude_controls.has(it.name): continue var sensor = PointerInputSensor.new() it.add_child(sensor) sensor.name = "sensor" sensor.anchor_right = 1.0 sensor.anchor_bottom = 1.0 sensor.connect("on_press", self, "pointer_input_on_press_handler") sensor.connect("on_drag", self, "pointer_input_on_drag_handler") sensor.connect("on_end_drag", self, "pointer_input_on_end_drag_handler") sensor.connect("on_click", self, "pointer_input_on_click_handler") # it.connect("focus_entered", sensor, "set_visible", [false]) # it.connect("focus_exited", sensor, "set_visible", [true]) func _process(delta: float): # Apply drag movement inertia. if is_pointer_dragging == false && abs(pointer_drag_velocity) > 0.5: pointer_drag_velocity *= clamp((1.0 - POINTER_VELOCITY_DECAYING_FACTOR * delta), 0.0, 1.0) self.scroll_vertical -= pointer_drag_velocity * delta func pointer_input_on_press_handler(pointer: PointerInputSensor.PointerInputData): is_pointer_dragging = true grab_focus() func pointer_input_on_drag_handler(pointer: PointerInputSensor.PointerInputData): is_pointer_dragging = true pointer_drag_velocity = pointer.velocity.y self.scroll_vertical -= pointer.relative_position.y func pointer_input_on_end_drag_handler(pointer: PointerInputSensor.PointerInputData): is_pointer_dragging = false func pointer_input_on_click_handler(pointer: PointerInputSensor.PointerInputData): propagate_click(pointer.target.get_parent(), pointer) # @DAM Maybe replace this with a stack of next items to process approach. func propagate_click(control: Control, pointer: PointerInputSensor.PointerInputData) -> bool: if control is PointerInputSensor || control.mouse_filter == MOUSE_FILTER_IGNORE || control.visible == false: return false var click_processed := false if control.get_global_rect().has_point(pointer.current_position): var children = control.get_children() children.invert() # @DAM Use inverted index for loop to avoid invert() operation. for child in children: if child is Control: click_processed = click_processed || propagate_click(child, pointer) if click_processed == true: break if click_processed == false: if control is CheckBox || control is CheckButton: control.pressed = !control.pressed control.grab_focus() control.emit_signal("button_down") control.emit_signal("pressed") control.emit_signal("button_up") click_processed = true pointer.target.visible = false control.connect("focus_exited", pointer.target, "set_visible", [true]) return click_processed