godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Drag Control nodes with Right Click (or another button) #10837

Open TheYellowArchitect opened 1 day ago

TheYellowArchitect commented 1 day ago

Describe the project you are working on

Online topdown shooter, with inventory system (think warcraft 3) where you can drop items in the floor (3D gameworld)

Describe the problem or limitation you are having in your project

I am using https://github.com/peter-kish/gloot as my inventory system. Dragging items is done in "The Godot Way" by using the 3 following existing functions:

_get_drag_data(at_position: Vector2) -> Variant
_can_drop_data(at_position: Vector2, data: Variant) -> bool
_drop_data(at_position: Vector2, data: Variant) -> void

I can detect if the mouse left click which drags, is no longer pressed, by extending the last 2 functions. Hence, the item is succesfully dropped off the inventory, its memory freed, and a corresponding DroppedItem3D is created in the 3D world.

The problem is the following. Left click is for activating the item. So I would like to make right click start dragging, instead of left click. Just like RTS games like warcraft 3.

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

On Project Settings, there should be a dropdown of inputs which trigger the Control dragging functions. For a starting PR, should be a boolean choice for right click. And hence a new parameter is added as a boolean in the core. But in the future, any input from the input map should be allowed. So that parameter becomes an input instead of a boolean.

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

idk where exactly the code is where it checks for the hardcoded left click, and triggers get_drag_data but I used grep to find all the instances, hope it helps:

./editor/renames_map_3_to_4.cpp:306:    { "get_drag_data", "_get_drag_data" }, // Control
./editor/editor_inspector.cpp:881:Variant EditorProperty::get_drag_data(const Point2 &p_point) {
./editor/animation_track_editor.h:309:  virtual Variant get_drag_data(const Point2 &p_point) override;
./editor/editor_inspector.h:210:    virtual Variant get_drag_data(const Point2 &p_point) override;
./editor/animation_track_editor.cpp:3208:Variant AnimationTrackEdit::get_drag_data(const Point2 &p_point) {
./editor/debugger/editor_debugger_tree.h:74:    virtual Variant get_drag_data(const Point2 &p_point) override;
./editor/debugger/editor_debugger_tree.cpp:269:Variant EditorDebuggerTree::get_drag_data(const Point2 &p_point) {
./editor/editor_audio_buses.cpp:602:Variant EditorAudioBus::get_drag_data(const Point2 &p_point) {
./editor/editor_audio_buses.h:115:  virtual Variant get_drag_data(const Point2 &p_point) override;
./tests/scene/test_viewport.h:99:   virtual Variant get_drag_data(const Point2 &p_point) override {
./scene/gui/line_edit.cpp:698:Variant LineEdit::get_drag_data(const Point2 &p_point) {
./scene/gui/line_edit.cpp:699:  Variant ret = Control::get_drag_data(p_point);
./scene/gui/rich_text_label.h:774:  virtual Variant get_drag_data(const Point2 &p_point) override;
./scene/gui/control.cpp:1928:Variant Control::get_drag_data(const Point2 &p_point) {
./scene/gui/control.cpp:1937:           ERR_FAIL_V_MSG(Variant(), "Error calling forwarded method from 'get_drag_data': " + Variant::get_callable_error_text(data.forward_drag, (const Variant **)vp, 1, ce) + ".");
./scene/gui/rich_text_label.cpp:5422:Variant RichTextLabel::get_drag_data(const Point2 &p_point) {
./scene/gui/rich_text_label.cpp:5423:   Variant ret = Control::get_drag_data(p_point);
./scene/gui/tree.cpp:5460:Variant Tree::get_drag_data(const Point2 &p_point) {
./scene/gui/tree.cpp:5466:  return Control::get_drag_data(p_point);
./scene/gui/tree.h:706: virtual Variant get_drag_data(const Point2 &p_point) override;
./scene/gui/text_edit.h:724:    virtual Variant get_drag_data(const Point2 &p_point) override;
./scene/gui/text_edit.cpp:2974:Variant TextEdit::get_drag_data(const Point2 &p_point) {
./scene/gui/text_edit.cpp:2975: Variant ret = Control::get_drag_data(p_point);
./scene/gui/tab_bar.cpp:1209:Variant TabBar::get_drag_data(const Point2 &p_point) {
./scene/gui/tab_bar.cpp:1211:       return Control::get_drag_data(p_point); // Allow stuff like TabContainer to override it.
./scene/gui/line_edit.h:263:    virtual Variant get_drag_data(const Point2 &p_point) override;
./scene/gui/control.h:527:  virtual Variant get_drag_data(const Point2 &p_point);
./scene/gui/tab_bar.h:184:  Variant get_drag_data(const Point2 &p_point) override;
./scene/main/viewport.cpp:1861:                         gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos - gui.drag_accum));
./editor/renames_map_3_to_4.cpp:306:    { "get_drag_data", "_get_drag_data" }, // Control
./editor/editor_inspector.cpp:881:Variant EditorProperty::get_drag_data(const Point2 &p_point) {
./editor/animation_track_editor.h:309:  virtual Variant get_drag_data(const Point2 &p_point) override;
./editor/editor_inspector.h:210:    virtual Variant get_drag_data(const Point2 &p_point) override;
./editor/animation_track_editor.cpp:3208:Variant AnimationTrackEdit::get_drag_data(const Point2 &p_point) {
./editor/debugger/editor_debugger_tree.h:74:    virtual Variant get_drag_data(const Point2 &p_point) override;
./editor/debugger/editor_debugger_tree.cpp:269:Variant EditorDebuggerTree::get_drag_data(const Point2 &p_point) {
./editor/editor_audio_buses.cpp:602:Variant EditorAudioBus::get_drag_data(const Point2 &p_point) {
./editor/editor_audio_buses.h:115:  virtual Variant get_drag_data(const Point2 &p_point) override;
./tests/scene/test_viewport.h:99:   virtual Variant get_drag_data(const Point2 &p_point) override {
./scene/gui/line_edit.cpp:698:Variant LineEdit::get_drag_data(const Point2 &p_point) {
./scene/gui/line_edit.cpp:699:  Variant ret = Control::get_drag_data(p_point);
./scene/gui/rich_text_label.h:774:  virtual Variant get_drag_data(const Point2 &p_point) override;
./scene/gui/control.cpp:1928:Variant Control::get_drag_data(const Point2 &p_point) {
./scene/gui/control.cpp:1937:           ERR_FAIL_V_MSG(Variant(), "Error calling forwarded method from 'get_drag_data': " + Variant::get_callable_error_text(data.forward_drag, (const Variant **)vp, 1, ce) + ".");
./scene/gui/rich_text_label.cpp:5422:Variant RichTextLabel::get_drag_data(const Point2 &p_point) {
./scene/gui/rich_text_label.cpp:5423:   Variant ret = Control::get_drag_data(p_point);
./scene/gui/tree.cpp:5460:Variant Tree::get_drag_data(const Point2 &p_point) {
./scene/gui/tree.cpp:5466:  return Control::get_drag_data(p_point);
./scene/gui/tree.h:706: virtual Variant get_drag_data(const Point2 &p_point) override;
./scene/gui/text_edit.h:724:    virtual Variant get_drag_data(const Point2 &p_point) override;
./scene/gui/text_edit.cpp:2974:Variant TextEdit::get_drag_data(const Point2 &p_point) {
./scene/gui/text_edit.cpp:2975: Variant ret = Control::get_drag_data(p_point);
./scene/gui/tab_bar.cpp:1209:Variant TabBar::get_drag_data(const Point2 &p_point) {
./scene/gui/tab_bar.cpp:1211:       return Control::get_drag_data(p_point); // Allow stuff like TabContainer to override it.
./scene/gui/line_edit.h:263:    virtual Variant get_drag_data(const Point2 &p_point) override;
./scene/gui/control.h:527:  virtual Variant get_drag_data(const Point2 &p_point);
./scene/gui/tab_bar.h:184:  Variant get_drag_data(const Point2 &p_point) override;
./scene/main/viewport.cpp:1861:                         gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos - gui.drag_accum));

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

Currently, I have found no way, only seen the following hack which I haven't tried: Detect the InputEventMouse and once right click is detected, create a duplicate InputEventMouse and then changes its right click to left click, and insert it into the input event bus. Then delete the original InputEventMouse. This such a hack, its just a bloated solution.

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

This is a missing feature which should be from the start. Why is left-click hardcoded?

RedMser commented 21 hours ago

For anyone interested in implementing this, I believe these are the places to change the input handling:

Drag: https://github.com/godotengine/godot/blob/78801f61da872d3df03d21b36626af6cfb7f2c00/scene/main/viewport.cpp#L1848

Drop: https://github.com/godotengine/godot/blob/78801f61da872d3df03d21b36626af6cfb7f2c00/scene/main/viewport.cpp#L1805-L1812