The purpose is to make handles for editing 3D meshes, and my desired behavior is quite the same as the little handles that you find in Godot's CollisionShapes, to adjust their extents.
Below is the code I have so far in the Area's script. The area is ray pickable, and I'm using input events as they seem straightforward and easy to setup, and it seems like this might be achievable with that.
As it is though, I can only drag the thing if I move the mouse slowly, or else it goes outside the Area and it stops receiving input events. I managed to make it so I can move the mouse outside the Area a little bit, but it has problems, as it doesn't reset the state (frame) of the Sprite, at least in the way I've coded it. It's suppose to work a bit like a button, so the Sprite has 3 frames for normal state, clicked and hovered.
The scene tree is just an Area, with a billboard Sprite3D (for the icon) and a sphere CollisionShape. Its parent is a spatial, which is the 3D view scene of my app.
It might help if someone could point me to the files in Godot's own source code where the CollisionShape handles are implemented, so I could see how they did this. I've been trying to find that, but so far no luck...
extends Area
# <- trying to make the the code more readable here, as it's not preserving my empty lines
onready var view = get_parent().get_parent().get_parent()
onready var sprite = get_node("Sprite3D")
#
enum {NONE, HOVERED, CLICKED}
var state
#
func _ready():
switch_state(NONE)
#
func switch_state(st):
if st != state:
state = st
sprite.set_frame(state)
#
func _on_TopHandle_input_event( camera, event, click_pos, click_normal, shape_idx ):
if event.type==InputEvent.MOUSE_MOTION and state == CLICKED:
# it's only supposed to move up and down, in y axis
set_translation(Vector3(get_translation().x, click_pos.y, get_translation().z))
#
if event.is_action_pressed("editor_select"):
switch_state(CLICKED)
elif event.is_action_released("editor_select"):
switch_state(HOVERED)
#
func _on_TopHandle_mouse_enter():
switch_state(HOVERED)
#
func _on_TopHandle_mouse_exit():
# my attempt at making it not let go until I release the mouse button
if state != CLICKED:
switch_state(NONE)