aboutsummaryrefslogtreecommitdiff
path: root/touch_scroll.gd
diff options
context:
space:
mode:
Diffstat (limited to 'touch_scroll.gd')
-rw-r--r--touch_scroll.gd134
1 files changed, 79 insertions, 55 deletions
diff --git a/touch_scroll.gd b/touch_scroll.gd
index ea92087..f2aeca7 100644
--- a/touch_scroll.gd
+++ b/touch_scroll.gd
@@ -1,66 +1,90 @@
extends Control
+const VELOCITY_DECAYING_FACTOR: float = 5.5
+const DRAG_THRESHOLD_CM: float = 0.250
-func _gui_input(event: InputEvent):
-#func _input(event: InputEvent):
-# return
- if event is InputEventScreenDrag:
- self.v_scroll.value -= event.relative.y
-# accept_event()
+var pointer: Dictionary
+var anchor: float
+var offset: float
+var screen_dpcm: float
+
+onready var target: Control = get_parent()
+onready var target_scroll: VScrollBar = get_parent().get_v_scroll()
+
+
+func _ready():
+ pointer = {
+ index = -1,
+ initial_position = Vector2.ZERO,
+ current_position = Vector2.ZERO,
+ velocity = Vector2.ZERO,
+ was_dragged = false,
+ is_active = false,
+ }
+ screen_dpcm = float(OS.get_screen_dpi()) / 2.54
-#func _gui_input(event):
-# accept_event()
-# get_tree().set_input_as_handled()
-# if event is InputEventScreenDrag:
-# get_parent().v_scroll.value -= event.relative.y
+func _process(delta: float):
+ if pointer.is_active:
+ var dragged_distance: float = - (pointer.current_position.y - pointer.initial_position.y)
+ offset = anchor + dragged_distance
+ self.target_scroll.value = offset
+ elif pointer.velocity.length() > 0.5:
+ pointer.velocity *= clamp((1.0 - VELOCITY_DECAYING_FACTOR * delta), 0.0, 1.0)
+ offset -= pointer.velocity.y * delta
+ self.target_scroll.value = offset
-export(float) var drag_threshold = 5
-onready var touch_enabled = OS.has_touchscreen_ui_hint()
-onready var v_scroll = get_parent().get_v_scroll()
-var dragging = false
-var pressed = false
-var last_event
-# must be _input, as _gui_input has bugs, with no touch.pressed = false events
-# see: https://github.com/godotengine/godot/issues/16761
-func _input_disabled(event):
-#func _gui_input(event):
+func _gui_input(event: InputEvent):
+
+ # @DAM A bug on GODOT-3.X makes events from non-mouse-emulated pointers (index > 0) unreliable.
+ if event is InputEventScreenTouch || event is InputEventScreenDrag:
+ if event.index != 0:
+ return
+
+ if event is InputEventScreenTouch && (pointer.is_active == false || pointer.index == event.index):
+ var touch := event as InputEventScreenTouch
+ pointer.is_active = event.pressed
+ pointer.current_position = touch.position
+ if pointer.is_active:
+ pointer.index = touch.index
+ pointer.initial_position = touch.position
+ anchor = self.target_scroll.value
+ else:
+ if pointer.was_dragged == false: # Click detected.
+ simulate_gui_click()
+ pointer.index = -1
+ pointer.was_dragged = false
- if not visible:
- return
+ if event is InputEventScreenDrag && event.index == pointer.index:
+ var drag := event as InputEventScreenDrag
+ pointer.current_position = drag.position
+ pointer.velocity = drag.speed
+ if pointer.current_position.distance_to(pointer.initial_position) / screen_dpcm > DRAG_THRESHOLD_CM:
+ pointer.was_dragged = true
- if not touch_enabled:
- return
- if event is InputEventScreenDrag:
- accept_event()
- if event.speed == Vector2():
- # we're on a device and speed is broken
- # see: https://github.com/godotengine/godot/issues/3623
- event.speed = event.relative
- if abs(event.speed.y) >= drag_threshold:
- # scroll the list
- dragging = true
- v_scroll.value -= event.relative.y
- return
+func simulate_gui_click():
+
+ var position := self.get_global_mouse_position() - target.rect_global_position
+
+ var event_touch := InputEventScreenTouch.new()
+ event_touch.index = 0
+ event_touch.position = position
+
+ var event_mouse := InputEventMouseButton.new()
+ event_mouse.button_index = BUTTON_LEFT
+ event_mouse.button_mask = BUTTON_MASK_LEFT
+ event_mouse.position = position
+
+ event_mouse.pressed = true
+ event_touch.pressed = true
+ target._gui_input(event_mouse)
+ target._gui_input(event_touch)
+
+ event_mouse.pressed = false
+ event_touch.pressed = false
+ target._gui_input(event_mouse)
+ target._gui_input(event_touch)
+
- if event is InputEventScreenTouch:
- if event.index == 0:
- accept_event()
- if dragging && event.pressed == false:
- # prints("end drag")
- dragging = false
- pressed = false
- else:
- if event.pressed && pressed == false:
- # prints("touch start")
- pressed = true
- # TODO: prevent select highlight
- elif !event.pressed && pressed == true:
- # prints("touch end and accept")
- pressed = false
- var ev = InputEventAction.new()
- ev.action = "ui_accept"
- ev.pressed = true
- Input.parse_input_event(ev)