From 5b863fdc25848817ef11f0c1a33ef45a4160aa2c Mon Sep 17 00:00:00 2001 From: dam Date: Mon, 27 Dec 2021 03:31:03 +0000 Subject: Allow to scroll database screen without selecting item on touch-down. --- fonts/font_regular.tres | 2 +- logic/database.gd | 95 ++++++---------------------------- logic/stage.gd | 8 --- main.tscn | 12 ++++- test_input.gd | 42 +++++++++++++++ test_input.tscn | 58 +++++++++++++++++++++ touch_scroll.gd | 134 ++++++++++++++++++++++++++++-------------------- 7 files changed, 207 insertions(+), 144 deletions(-) create mode 100644 test_input.gd create mode 100644 test_input.tscn diff --git a/fonts/font_regular.tres b/fonts/font_regular.tres index 095114d..01b4567 100644 --- a/fonts/font_regular.tres +++ b/fonts/font_regular.tres @@ -3,6 +3,6 @@ [ext_resource path="res://fonts/B612Mono-Regular.ttf" type="DynamicFontData" id=1] [resource] -size = 34 +size = 32 use_filter = true font_data = ExtResource( 1 ) diff --git a/logic/database.gd b/logic/database.gd index 5f91c12..ea02324 100644 --- a/logic/database.gd +++ b/logic/database.gd @@ -54,6 +54,9 @@ func _ready(): func _notification(what: int): + if visible == false: + return + if what == MainLoop.NOTIFICATION_WM_GO_BACK_REQUEST: if selected_idx >= 0: clear_selection() @@ -61,22 +64,6 @@ func _notification(what: int): get_tree().quit() -# @DAM Testing -#var last_event -#var bypass: bool = false -#func _gui_input(event: InputEvent): -# if bypass == false: -# if event is InputEventScreenTouch && event.is_pressed(): -# accept_event() -# last_event = event -# elif event is InputEventScreenTouch && event.is_pressed() == false: -# bypass = true -# get_tree().input_event(event) -# bypass = false -# else: -# var x = 3 - - func get_entry_view(database_entry: Dictionary) -> String: return "%6s | %6s | %s" % [database_entry.process_id, database_entry.surgery_id, get_entry_date(database_entry)] @@ -102,6 +89,7 @@ func delete_action(): db.remove(selected_idx) self.remove_item(selected_idx) + selected_idx = -1 store_database() @@ -122,15 +110,25 @@ func add_action(): stage.set_stage(staged) +func scroll_down(): + get_v_scroll().value = get_v_scroll().max_value + + func save(database_entry: Dictionary): database_entry = instance_entry(database_entry) # @DAM Maybe we could not be creating endless dictionaries? + var next_selected_idx: int if staged_idx >= 0: db[staged_idx] = database_entry - set_item_text(staged_idx, get_entry_view(database_entry)) + next_selected_idx = staged_idx else: db.append(database_entry) add_item(get_entry_view(database_entry)) + call_deferred("scroll_down") + next_selected_idx = db.size() - 1 + store_database() + select(next_selected_idx) + item_selected(next_selected_idx) # Calling "select" does not trigger the "item_selected" signal. staged_idx = -1 self.visible = true @@ -254,7 +252,7 @@ static func set_entry_date(entry: Dictionary, date: String): func fake_database(): db.resize(0) - for idx in range(50): + for idx in range(500): var date_year = 1 + int(float(idx) / 365.0) var date_month = idx % 12 var date_day = idx % 365 @@ -264,64 +262,3 @@ func fake_database(): "date": "%04d-%02d-%02d" % [date_year, date_month, date_day] })) - - - - - - -# @DAM Testing. -export(float) var drag_threshold = 5 - -onready var touch_enabled = OS.has_touchscreen_ui_hint() -onready var v_scroll = 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 _gui_input(event): - - if event is InputEventScreenDrag: - self.v_scroll.value -= event.relative.y - - return - if not visible: - return - - 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 - - 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 - accept_event() - # 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) diff --git a/logic/stage.gd b/logic/stage.gd index 207b451..ac5e9aa 100644 --- a/logic/stage.gd +++ b/logic/stage.gd @@ -100,11 +100,3 @@ func _notification(what: int): discard_action() -func _unhandled_input(event): - get_node("/root/main/debug").text += "%s\n" % event.to_string() - - -func _unhandled_key_input(event): - get_node("/root/main/debug").text += "%s\n" % event.to_string() - - diff --git a/main.tscn b/main.tscn index 4096c59..b584c88 100644 --- a/main.tscn +++ b/main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=10 format=2] +[gd_scene load_steps=11 format=2] [ext_resource path="res://main.gd" type="Script" id=1] [ext_resource path="res://date_picker/date_picker.tscn" type="PackedScene" id=2] @@ -9,6 +9,7 @@ [ext_resource path="res://icons/add.png" type="Texture" id=7] [ext_resource path="res://icons/delete.png" type="Texture" id=8] [ext_resource path="res://logic/stage.gd" type="Script" id=9] +[ext_resource path="res://touch_scroll.gd" type="Script" id=10] [node name="main" type="Control"] anchor_right = 1.0 @@ -28,6 +29,15 @@ __meta__ = { "_edit_use_anchors_": false } +[node name="touch_scroll" type="Control" parent="database"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_right = -8.0 +script = ExtResource( 10 ) +__meta__ = { +"_edit_use_anchors_": false +} + [node name="actions" type="VBoxContainer" parent="database"] anchor_left = 1.0 anchor_top = 1.0 diff --git a/test_input.gd b/test_input.gd new file mode 100644 index 0000000..bae409d --- /dev/null +++ b/test_input.gd @@ -0,0 +1,42 @@ +extends ColorRect + +onready var debug: RichTextLabel = get_node("/root/main/debug") + + +func _gui_input(event): +# if name == "a": +# accept_event() +# if name == "b" : #&& (event is InputEventScreenTouch): +# if name == "b": +# get_tree().set_input_as_handled() +# accept_event() +# if name == "b" && event is InputEventScreenTouch && event.is_pressed() == false: +# simulate_click() +# call_deferred("simulate_click") + + if event is InputEventScreenTouch || event is InputEventMouseButton: + debug.text += "%s> %-24s\t:\t%s\n" % [name, event.get_class(), event.is_pressed()] + else: + debug.text += "%s> %s\n" % [name, event.get_class()] + + +func simulate_click(): + var event_touch = InputEventScreenTouch.new() + event_touch.index = 0 + event_touch.position = self.get_global_mouse_position() + + var event_mouse = InputEventMouseButton.new() + event_mouse.button_index = BUTTON_LEFT + event_mouse.button_mask = BUTTON_MASK_LEFT + event_mouse.position = self.get_global_mouse_position() + + self.mouse_filter = Control.MOUSE_FILTER_IGNORE + event_mouse.pressed = true + event_touch.pressed = true +# Input.parse_input_event(event_mouse) + Input.parse_input_event(event_touch) + event_mouse.pressed = false + event_touch.pressed = false +# Input.parse_input_event(event_mouse) + Input.parse_input_event(event_touch) + self.mouse_filter = Control.MOUSE_FILTER_STOP diff --git a/test_input.tscn b/test_input.tscn new file mode 100644 index 0000000..4b507fe --- /dev/null +++ b/test_input.tscn @@ -0,0 +1,58 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://test_input.gd" type="Script" id=1] +[ext_resource path="res://fonts/font_regular.tres" type="DynamicFont" id=2] + +[node name="main" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="debug" type="RichTextLabel" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 2 +custom_fonts/normal_font = ExtResource( 2 ) +scroll_following = true +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="a" type="ColorRect" parent="."] +anchor_right = 0.66 +anchor_bottom = 0.66 +color = Color( 1, 0, 0, 0.196078 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="b" type="ColorRect" parent="a"] +anchor_left = 0.5 +anchor_right = 1.502 +anchor_bottom = 1.0 +mouse_filter = 1 +color = Color( 0, 1, 0, 0.196078 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="c" type="ColorRect" parent="."] +anchor_top = 0.333 +anchor_right = 0.666 +anchor_bottom = 1.0 +color = Color( 0, 0, 1, 0.196078 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="d" type="ColorRect" parent="c"] +anchor_left = 0.5 +anchor_right = 1.502 +anchor_bottom = 1.0 +color = Color( 1, 1, 1, 0.196078 ) +script = ExtResource( 1 ) 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) -- cgit v1.2.3