extends ScrollContainer class_name TouchVerticalContainer const POINTER_VELOCITY_DECAYING_FACTOR: float = 2.5 const POINTER_VELOCITY_BOOST_FACTOR: float = 1.5 var is_pointer_dragging := false var pointer_drag_velocity := 0.0 var exclude_controls := [] onready var controls = get_node("controls") func _ready(): assert(controls != null, "TouchVerticalContainer failed to get 'controls' node.") var item_list_separation := float(controls.get_constant("separation")) for it in 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.margin_top = - item_list_separation / 2.0 sensor.margin_bottom = item_list_separation / 2.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") 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 var reported_velocity_abs := abs(pointer.velocity.y) var relative_velocity := pointer.relative_position.y * Engine.get_frames_per_second() var relative_velocity_abs := abs(relative_velocity) var max_velocity := pointer.velocity.y if reported_velocity_abs > relative_velocity_abs else relative_velocity pointer_drag_velocity = max_velocity * POINTER_VELOCITY_BOOST_FACTOR 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): # Get last leaf node. var root := pointer.target.get_parent() as Control var leaf := root as Node while leaf.get_child_count() > 0: leaf = leaf.get_child(leaf.get_child_count() - 1) # Navigate backwards from leaf to root until we find a node accepting the input. var tried_leaf_as_root := false while leaf != root || tried_leaf_as_root == false: tried_leaf_as_root = leaf == root # Allow a final iteration cycle when leaf reaches root. var node := leaf if node is PointerInputSensor \ || node is Control == false \ || node.mouse_filter == MOUSE_FILTER_IGNORE \ || node.visible == false \ || node.get_global_rect().has_point(pointer.current_position) == false: # Get next node to be processed. var leaf_index_in_parent := leaf.get_position_in_parent() var parent := leaf.get_parent() if leaf_index_in_parent == 0: leaf = parent else: leaf = parent.get_child(leaf_index_in_parent - 1) # Drill down into the new tree branch. while leaf.get_child_count() > 0: leaf = leaf.get_child(leaf.get_child_count() - 1) continue var control: Control = node 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") control.connect("focus_exited", pointer.target, "set_visible", [true], CONNECT_ONESHOT) pointer.target.visible = false break