godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Add `drag_data_rejected` and `drag_data_accepted` virtual methods to Control node #3195

Open ghsoares opened 3 years ago

ghsoares commented 3 years ago

Describe the project you are working on

A inventory system with draggable items

Describe the problem or limitation you are having in your project

Godot's Control node provides some helpful overridable methods to change dragging behaviour, where you can use get_drag_data to return a data to be dragged and dropped somewhere else, can_drop_data that controls if a drag data can be dropped in this Control node and drop_data that is called when the drag data is dropped into this node. The problem is that there isn't no easy way to know if a drag data was refused (drag data didn't drop in a Control node) or accepted (drag data did drop in a Control node). I may be wrong, but I didn't find these methods reading on documentation

Describe the feature / enhancement and how it helps to overcome the problem or limitation

My suggestion is to add two overridable methods: drag_data_rejected and drag_data_accepted, which are called whenever the drag data returned from this node was dropped in another node. The first method is called with the drag data rejected, and the second method is called with drag data accepted, the node which the data was dropped and the position the data was dropped.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

It would work like this:

#NodeA.gd
func get_drag_data(pos):
    return {"msg": "Hello!"}

func drag_data_rejected(data) -> void:
    print("Data was rejected")

func drag_data_accepted(data, dropped_node, pos) -> void:
    print(dropped_node.name + " accepted the drag data!")
    print(data.msg)
    #"NodeB accepted the drag data!"
    #"Hey!"

#NodeB.gd
func drop_data(pos, data):
    pos.msg = "Hey!"

If this enhancement will not be used often, can it be worked around with a few lines of script?

For the second method, drag_data_accepted you could just set the reference of the node that created the data inside the data, something like this:

func get_drag_data(pos):
    return {"msg": "Hello!", "messenger": self}

So when the data drops in a node, this node could call a function in the messenger that the data was accepted, but this don't work for rejected data, because there is no way to call the messenger if the data was rejected in the first place.

Is there a reason why this should be core and not an add-on in the asset library?

Because it seens not easily possible to do this with a script or addon, it requires to change the dragging behaviour on core.

KoBeWi commented 3 years ago

It could be better as a signal. Also drag_data_accepted() is basically drop_data_fw().

nagyv commented 1 year ago

I came here to write a proposal for a signal to notifiy the system about

Such signal would allow managing the global (higher level) state of the system.

KoBeWi commented 1 year ago

Check NOTIFICATION_DRAG_BEGIN and NOTIFICATION_DRAG_END.

KoBeWi commented 1 year ago

To elaborate more, NOTIFICATION_DRAG_BEGIN and NOTIFICATION_DRAG_END is received by every Control when a drag begins or ends. During NOTIFICATION_DRAG_END you can call is_drag_successful() to check if the drag was accepted or not. It's not signals, but provides all the functionality requested here. Check the documentation, the usage is properly described.

@ghsoares Does it resolve your problem?