Skip to content

Commit

Permalink
add touch screen drag&drop support
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeSchulze committed Aug 16, 2024
1 parent 2a06604 commit 8a4cc29
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 50 deletions.
33 changes: 29 additions & 4 deletions addons/gdUnit4/src/GdUnitSceneRunner.gd
Original file line number Diff line number Diff line change
Expand Up @@ -131,31 +131,56 @@ func simulate_mouse_button_release(buttonIndex :MouseButton) -> GdUnitSceneRunne
return self



## Simulates a screen touch is pressed.[br]
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.[br]
## [member double_tap] : If true, the touch's state is a double tab.
@warning_ignore("unused_parameter")
func simulate_screen_touch_pressed(index :int, double_tap := false) -> GdUnitSceneRunner:
return self


## Simulates a screen touch is press.[br]
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.[br]
## [member double_tap] : If true, the touch's state is a double tab.
@warning_ignore("unused_parameter")
func simulate_screen_touch_press(index :int, double_tap := false) -> GdUnitSceneRunner:
return self


## Simulates a screen touch is released.[br]
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.[br]
## [member double_tap] : If true, the touch's state is a double tab.
@warning_ignore("unused_parameter")
func simulate_screen_touch_release(index :int, double_tap := false) -> GdUnitSceneRunner:
return self


## Starts the simulate of drag&drop at given position.[br]
## [member index] : The touch index in the case of a multi-touch event. One index = one finger.[br]
## [member index] : The starting position to drag
@warning_ignore("unused_parameter")
func simulate_screen_touch_drag_begin(index :int, position :Vector2) -> GdUnitSceneRunner:
return self


## Simulates a touch screen drag&drop to the relative coordinates (offset).[br]
## [color=yellow]You must use [b]await[/b] to wait until the simulated drag&drop is complete.[/color][br]
## [br]
## [member relative] : The relative position, indicating the drag&drop position offset.[br]
## [member time] : The time to move to the relative position in seconds (default is 1 second).[br]
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
## [codeblock]
## func test_touch_drag_drop():
## var runner = scene_runner("res://scenes/simple_scene.tscn")
## runner.simulate_screen_touch_drag_begin(1, (Vector2(50, 50))
## await runner.simulate_screen_touch_drag_relative(1, Vector2(100,100))
## [/codeblock]
@warning_ignore("unused_parameter")
func simulate_screen_touch_drag_relative(index :int, relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner:
await Engine.get_main_loop().process_frame
return self


## Sets how fast or slow the scene simulation is processed (clock ticks versus the real).[br]
## It defaults to 1.0. A value of 2.0 means the game moves twice as fast as real life,
## whilst a value of 0.5 means the game moves at half the regular speed.
Expand Down
70 changes: 63 additions & 7 deletions addons/gdUnit4/src/core/GdUnitSceneRunnerImpl.gd
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var _mouse_button_on_press := []
var _key_on_press := []
var _action_on_press := []
var _curent_mouse_position :Vector2
var _current_touch_drag_position :Vector2

# time factor settings
var _time_factor := 1.0
Expand Down Expand Up @@ -250,27 +251,82 @@ func simulate_screen_touch_pressed(index :int, double_tap := false) -> GdUnitSce


func simulate_screen_touch_press(index :int, double_tap := false) -> GdUnitSceneRunner:
# we need to simulate in addition to the touch the mouse events
simulate_mouse_button_press(MOUSE_BUTTON_LEFT)
# push touch press event at position
var event := InputEventScreenTouch.new()
event.window_id = scene().get_viewport().get_window_id()
event.index = index
event.position = get_mouse_position()
event.double_tap = double_tap
event.pressed = true
event.window_id = scene().get_viewport().get_window_id()
if ProjectSettings.get_setting("input_devices/pointing/emulate_touch_from_mouse") == true:
_mouse_button_on_press.append(index)
return _handle_input_event(event)
_current_scene.get_viewport().push_input(event)
return self


func simulate_screen_touch_release(index :int, double_tap := false) -> GdUnitSceneRunner:
# we need to simulate in addition to the touch the mouse events
simulate_mouse_button_release(MOUSE_BUTTON_LEFT)
# push touch release event at position
var event := InputEventScreenTouch.new()
event.window_id = scene().get_viewport().get_window_id()
event.index = index
event.position = get_mouse_position()
event.pressed = false
event.double_tap = _last_input_event.double_tap if _last_input_event is InputEventScreenTouch else double_tap
_current_scene.get_viewport().push_input(event)
return self


func simulate_screen_touch_drag_begin(index :int, position :Vector2) -> GdUnitSceneRunner:
# we need to simulate in addition to the touch the mouse events
set_mouse_pos(position)
simulate_mouse_button_press(MOUSE_BUTTON_LEFT)

# start drag by touch it at position
var event := InputEventScreenTouch.new()
event.window_id = scene().get_viewport().get_window_id()
if ProjectSettings.get_setting("input_devices/pointing/emulate_touch_from_mouse") == true:
_mouse_button_on_press.erase(index)
return _handle_input_event(event)
event.index = index
event.position = position
event.pressed = true
_current_touch_drag_position = position
_current_scene.get_viewport().push_input(event)
return self


func simulate_screen_touch_drag_relative(index :int, relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner:
# start draging
var event := InputEventScreenDrag.new()
event.window_id = scene().get_viewport().get_window_id()
event.index = index
event.position = _current_touch_drag_position
event.pressure = 1.0

var tween := _scene_tree().create_tween()
var final_position := _current_touch_drag_position + relative
tween.tween_property(self, "_current_touch_drag_position", final_position, time).set_trans(trans_type)
tween.play()

while not _current_touch_drag_position.is_equal_approx(final_position):
# we need to simulate in addition to the drag the mouse move events
simulate_mouse_move(event.position)
# send touche drag event to new position
event.relative = _current_touch_drag_position - event.position
event.velocity = event.relative / _scene_tree().root.get_process_delta_time()
event.position = _current_touch_drag_position
_current_scene.get_viewport().push_input(event)
await _scene_tree().process_frame

# finaly drop it
simulate_mouse_button_release(MOUSE_BUTTON_LEFT)
var touch_drop_event := InputEventScreenTouch.new()
touch_drop_event.window_id = event.window_id
touch_drop_event.index = event.index
touch_drop_event.position = event.position
touch_drop_event.pressed = false
_current_scene.get_viewport().push_input(touch_drop_event)
await _scene_tree().process_frame
return self


func set_time_factor(time_factor := 1.0) -> GdUnitSceneRunner:
Expand Down
34 changes: 0 additions & 34 deletions addons/gdUnit4/test/core/GdUnitSceneRunnerInputEventTest.gd
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ func before_test() -> void:
reset(_scene_spy)


func after_test() -> void:
set_mouse_as_touch_device(false)


# asserts to action strings
func assert_initial_action_state() -> void:
for action in InputMap.get_actions():
Expand Down Expand Up @@ -568,9 +564,6 @@ func test_simulate_mouse_button_press_and_release() -> void:


func test_simulate_screen_touch_press() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate one finger is touching the screen
_runner.simulate_screen_touch_press(1)
Expand All @@ -588,9 +581,6 @@ func test_simulate_screen_touch_press() -> void:


func test_simulate_screen_touch_press_double_click() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that two fingers have touched the touch screen as a double click
_runner.simulate_screen_touch_press(2, true)
Expand All @@ -608,9 +598,6 @@ func test_simulate_screen_touch_press_double_click() -> void:


func test_simulate_screen_touch_pressed() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that a finger has touched the screen
_runner.simulate_screen_touch_pressed(1)
Expand All @@ -630,31 +617,17 @@ func test_simulate_screen_touch_pressed() -> void:


func test_simulate_screen_touch_pressed_double_click() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that two fingers have touched the touch screen as a double click
_runner.simulate_screen_touch_pressed(2, true)
await await_idle_frame()

# verify the InputEventScreenTouch is emitted
var event := InputEventScreenTouch.new()
event.position = Vector2(683, 339)
event.pressed = true
event.index = 2
event.double_tap = true
verify(_scene_spy, 1)._input(event)
event.pressed = false
verify(_scene_spy, 1)._input(event)
verify(_scene_spy, 1)._on_touch_1_pressed()
verify(_scene_spy, 1)._on_touch_1_released()


func test_simulate_screen_touch_release() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that the finger no longer touches the screen
_runner.simulate_screen_touch_release(1)
Expand All @@ -671,9 +644,6 @@ func test_simulate_screen_touch_release() -> void:


func test_simulate_screen_touch_release_double_click() -> void:
# we need to simmulate the mouse as a touch device
set_mouse_as_touch_device(true)

_runner.set_mouse_pos(Vector2(683, 339))
# simulate that two fingers no longer touches the screen as a double click
_runner.simulate_screen_touch_release(2, true)
Expand All @@ -687,7 +657,3 @@ func test_simulate_screen_touch_release_double_click() -> void:
event.double_tap = true
verify(_scene_spy, 1)._input(event)
verify(_scene_spy, 0)._on_touch_1_pressed()


func set_mouse_as_touch_device(enabled := false) -> void:
ProjectSettings.set_setting("input_devices/pointing/emulate_touch_from_mouse", enabled)
28 changes: 25 additions & 3 deletions addons/gdUnit4/test/core/GdUnitSceneRunnerTest.gd
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,9 @@ func test_mouse_drag_and_drop() -> void:

var save_mouse_pos := get_tree().root.get_mouse_position()
# set inital mouse pos over the left slot
var mouse_pos := slot_left.global_position + Vector2(10, 10)
var mouse_pos := slot_left.global_position + Vector2(50, 50)
runner.set_mouse_pos(mouse_pos)
await await_millis(1000)
#await await_millis(1000)

await await_idle_frame()
var event := InputEventMouseMotion.new()
Expand All @@ -362,14 +362,36 @@ func test_mouse_drag_and_drop() -> void:

# start drag&drop to left pannel
for i in 20:
runner.simulate_mouse_move(mouse_pos + Vector2(i*.5*i, 0))
runner.simulate_mouse_move(mouse_pos + Vector2(i*.4*i, 0))
await await_millis(40)

runner.simulate_mouse_button_release(MOUSE_BUTTON_LEFT)
await await_idle_frame()
assert_that(slot_right.texture).is_equal(slot_left.texture)


func test_touch_drag_and_drop_relative() -> void:
var spy_scene :Variant = spy("res://addons/gdUnit4/test/core/resources/scenes/drag_and_drop/DragAndDropTestScene.tscn")
var runner := scene_runner(spy_scene)

var slot_left :TextureRect = $"/root/DragAndDropScene/left/TextureRect"
var slot_right :TextureRect = $"/root/DragAndDropScene/right/TextureRect"
var mouse_pos := slot_left.global_position + Vector2(50, 50)

# set inital mouse pos over the left touch button
runner.simulate_screen_touch_drag_begin(1, mouse_pos)
await await_idle_frame()
assert_bool(Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)).is_true()
assert_that(get_tree().root.get_mouse_position()).is_equal(mouse_pos)

# enable only for a small wait to for manual testing
#await await_millis(1000)

# start drag&drop to right touch button
await runner.simulate_screen_touch_drag_relative(1, Vector2(140, 0))
assert_that(slot_right.texture).is_equal(slot_left.texture)


func test_runner_GD_356() -> void:
# to avoid reporting the expected push_error as test failure we disable it
ProjectSettings.set_setting(GdUnitSettings.REPORT_PUSH_ERRORS, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ func _drop_data(_position: Vector2, data :Variant) -> void:

# Virtual method to be implemented by the user. Use this method to process and accept inputs on UI elements. See accept_event().
func _gui_input(_event :InputEvent) -> void:
#prints("Panel _gui_input", _event.as_text())
#if _event is InputEventScreenDrag:
# prints(" InputEventScreenDrag", _event.as_text())
#if _event is InputEventScreenTouch:
# prints(" InputEventScreenTouch", _event.as_text())
#if _event is InputEventMouseButton:
# prints("Panel _gui_input", _event.as_text())
pass
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
[gd_scene load_steps=2 format=3 uid="uid://ca2rr3dan4vvw"]
[gd_scene load_steps=3 format=3 uid="uid://ca2rr3dan4vvw"]

[ext_resource type="Script" path="res://addons/gdUnit4/test/core/resources/scenes/drag_and_drop/DragAndDropControl.gd" id="1"]

[sub_resource type="RectangleShape2D" id="RectangleShape2D_s2qi1"]
size = Vector2(110, 110)

[node name="Panel" type="PanelContainer"]
offset_left = 245.0
offset_top = 232.0
Expand All @@ -14,3 +17,7 @@ script = ExtResource("1")
[node name="TextureRect" type="TextureRect" parent="."]
layout_mode = 2
expand_mode = 1

[node name="touch_area" type="TouchScreenButton" parent="TextureRect"]
position = Vector2(52, 52)
shape = SubResource("RectangleShape2D_s2qi1")
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ func _gui_input(_event :InputEvent) -> void:
func _on_Button_button_down() -> void:
# print("BUTTON DOWN")
pass


func _on_quit_pressed() -> void:
get_tree().quit()
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,13 @@ offset_bottom = 200.0
text = "BUTTON"
metadata/_edit_use_anchors_ = true

[node name="Button2" type="Button" parent="."]
layout_mode = 0
offset_left = 593.0
offset_top = 201.0
offset_right = 700.0
offset_bottom = 239.0
text = "QUIT"

[connection signal="button_down" from="Button" to="." method="_on_Button_button_down"]
[connection signal="pressed" from="Button2" to="." method="_on_quit_pressed"]

0 comments on commit 8a4cc29

Please sign in to comment.