Browse Source

Change set_drag_forwarding() to use callables.

* This solution is much cleaner than the one in 3.x thanks to the use of callables.
* Works without issues in any language (no need to worry about camel or snake case).
* Editor code uses a compatibility function (too much work to redo).

Fixes #59899
Juan Linietsky 2 years ago
parent
commit
e6a4debede

+ 6 - 60
doc/classes/Control.xml

@@ -780,67 +780,13 @@
 		</method>
 		</method>
 		<method name="set_drag_forwarding">
 		<method name="set_drag_forwarding">
 			<return type="void" />
 			<return type="void" />
-			<param index="0" name="target" type="Object" />
+			<param index="0" name="drag_func" type="Callable" />
+			<param index="1" name="can_drop_func" type="Callable" />
+			<param index="2" name="drop_func" type="Callable" />
 			<description>
 			<description>
-				Forwards the handling of this control's drag and drop to [param target] object.
-				Forwarding can be implemented in the target object similar to the methods [method _get_drag_data], [method _can_drop_data], and [method _drop_data] but with two differences:
-				1. The function name must be suffixed with [b]_fw[/b]
-				2. The function must take an extra argument that is the control doing the forwarding
-				[codeblocks]
-				[gdscript]
-				# ThisControl.gd
-				extends Control
-				export(Control) var target_control
-
-				func _ready():
-				    set_drag_forwarding(target_control)
-
-				# TargetControl.gd
-				extends Control
-
-				func _can_drop_data_fw(position, data, from_control):
-				    return true
-
-				func _drop_data_fw(position, data, from_control):
-				    my_handle_data(data) # Your handler method.
-
-				func _get_drag_data_fw(position, from_control):
-				    set_drag_preview(my_preview)
-				    return my_data()
-				[/gdscript]
-				[csharp]
-				// ThisControl.cs
-				public class ThisControl : Control
-				{
-				    [Export]
-				    public Control TargetControl { get; set; }
-				    public override void _Ready()
-				    {
-				        SetDragForwarding(TargetControl);
-				    }
-				}
-
-				// TargetControl.cs
-				public class TargetControl : Control
-				{
-				    public void CanDropDataFw(Vector2 position, object data, Control fromControl)
-				    {
-				        return true;
-				    }
-
-				    public void DropDataFw(Vector2 position, object data, Control fromControl)
-				    {
-				        MyHandleData(data); // Your handler method.
-				    }
-
-				    public void GetDragDataFw(Vector2 position, Control fromControl)
-				    {
-				        SetDragPreview(MyPreview);
-				        return MyData();
-				    }
-				}
-				[/csharp]
-				[/codeblocks]
+				Forwards the handling of this control's [method _get_drag_data],  [method _can_drop_data] and [method _drop_data] virtual functions to delegate callables.
+				For each argument, if not empty, the delegate callable is used, otherwise the local (virtual) function is used.
+				The function format for each callable should be exactly the same as the virtual functions described above.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="set_drag_preview">
 		<method name="set_drag_preview">

+ 1 - 1
editor/action_map_editor.cpp

@@ -578,7 +578,7 @@ ActionMapEditor::ActionMapEditor() {
 	action_tree->connect("button_clicked", callable_mp(this, &ActionMapEditor::_tree_button_pressed));
 	action_tree->connect("button_clicked", callable_mp(this, &ActionMapEditor::_tree_button_pressed));
 	main_vbox->add_child(action_tree);
 	main_vbox->add_child(action_tree);
 
 
-	action_tree->set_drag_forwarding(this);
+	action_tree->set_drag_forwarding_compat(this);
 
 
 	// Adding event dialog
 	// Adding event dialog
 	event_config_dialog = memnew(InputEventConfigurationDialog);
 	event_config_dialog = memnew(InputEventConfigurationDialog);

+ 1 - 1
editor/create_dialog.cpp

@@ -754,7 +754,7 @@ CreateDialog::CreateDialog() {
 	favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected));
 	favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected));
 	favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated));
 	favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated));
 	favorites->add_theme_constant_override("draw_guides", 1);
 	favorites->add_theme_constant_override("draw_guides", 1);
-	favorites->set_drag_forwarding(this);
+	favorites->set_drag_forwarding_compat(this);
 	fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
 	fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
 
 
 	VBoxContainer *rec_vb = memnew(VBoxContainer);
 	VBoxContainer *rec_vb = memnew(VBoxContainer);

+ 1 - 1
editor/editor_audio_buses.cpp

@@ -903,7 +903,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
 	effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited));
 	effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited));
 	effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));
 	effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));
 	effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
 	effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
-	effects->set_drag_forwarding(this);
+	effects->set_drag_forwarding_compat(this);
 	effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb));
 	effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb));
 	effects->set_allow_rmb_select(true);
 	effects->set_allow_rmb_select(true);
 	effects->set_focus_mode(FOCUS_CLICK);
 	effects->set_focus_mode(FOCUS_CLICK);

+ 1 - 1
editor/editor_autoload_settings.cpp

@@ -935,7 +935,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
 	tree->set_select_mode(Tree::SELECT_MULTI);
 	tree->set_select_mode(Tree::SELECT_MULTI);
 	tree->set_allow_reselect(true);
 	tree->set_allow_reselect(true);
 
 
-	tree->set_drag_forwarding(this);
+	tree->set_drag_forwarding_compat(this);
 
 
 	tree->set_columns(4);
 	tree->set_columns(4);
 	tree->set_column_titles_visible(true);
 	tree->set_column_titles_visible(true);

+ 1 - 1
editor/editor_inspector.cpp

@@ -2065,7 +2065,7 @@ void EditorInspectorArray::_setup() {
 		ae.panel = memnew(PanelContainer);
 		ae.panel = memnew(PanelContainer);
 		ae.panel->set_focus_mode(FOCUS_ALL);
 		ae.panel->set_focus_mode(FOCUS_ALL);
 		ae.panel->set_mouse_filter(MOUSE_FILTER_PASS);
 		ae.panel->set_mouse_filter(MOUSE_FILTER_PASS);
-		ae.panel->set_drag_forwarding(this);
+		ae.panel->set_drag_forwarding_compat(this);
 		ae.panel->set_meta("index", begin_array_index + i);
 		ae.panel->set_meta("index", begin_array_index + i);
 		ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
 		ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
 		ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));
 		ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));

+ 2 - 2
editor/editor_properties.cpp

@@ -569,7 +569,7 @@ EditorPropertyPath::EditorPropertyPath() {
 	HBoxContainer *path_hb = memnew(HBoxContainer);
 	HBoxContainer *path_hb = memnew(HBoxContainer);
 	add_child(path_hb);
 	add_child(path_hb);
 	path = memnew(LineEdit);
 	path = memnew(LineEdit);
-	path->set_drag_forwarding(this);
+	path->set_drag_forwarding_compat(this);
 	path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
 	path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
 	path_hb->add_child(path);
 	path_hb->add_child(path);
 	path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected));
 	path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected));
@@ -3686,7 +3686,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() {
 	assign->set_h_size_flags(SIZE_EXPAND_FILL);
 	assign->set_h_size_flags(SIZE_EXPAND_FILL);
 	assign->set_clip_text(true);
 	assign->set_clip_text(true);
 	assign->connect("pressed", callable_mp(this, &EditorPropertyNodePath::_node_assign));
 	assign->connect("pressed", callable_mp(this, &EditorPropertyNodePath::_node_assign));
-	assign->set_drag_forwarding(this);
+	assign->set_drag_forwarding_compat(this);
 	hbc->add_child(assign);
 	hbc->add_child(assign);
 
 
 	clear = memnew(Button);
 	clear = memnew(Button);

+ 1 - 1
editor/editor_properties_array_dict.cpp

@@ -715,7 +715,7 @@ EditorPropertyArray::EditorPropertyArray() {
 	edit->set_clip_text(true);
 	edit->set_clip_text(true);
 	edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed));
 	edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed));
 	edit->set_toggle_mode(true);
 	edit->set_toggle_mode(true);
-	edit->set_drag_forwarding(this);
+	edit->set_drag_forwarding_compat(this);
 	edit->connect("draw", callable_mp(this, &EditorPropertyArray::_button_draw));
 	edit->connect("draw", callable_mp(this, &EditorPropertyArray::_button_draw));
 	add_child(edit);
 	add_child(edit);
 	add_focusable(edit);
 	add_focusable(edit);

+ 1 - 1
editor/editor_resource_picker.cpp

@@ -950,7 +950,7 @@ EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) {
 	assign_button->set_flat(true);
 	assign_button->set_flat(true);
 	assign_button->set_h_size_flags(SIZE_EXPAND_FILL);
 	assign_button->set_h_size_flags(SIZE_EXPAND_FILL);
 	assign_button->set_clip_text(true);
 	assign_button->set_clip_text(true);
-	assign_button->set_drag_forwarding(this);
+	assign_button->set_drag_forwarding_compat(this);
 	add_child(assign_button);
 	add_child(assign_button);
 	assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected));
 	assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected));
 	assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw));
 	assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw));

+ 1 - 1
editor/editor_settings_dialog.cpp

@@ -793,7 +793,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
 	shortcuts->connect("item_activated", callable_mp(this, &EditorSettingsDialog::_shortcut_cell_double_clicked));
 	shortcuts->connect("item_activated", callable_mp(this, &EditorSettingsDialog::_shortcut_cell_double_clicked));
 	tab_shortcuts->add_child(shortcuts);
 	tab_shortcuts->add_child(shortcuts);
 
 
-	shortcuts->set_drag_forwarding(this);
+	shortcuts->set_drag_forwarding_compat(this);
 
 
 	// Adding event dialog
 	// Adding event dialog
 	shortcut_editor = memnew(InputEventConfigurationDialog);
 	shortcut_editor = memnew(InputEventConfigurationDialog);

+ 1 - 1
editor/export/project_export.cpp

@@ -1023,7 +1023,7 @@ ProjectExportDialog::ProjectExportDialog() {
 	mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	presets = memnew(ItemList);
 	presets = memnew(ItemList);
 	// TODO: Must reimplement drag forwarding.
 	// TODO: Must reimplement drag forwarding.
-	//presets->set_drag_forwarding(this);
+	//presets->set_drag_forwarding_compat(this);
 	mc->add_child(presets);
 	mc->add_child(presets);
 	presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));
 	presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));
 	duplicate_preset = memnew(Button);
 	duplicate_preset = memnew(Button);

+ 2 - 2
editor/filesystem_dock.cpp

@@ -3116,7 +3116,7 @@ FileSystemDock::FileSystemDock() {
 	tree = memnew(Tree);
 	tree = memnew(Tree);
 
 
 	tree->set_hide_root(true);
 	tree->set_hide_root(true);
-	tree->set_drag_forwarding(this);
+	tree->set_drag_forwarding_compat(this);
 	tree->set_allow_rmb_select(true);
 	tree->set_allow_rmb_select(true);
 	tree->set_select_mode(Tree::SELECT_MULTI);
 	tree->set_select_mode(Tree::SELECT_MULTI);
 	tree->set_custom_minimum_size(Size2(0, 15 * EDSCALE));
 	tree->set_custom_minimum_size(Size2(0, 15 * EDSCALE));
@@ -3153,7 +3153,7 @@ FileSystemDock::FileSystemDock() {
 	files = memnew(ItemList);
 	files = memnew(ItemList);
 	files->set_v_size_flags(SIZE_EXPAND_FILL);
 	files->set_v_size_flags(SIZE_EXPAND_FILL);
 	files->set_select_mode(ItemList::SELECT_MULTI);
 	files->set_select_mode(ItemList::SELECT_MULTI);
-	files->set_drag_forwarding(this);
+	files->set_drag_forwarding_compat(this);
 	files->connect("item_clicked", callable_mp(this, &FileSystemDock::_file_list_item_clicked));
 	files->connect("item_clicked", callable_mp(this, &FileSystemDock::_file_list_item_clicked));
 	files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input));
 	files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input));
 	files->connect("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected));
 	files->connect("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected));

+ 1 - 1
editor/plugins/node_3d_editor_plugin.cpp

@@ -4921,7 +4921,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
 
 
 	c->add_child(viewport);
 	c->add_child(viewport);
 	surface = memnew(Control);
 	surface = memnew(Control);
-	surface->set_drag_forwarding(this);
+	surface->set_drag_forwarding_compat(this);
 	add_child(surface);
 	add_child(surface);
 	surface->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
 	surface->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
 	surface->set_clip_contents(true);
 	surface->set_clip_contents(true);

+ 1 - 1
editor/plugins/resource_preloader_editor_plugin.cpp

@@ -379,7 +379,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
 	tree->set_column_expand(1, true);
 	tree->set_column_expand(1, true);
 	tree->set_v_size_flags(SIZE_EXPAND_FILL);
 	tree->set_v_size_flags(SIZE_EXPAND_FILL);
 
 
-	tree->set_drag_forwarding(this);
+	tree->set_drag_forwarding_compat(this);
 	vbc->add_child(tree);
 	vbc->add_child(tree);
 
 
 	dialog = memnew(AcceptDialog);
 	dialog = memnew(AcceptDialog);

+ 1 - 1
editor/plugins/script_editor_plugin.cpp

@@ -3669,7 +3669,7 @@ ScriptEditor::ScriptEditor() {
 	_sort_list_on_update = true;
 	_sort_list_on_update = true;
 	script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED);
 	script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED);
 	script_list->set_allow_rmb_select(true);
 	script_list->set_allow_rmb_select(true);
-	script_list->set_drag_forwarding(this);
+	script_list->set_drag_forwarding_compat(this);
 
 
 	context_menu = memnew(PopupMenu);
 	context_menu = memnew(PopupMenu);
 	add_child(context_menu);
 	add_child(context_menu);

+ 1 - 1
editor/plugins/script_text_editor.cpp

@@ -2167,7 +2167,7 @@ ScriptTextEditor::ScriptTextEditor() {
 
 
 	connection_info_dialog = memnew(ConnectionInfoDialog);
 	connection_info_dialog = memnew(ConnectionInfoDialog);
 
 
-	code_editor->get_text_editor()->set_drag_forwarding(this);
+	code_editor->get_text_editor()->set_drag_forwarding_compat(this);
 }
 }
 
 
 ScriptTextEditor::~ScriptTextEditor() {
 ScriptTextEditor::~ScriptTextEditor() {

+ 1 - 1
editor/plugins/shader_editor_plugin.cpp

@@ -451,7 +451,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() {
 	vb->add_child(shader_list);
 	vb->add_child(shader_list);
 	shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected));
 	shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected));
 	shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked));
 	shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked));
-	shader_list->set_drag_forwarding(this);
+	shader_list->set_drag_forwarding_compat(this);
 
 
 	main_split->add_child(vb);
 	main_split->add_child(vb);
 	vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE);
 	vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE);

+ 1 - 1
editor/plugins/skeleton_3d_editor_plugin.cpp

@@ -813,7 +813,7 @@ void Skeleton3DEditor::create_editors() {
 	joint_tree->set_v_size_flags(SIZE_EXPAND_FILL);
 	joint_tree->set_v_size_flags(SIZE_EXPAND_FILL);
 	joint_tree->set_h_size_flags(SIZE_EXPAND_FILL);
 	joint_tree->set_h_size_flags(SIZE_EXPAND_FILL);
 	joint_tree->set_allow_rmb_select(true);
 	joint_tree->set_allow_rmb_select(true);
-	joint_tree->set_drag_forwarding(this);
+	joint_tree->set_drag_forwarding_compat(this);
 	s_con->add_child(joint_tree);
 	s_con->add_child(joint_tree);
 
 
 	pose_editor = memnew(BoneTransformEditor(skeleton));
 	pose_editor = memnew(BoneTransformEditor(skeleton));

+ 1 - 1
editor/plugins/sprite_frames_editor_plugin.cpp

@@ -1408,7 +1408,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
 	frame_list->set_max_columns(0);
 	frame_list->set_max_columns(0);
 	frame_list->set_icon_mode(ItemList::ICON_MODE_TOP);
 	frame_list->set_icon_mode(ItemList::ICON_MODE_TOP);
 	frame_list->set_max_text_lines(2);
 	frame_list->set_max_text_lines(2);
-	frame_list->set_drag_forwarding(this);
+	frame_list->set_drag_forwarding_compat(this);
 	frame_list->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_frame_list_gui_input));
 	frame_list->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_frame_list_gui_input));
 	frame_list->connect("item_selected", callable_mp(this, &SpriteFramesEditor::_frame_list_item_selected));
 	frame_list->connect("item_selected", callable_mp(this, &SpriteFramesEditor::_frame_list_item_selected));
 
 

+ 1 - 1
editor/plugins/text_editor.cpp

@@ -650,7 +650,7 @@ TextEditor::TextEditor() {
 	goto_line_dialog = memnew(GotoLineDialog);
 	goto_line_dialog = memnew(GotoLineDialog);
 	add_child(goto_line_dialog);
 	add_child(goto_line_dialog);
 
 
-	code_editor->get_text_editor()->set_drag_forwarding(this);
+	code_editor->get_text_editor()->set_drag_forwarding_compat(this);
 }
 }
 
 
 TextEditor::~TextEditor() {
 TextEditor::~TextEditor() {

+ 1 - 1
editor/plugins/tiles/tile_map_editor.cpp

@@ -2236,7 +2236,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
 	scene_tiles_list = memnew(ItemList);
 	scene_tiles_list = memnew(ItemList);
 	scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 	scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 	scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
-	scene_tiles_list->set_drag_forwarding(this);
+	scene_tiles_list->set_drag_forwarding_compat(this);
 	scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);
 	scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);
 	scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));
 	scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));
 	scene_tiles_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked));
 	scene_tiles_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked));

+ 1 - 1
editor/plugins/tiles/tile_set_editor.cpp

@@ -728,7 +728,7 @@ TileSetEditor::TileSetEditor() {
 	sources_list->add_user_signal(MethodInfo("sort_request"));
 	sources_list->add_user_signal(MethodInfo("sort_request"));
 	sources_list->connect("sort_request", callable_mp(this, &TileSetEditor::_update_sources_list).bind(-1));
 	sources_list->connect("sort_request", callable_mp(this, &TileSetEditor::_update_sources_list).bind(-1));
 	sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
 	sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
-	sources_list->set_drag_forwarding(this);
+	sources_list->set_drag_forwarding_compat(this);
 	split_container_left_side->add_child(sources_list);
 	split_container_left_side->add_child(sources_list);
 
 
 	HBoxContainer *sources_bottom_actions = memnew(HBoxContainer);
 	HBoxContainer *sources_bottom_actions = memnew(HBoxContainer);

+ 1 - 1
editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp

@@ -509,7 +509,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
 	scene_tiles_list = memnew(ItemList);
 	scene_tiles_list = memnew(ItemList);
 	scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);
 	scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);
 	scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL);
 	scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL);
-	scene_tiles_list->set_drag_forwarding(this);
+	scene_tiles_list->set_drag_forwarding_compat(this);
 	scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_tile_inspector).unbind(1));
 	scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_tile_inspector).unbind(1));
 	scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));
 	scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));
 	scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated));
 	scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated));

+ 2 - 2
editor/plugins/visual_shader_editor_plugin.cpp

@@ -4915,7 +4915,7 @@ VisualShaderEditor::VisualShaderEditor() {
 	graph->set_h_size_flags(SIZE_EXPAND_FILL);
 	graph->set_h_size_flags(SIZE_EXPAND_FILL);
 	graph->set_show_zoom_label(true);
 	graph->set_show_zoom_label(true);
 	add_child(graph);
 	add_child(graph);
-	graph->set_drag_forwarding(this);
+	graph->set_drag_forwarding_compat(this);
 	float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
 	float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
 	graph->set_minimap_opacity(graph_minimap_opacity);
 	graph->set_minimap_opacity(graph_minimap_opacity);
 	float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
 	float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
@@ -5146,7 +5146,7 @@ VisualShaderEditor::VisualShaderEditor() {
 
 
 	members = memnew(Tree);
 	members = memnew(Tree);
 	members_vb->add_child(members);
 	members_vb->add_child(members);
-	members->set_drag_forwarding(this);
+	members->set_drag_forwarding_compat(this);
 	members->set_h_size_flags(SIZE_EXPAND_FILL);
 	members->set_h_size_flags(SIZE_EXPAND_FILL);
 	members->set_v_size_flags(SIZE_EXPAND_FILL);
 	members->set_v_size_flags(SIZE_EXPAND_FILL);
 	members->set_hide_root(true);
 	members->set_hide_root(true);

+ 1 - 1
editor/scene_tree_editor.cpp

@@ -1415,7 +1415,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
 
 
 	add_child(tree);
 	add_child(tree);
 
 
-	tree->set_drag_forwarding(this);
+	tree->set_drag_forwarding_compat(this);
 	if (p_can_rename) {
 	if (p_can_rename) {
 		tree->set_allow_rmb_select(true);
 		tree->set_allow_rmb_select(true);
 		tree->connect("item_mouse_selected", callable_mp(this, &SceneTreeEditor::_rmb_select));
 		tree->connect("item_mouse_selected", callable_mp(this, &SceneTreeEditor::_rmb_select));

+ 1 - 1
modules/multiplayer/editor/replication_editor.cpp

@@ -250,7 +250,7 @@ ReplicationEditor::ReplicationEditor() {
 	tree->add_child(drop_label);
 	tree->add_child(drop_label);
 	drop_label->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
 	drop_label->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
 
 
-	tree->set_drag_forwarding(this);
+	tree->set_drag_forwarding_compat(this);
 }
 }
 
 
 void ReplicationEditor::_bind_methods() {
 void ReplicationEditor::_bind_methods() {

+ 1 - 1
scene/gui/color_picker.cpp

@@ -642,7 +642,7 @@ inline int ColorPicker::_get_preset_size() {
 void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
 void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
 	ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size));
 	ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size));
 	btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
 	btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
-	btn_preset_new->set_drag_forwarding(this);
+	btn_preset_new->set_drag_forwarding_compat(this);
 	btn_preset_new->set_button_group(preset_group);
 	btn_preset_new->set_button_group(preset_group);
 	preset_container->add_child(btn_preset_new);
 	preset_container->add_child(btn_preset_new);
 	btn_preset_new->set_pressed(true);
 	btn_preset_new->set_pressed(true);

+ 45 - 21
scene/gui/control.cpp

@@ -1813,33 +1813,53 @@ bool Control::is_focus_owner_in_shortcut_context() const {
 
 
 // Drag and drop handling.
 // Drag and drop handling.
 
 
-void Control::set_drag_forwarding(Object *p_target) {
-	if (p_target) {
-		data.drag_owner = p_target->get_instance_id();
+void Control::set_drag_forwarding_compat(Object *p_base) {
+	if (p_base != nullptr) {
+		data.forward_drag = Callable(p_base, "_get_drag_data_fw").bind(this);
+		data.forward_can_drop = Callable(p_base, "_can_drop_data_fw").bind(this);
+		data.forward_drop = Callable(p_base, "_drop_data_fw").bind(this);
+
 	} else {
 	} else {
-		data.drag_owner = ObjectID();
+		data.forward_drag = Callable();
+		data.forward_can_drop = Callable();
+		data.forward_drop = Callable();
 	}
 	}
 }
 }
 
 
+void Control::set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop) {
+	data.forward_drag = p_drag;
+	data.forward_can_drop = p_can_drop;
+	data.forward_drop = p_drop;
+}
+
 Variant Control::get_drag_data(const Point2 &p_point) {
 Variant Control::get_drag_data(const Point2 &p_point) {
-	if (data.drag_owner.is_valid()) {
-		Object *obj = ObjectDB::get_instance(data.drag_owner);
-		if (obj) {
-			return obj->call("_get_drag_data_fw", p_point, this);
+	Variant ret;
+	if (data.forward_drag.is_valid()) {
+		Variant p = p_point;
+		const Variant *vp[1] = { &p };
+		Callable::CallError ce;
+		data.forward_drag.callp((const Variant **)vp, 1, ret, ce);
+		if (ce.error != Callable::CallError::CALL_OK) {
+			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) + ".");
 		}
 		}
+		return ret;
 	}
 	}
 
 
-	Variant dd;
-	GDVIRTUAL_CALL(_get_drag_data, p_point, dd);
-	return dd;
+	GDVIRTUAL_CALL(_get_drag_data, p_point, ret);
+	return ret;
 }
 }
 
 
 bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
 bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
-	if (data.drag_owner.is_valid()) {
-		Object *obj = ObjectDB::get_instance(data.drag_owner);
-		if (obj) {
-			return obj->call("_can_drop_data_fw", p_point, p_data, this);
+	if (data.forward_can_drop.is_valid()) {
+		Variant ret;
+		Variant p = p_point;
+		const Variant *vp[2] = { &p, &p_data };
+		Callable::CallError ce;
+		data.forward_can_drop.callp((const Variant **)vp, 2, ret, ce);
+		if (ce.error != Callable::CallError::CALL_OK) {
+			ERR_FAIL_V_MSG(Variant(), "Error calling forwarded method from 'can_drop_data': " + Variant::get_callable_error_text(data.forward_can_drop, (const Variant **)vp, 2, ce) + ".");
 		}
 		}
+		return ret;
 	}
 	}
 
 
 	bool ret = false;
 	bool ret = false;
@@ -1848,12 +1868,16 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const
 }
 }
 
 
 void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
 void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
-	if (data.drag_owner.is_valid()) {
-		Object *obj = ObjectDB::get_instance(data.drag_owner);
-		if (obj) {
-			obj->call("_drop_data_fw", p_point, p_data, this);
-			return;
+	if (data.forward_drop.is_valid()) {
+		Variant ret;
+		Variant p = p_point;
+		const Variant *vp[2] = { &p, &p_data };
+		Callable::CallError ce;
+		data.forward_drop.callp((const Variant **)vp, 2, ret, ce);
+		if (ce.error != Callable::CallError::CALL_OK) {
+			ERR_FAIL_MSG("Error calling forwarded method from 'drop_data': " + Variant::get_callable_error_text(data.forward_drop, (const Variant **)vp, 2, ce) + ".");
 		}
 		}
+		return;
 	}
 	}
 
 
 	GDVIRTUAL_CALL(_drop_data, p_point, p_data);
 	GDVIRTUAL_CALL(_drop_data, p_point, p_data);
@@ -3189,7 +3213,7 @@ void Control::_bind_methods() {
 
 
 	ClassDB::bind_method(D_METHOD("grab_click_focus"), &Control::grab_click_focus);
 	ClassDB::bind_method(D_METHOD("grab_click_focus"), &Control::grab_click_focus);
 
 
-	ClassDB::bind_method(D_METHOD("set_drag_forwarding", "target"), &Control::set_drag_forwarding);
+	ClassDB::bind_method(D_METHOD("set_drag_forwarding", "drag_func", "can_drop_func", "drop_func"), &Control::set_drag_forwarding);
 	ClassDB::bind_method(D_METHOD("set_drag_preview", "control"), &Control::set_drag_preview);
 	ClassDB::bind_method(D_METHOD("set_drag_preview", "control"), &Control::set_drag_preview);
 	ClassDB::bind_method(D_METHOD("is_drag_successful"), &Control::is_drag_successful);
 	ClassDB::bind_method(D_METHOD("is_drag_successful"), &Control::is_drag_successful);
 
 

+ 5 - 2
scene/gui/control.h

@@ -168,7 +168,9 @@ private:
 		Control *parent_control = nullptr;
 		Control *parent_control = nullptr;
 		Window *parent_window = nullptr;
 		Window *parent_window = nullptr;
 		CanvasItem *parent_canvas_item = nullptr;
 		CanvasItem *parent_canvas_item = nullptr;
-		ObjectID drag_owner;
+		Callable forward_drag;
+		Callable forward_can_drop;
+		Callable forward_drop;
 
 
 		// Positioning and sizing.
 		// Positioning and sizing.
 
 
@@ -499,7 +501,8 @@ public:
 
 
 	// Drag and drop handling.
 	// Drag and drop handling.
 
 
-	virtual void set_drag_forwarding(Object *p_target);
+	virtual void set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop);
+	virtual void set_drag_forwarding_compat(Object *p_base);
 	virtual Variant get_drag_data(const Point2 &p_point);
 	virtual Variant get_drag_data(const Point2 &p_point);
 	virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
 	virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
 	virtual void drop_data(const Point2 &p_point, const Variant &p_data);
 	virtual void drop_data(const Point2 &p_point, const Variant &p_data);

+ 1 - 1
scene/gui/tab_container.cpp

@@ -975,7 +975,7 @@ void TabContainer::_bind_methods() {
 
 
 TabContainer::TabContainer() {
 TabContainer::TabContainer() {
 	tab_bar = memnew(TabBar);
 	tab_bar = memnew(TabBar);
-	tab_bar->set_drag_forwarding(this);
+	tab_bar->set_drag_forwarding_compat(this);
 	add_child(tab_bar, false, INTERNAL_MODE_FRONT);
 	add_child(tab_bar, false, INTERNAL_MODE_FRONT);
 	tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
 	tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
 	tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed));
 	tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed));