Merge pull request #71127 from reduz/drag-forward-to-callables

Change set_drag_forwarding() to use callables.
This commit is contained in:
Rémi Verschelde 2023-01-11 01:14:58 +01:00 committed by GitHub
commit 54688a7535
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 86 additions and 113 deletions

View file

@ -780,67 +780,13 @@
</method>
<method name="set_drag_forwarding">
<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>
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>
</method>
<method name="set_drag_preview">

View file

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

View file

@ -754,7 +754,7 @@ CreateDialog::CreateDialog() {
favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected));
favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated));
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);
VBoxContainer *rec_vb = memnew(VBoxContainer);

View file

@ -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("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));
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->set_allow_rmb_select(true);
effects->set_focus_mode(FOCUS_CLICK);

View file

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

View file

@ -2065,7 +2065,7 @@ void EditorInspectorArray::_setup() {
ae.panel = memnew(PanelContainer);
ae.panel->set_focus_mode(FOCUS_ALL);
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_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));

View file

@ -569,7 +569,7 @@ EditorPropertyPath::EditorPropertyPath() {
HBoxContainer *path_hb = memnew(HBoxContainer);
add_child(path_hb);
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_hb->add_child(path);
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_clip_text(true);
assign->connect("pressed", callable_mp(this, &EditorPropertyNodePath::_node_assign));
assign->set_drag_forwarding(this);
assign->set_drag_forwarding_compat(this);
hbc->add_child(assign);
clear = memnew(Button);

View file

@ -715,7 +715,7 @@ EditorPropertyArray::EditorPropertyArray() {
edit->set_clip_text(true);
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed));
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));
add_child(edit);
add_focusable(edit);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2167,7 +2167,7 @@ ScriptTextEditor::ScriptTextEditor() {
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() {

View file

@ -451,7 +451,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() {
vb->add_child(shader_list);
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->set_drag_forwarding(this);
shader_list->set_drag_forwarding_compat(this);
main_split->add_child(vb);
vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE);

View file

@ -813,7 +813,7 @@ void Skeleton3DEditor::create_editors() {
joint_tree->set_v_size_flags(SIZE_EXPAND_FILL);
joint_tree->set_h_size_flags(SIZE_EXPAND_FILL);
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);
pose_editor = memnew(BoneTransformEditor(skeleton));

View file

@ -1408,7 +1408,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
frame_list->set_max_columns(0);
frame_list->set_icon_mode(ItemList::ICON_MODE_TOP);
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("item_selected", callable_mp(this, &SpriteFramesEditor::_frame_list_item_selected));

View file

@ -650,7 +650,7 @@ TextEditor::TextEditor() {
goto_line_dialog = memnew(GotoLineDialog);
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() {

View file

@ -2236,7 +2236,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
scene_tiles_list = memnew(ItemList);
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_drag_forwarding(this);
scene_tiles_list->set_drag_forwarding_compat(this);
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("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked));

View file

@ -728,7 +728,7 @@ TileSetEditor::TileSetEditor() {
sources_list->add_user_signal(MethodInfo("sort_request"));
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_drag_forwarding(this);
sources_list->set_drag_forwarding_compat(this);
split_container_left_side->add_child(sources_list);
HBoxContainer *sources_bottom_actions = memnew(HBoxContainer);

View file

@ -509,7 +509,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
scene_tiles_list = memnew(ItemList);
scene_tiles_list->set_h_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_action_buttons).unbind(1));
scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated));

View file

@ -4915,7 +4915,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->set_h_size_flags(SIZE_EXPAND_FILL);
graph->set_show_zoom_label(true);
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");
graph->set_minimap_opacity(graph_minimap_opacity);
float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
@ -5146,7 +5146,7 @@ VisualShaderEditor::VisualShaderEditor() {
members = memnew(Tree);
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_v_size_flags(SIZE_EXPAND_FILL);
members->set_hide_root(true);

View file

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

View file

@ -250,7 +250,7 @@ ReplicationEditor::ReplicationEditor() {
tree->add_child(drop_label);
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() {

View file

@ -642,7 +642,7 @@ inline int ColorPicker::_get_preset_size() {
void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
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_drag_forwarding(this);
btn_preset_new->set_drag_forwarding_compat(this);
btn_preset_new->set_button_group(preset_group);
preset_container->add_child(btn_preset_new);
btn_preset_new->set_pressed(true);

View file

@ -1813,33 +1813,53 @@ bool Control::is_focus_owner_in_shortcut_context() const {
// 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 {
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) {
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 {
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;
@ -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) {
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);
@ -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("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("is_drag_successful"), &Control::is_drag_successful);

View file

@ -168,7 +168,9 @@ private:
Control *parent_control = nullptr;
Window *parent_window = nullptr;
CanvasItem *parent_canvas_item = nullptr;
ObjectID drag_owner;
Callable forward_drag;
Callable forward_can_drop;
Callable forward_drop;
// Positioning and sizing.
@ -499,7 +501,8 @@ public:
// 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 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);

View file

@ -975,7 +975,7 @@ void TabContainer::_bind_methods() {
TabContainer::TabContainer() {
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);
tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed));