aboutsummaryrefslogtreecommitdiff
path: root/touch_vertical_container/touch_vertical_container.gd
blob: 4633c64699386534a7b79e76f419c6c0633ae74f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
extends ScrollContainer
class_name TouchVerticalContainer

const POINTER_VELOCITY_DECAYING_FACTOR: float = PI
const POINTER_VELOCITY_BOOST_FACTOR: float = 1.25

var is_pointer_dragging		:= false
var pointer_drag_velocity	:= 0.0
var when_last_dragged		:= 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")
		sensor.connect("on_scroll", self, "pointer_input_on_scroll_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)
	pointer_drag_velocity = pointer.velocity.y if reported_velocity_abs > relative_velocity_abs else relative_velocity
	self.scroll_vertical -= pointer.relative_position.y
	when_last_dragged = OS.get_ticks_msec()


func pointer_input_on_end_drag_handler(pointer: PointerInputSensor.PointerInputData):
	is_pointer_dragging = false
	if OS.get_ticks_msec() - when_last_dragged > 20:
		pointer_drag_velocity = 0.0
	else:
		pointer_drag_velocity *= POINTER_VELOCITY_BOOST_FACTOR


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


func pointer_input_on_scroll_handler(pointer: PointerInputSensor.PointerInputData):
	var target := self
	target._gui_input(pointer.event)