godotengine / godot-proposals

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

Implement `Viewport.force_drop()` to go along with `Viewport.force_drag()` #10624

Closed GTG3000 closed 2 months ago

GTG3000 commented 2 months ago

Describe the project you are working on

A game featuring tiled inventories. If player clicks on an item, or if player splits a stack and then drops that onto an item, there will be a force_drag call to put that item into "their hand", that is dragging somewhere else.

If the inventory is closed/game is exited, it would be nice not to lose that data, so the player UI has some handling with code that goes kind of like this:

var data = get_viewport().gui_get_drag_data();
if data:
  var fakeInput = InputEventMouseButton.new();
  fakeInput.pressed = false;
  fakeInput.button_index = MOUSE_BUTTON_LEFT;
  Input.parse_input_event(fakeInput);
  ...

Describe the problem or limitation you are having in your project

Forcing the drag/drop data to empty that way works but it was quite unintuitive to figure out, and does look hacky. You shouldn't need to emulate events to work with a gui system like that.

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

I think there must be a counter-part to force_drag that terminates the current drag state and returns the drag data.

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

func on_dragbutton_pressed():
  force_drag({item = item}, item.generate_preview());

func on_inventory_closed():
  var dragData = get_viewport().gui_force_drop();
  if dragData:
    # return item to inventory

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

Yes, you can emulate left mouse button being released after grabbing the data from gui_get_drag_data

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

The change is a little to small to be a stand-alone add-on in my opinion. And the built-in drag-and-drop system could use to be more friendly.

KoBeWi commented 2 months ago

There is unexposed gui_cancel_drag() function in Viewport. If it was exposed, you could use it with gui_get_drag_data() to achieve the same effect. force_drop() sounds like something that's supposed to drop data onto specific Control; cancelling drag and returning data is rather odd IMO.

graydoubt commented 2 months ago

I ran into the same issue. Not sure if I jumped the gun, but I submitted PR https://github.com/godotengine/godot/pull/96614 to expose the Viewport.gui_cancel_drag() method to GDScript. It's a small change and avoids the need for a fake input mouse click that could have side effects.

GTG3000 commented 2 months ago

Yeah, this seems like the perfect solution. Currently dealing with those side effects myself. Thank you!

KoBeWi commented 2 months ago

Solved by https://github.com/godotengine/godot/pull/96614