From 62a858d4c95b1ece71ff0cec28d7f47bce73ee42 Mon Sep 17 00:00:00 2001 From: Eoin O'Neill Date: Fri, 27 Apr 2018 17:08:34 -0700 Subject: Basic context menu added to connections docker w/ code cleanup. --- editor/connections_dialog.cpp | 192 ++++++++++++++++++++++++++---------------- editor/connections_dialog.h | 30 ++++++- 2 files changed, 147 insertions(+), 75 deletions(-) diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index ef133e2589..9d28664d22 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -35,6 +35,7 @@ #include "plugins/script_editor_plugin.h" #include "print_string.h" #include "scene/gui/label.h" +#include "scene/gui/popup_menu.h" class ConnectDialogBinds : public Object { @@ -408,56 +409,62 @@ void ConnectionsDock::_connect() { update_tree(); } -void ConnectionsDock::_connect_pressed() { +void ConnectionsDock::_disconnect( TreeItem *item ) +{ + Connection c = item->get_metadata(0); + ERR_FAIL_COND(c.source != node); //shouldn't happen but...bugcheck + + undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), c.signal, c.method)); + undo_redo->add_do_method(node, "disconnect", c.signal, c.target, c.method); + undo_redo->add_undo_method(node, "connect", c.signal, c.target, c.method, Vector(), c.flags); + undo_redo->add_do_method(this, "update_tree"); + undo_redo->add_undo_method(this, "update_tree"); + undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree + undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree + undo_redo->commit_action(); + + c.source->disconnect(c.signal, c.target, c.method); + update_tree(); +} + +void ConnectionsDock::_open_connection_dialog( TreeItem *item ) +{ + String signal = item->get_metadata(0).operator Dictionary()["name"]; + String signalname = signal; + String midname = node->get_name(); + for (int i = 0; i < midname.length(); i++) { + CharType c = midname[i]; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') { + //all good + } else if (c == ' ') { + c = '_'; + } else { + midname.remove(i); + i--; + continue; + } + + midname[i] = c; + } + connect_dialog->edit(node); + connect_dialog->popup_centered_ratio(); + connect_dialog->set_title(TTR("Connecting Signal:") + " " + signalname); + connect_dialog->set_dst_method("_on_" + midname + "_" + signal); + connect_dialog->set_dst_node(node->get_owner() ? node->get_owner() : node); +} + +void ConnectionsDock::_connect_pressed() { TreeItem *item = tree->get_selected(); if (!item) { - //no idea how this happened, but disable connect_button->set_disabled(true); return; } - if (item->get_parent() == tree->get_root() || item->get_parent()->get_parent() == tree->get_root()) { - //a signal - connect - String signal = item->get_metadata(0).operator Dictionary()["name"]; - String signalname = signal; - String midname = node->get_name(); - for (int i = 0; i < midname.length(); i++) { - CharType c = midname[i]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') { - //all good - } else if (c == ' ') { - c = '_'; - } else { - midname.remove(i); - i--; - continue; - } - - midname[i] = c; - } - - connect_dialog->edit(node); - connect_dialog->popup_centered_ratio(); - connect_dialog->set_title(TTR("Connecting Signal:") + " " + signalname); - connect_dialog->set_dst_method("_on_" + midname + "_" + signal); - connect_dialog->set_dst_node(node->get_owner() ? node->get_owner() : node); + if (_is_item_signal( item )) { + _open_connection_dialog( item ); } else { - //a slot- disconnect - Connection c = item->get_metadata(0); - ERR_FAIL_COND(c.source != node); //shouldn't happen but...bugcheck - - undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), c.signal, c.method)); - undo_redo->add_do_method(node, "disconnect", c.signal, c.target, c.method); - undo_redo->add_undo_method(node, "connect", c.signal, c.target, c.method, Vector(), c.flags); - undo_redo->add_do_method(this, "update_tree"); - undo_redo->add_undo_method(this, "update_tree"); - undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree - undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree - undo_redo->commit_action(); - - c.source->disconnect(c.signal, c.target, c.method); - update_tree(); + _disconnect( item ); } } @@ -611,7 +618,6 @@ void ConnectionsDock::update_tree() { } void ConnectionsDock::set_node(Node *p_node) { - node = p_node; update_tree(); } @@ -624,13 +630,11 @@ void ConnectionsDock::_something_selected() { connect_button->set_text(TTR("Connect...")); connect_button->set_disabled(true); - } else if (item->get_parent() == tree->get_root() || item->get_parent()->get_parent() == tree->get_root()) { - //a signal - connect + } else if (_is_item_signal( item )) { connect_button->set_text(TTR("Connect...")); connect_button->set_disabled(false); } else { - //a slot- disconnect connect_button->set_text(TTR("Disconnect")); connect_button->set_disabled(false); } @@ -643,31 +647,10 @@ void ConnectionsDock::_something_activated() { if (!item) return; - if (item->get_parent() == tree->get_root() || item->get_parent()->get_parent() == tree->get_root()) { - // a signal - connect - String signal = item->get_metadata(0).operator Dictionary()["name"]; - String midname = node->get_name(); - for (int i = 0; i < midname.length(); i++) { - CharType c = midname[i]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') { - //all good - } else if (c == ' ') { - c = '_'; - } else { - midname.remove(i); - i--; - continue; - } - - midname[i] = c; - } - - connect_dialog->edit(node); - connect_dialog->popup_centered_ratio(); - connect_dialog->set_dst_method("_on_" + midname + "_" + signal); - connect_dialog->set_dst_node(node->get_owner() ? node->get_owner() : node); + if (_is_item_signal( item )) { + _open_connection_dialog( item ); } else { - // a slot - go to target method + //Go to method within script editor, if avaiable. Connection c = item->get_metadata(0); ERR_FAIL_COND(c.source != node); //shouldn't happen but...bugcheck @@ -682,11 +665,65 @@ void ConnectionsDock::_something_activated() { } } -void ConnectionsDock::_bind_methods() { +bool ConnectionsDock::_is_item_signal( TreeItem *item ) { + return (item->get_parent() == tree->get_root() || item->get_parent()->get_parent() == tree->get_root()); +} + +void ConnectionsDock::_handle_signal_option( int option ) { + TreeItem *item = tree->get_selected(); + switch( option ) + { + case SignalMenuOption::CONNECT: + { + _open_connection_dialog(item); + } break; + } +} + +void ConnectionsDock::_handle_slot_option( int option ) { + TreeItem *item = tree->get_selected(); + + switch( option ) + { + case SlotMenuOption::EDIT: + { + //TODO: add edit functionality + } break; + case SlotMenuOption::DISCONNECT: + { + _disconnect(item); + } break; + } +} + +void ConnectionsDock::_rmb_pressed( Vector2 position ) { + TreeItem *item = tree->get_selected(); + + if( !item ) + return; + + Vector2 global_position = tree->get_global_position() + position; + + if( _is_item_signal(item) ) + { + signal_menu->set_position( global_position ); + signal_menu->popup(); + } + else + { + slot_menu->set_position( global_position ); + slot_menu->popup(); + } +} + +void ConnectionsDock::_bind_methods() { ClassDB::bind_method("_connect", &ConnectionsDock::_connect); ClassDB::bind_method("_something_selected", &ConnectionsDock::_something_selected); ClassDB::bind_method("_something_activated", &ConnectionsDock::_something_activated); + ClassDB::bind_method("_handle_signal_option", &ConnectionsDock::_handle_signal_option); + ClassDB::bind_method("_handle_slot_option", &ConnectionsDock::_handle_slot_option); + ClassDB::bind_method("_rmb_pressed", &ConnectionsDock::_rmb_pressed); ClassDB::bind_method("_close", &ConnectionsDock::_close); ClassDB::bind_method("_connect_pressed", &ConnectionsDock::_connect_pressed); ClassDB::bind_method("update_tree", &ConnectionsDock::update_tree); @@ -705,6 +742,7 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) { tree->set_hide_root(true); vbc->add_child(tree); tree->set_v_size_flags(SIZE_EXPAND_FILL); + tree->set_allow_rmb_select(true); connect_button = memnew(Button); connect_button->set_text(TTR("Connect")); @@ -723,6 +761,17 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) { remove_confirm->set_as_toplevel(true); add_child(remove_confirm); + signal_menu = memnew(PopupMenu); + add_child(signal_menu); + signal_menu->connect( "id_pressed", this, "_handle_signal_option" ); + signal_menu->add_item(TTR("Connect"), SignalMenuOption::CONNECT ); + + slot_menu = memnew(PopupMenu); + add_child(slot_menu); + slot_menu->connect( "id_pressed", this, "_handle_slot_option" ); + slot_menu->add_item(TTR("Edit"), SlotMenuOption::EDIT); + slot_menu->add_item(TTR("Disconnect"), SlotMenuOption::DISCONNECT); + /* node_only->set_anchor( MARGIN_TOP, ANCHOR_END ); node_only->set_anchor( MARGIN_BOTTOM, ANCHOR_END ); @@ -736,6 +785,7 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) { connect_dialog->connect("connected", this, "_connect"); tree->connect("item_selected", this, "_something_selected"); tree->connect("item_activated", this, "_something_activated"); + tree->connect("item_rmb_selected", this, "_rmb_pressed" ); add_constant_override("separation", 3 * EDSCALE); } diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 5e26e00f67..ca0e404740 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -28,6 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +/** +@author Juan Linietsky +*/ + #ifndef CONNECTIONS_DIALOG_H #define CONNECTIONS_DIALOG_H @@ -42,10 +46,7 @@ #include "scene/gui/tree.h" #include "undo_redo.h" -/** -@author Juan Linietsky -*/ - +class PopupMenu; class ConnectDialogBinds; class ConnectDialog : public ConfirmationDialog { @@ -93,6 +94,15 @@ class ConnectionsDock : public VBoxContainer { GDCLASS(ConnectionsDock, VBoxContainer); + enum SignalMenuOption { + CONNECT + }; + + enum SlotMenuOption { + EDIT, + DISCONNECT + }; + Button *connect_button; EditorNode *editor; Node *node; @@ -100,10 +110,17 @@ class ConnectionsDock : public VBoxContainer { ConfirmationDialog *remove_confirm; ConnectDialog *connect_dialog; + PopupMenu *signal_menu; + PopupMenu *slot_menu; + void _close(); void _connect(); + void _disconnect( TreeItem *item ); void _something_selected(); void _something_activated(); + void _handle_signal_option( int option ); + void _handle_slot_option( int option ); + void _rmb_pressed( Vector2 position ); UndoRedo *undo_redo; protected: @@ -111,6 +128,11 @@ protected: void _notification(int p_what); static void _bind_methods(); +private: + bool _is_item_signal( TreeItem *item ); + void _open_connection_dialog( TreeItem *item ); + + public: void set_undoredo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } -- cgit v1.2.3 From 6cef0eaa093259b46d5101a565feae1958b3bbcb Mon Sep 17 00:00:00 2001 From: Eoin O'Neill Date: Sat, 28 Apr 2018 15:11:51 -0700 Subject: Added connection editing. Some refactoring. --- editor/connections_dialog.cpp | 142 +++++++++++++++++++++++++++++------------- editor/connections_dialog.h | 16 +++-- 2 files changed, 112 insertions(+), 46 deletions(-) diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 9d28664d22..ec63da127c 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -110,23 +110,30 @@ void ConnectDialog::_tree_node_selected() { else make_callback->show(); - dst_path->set_text(node->get_path_to(current)); + dst_path->set_text(source->get_path_to(current)); } -void ConnectDialog::edit(Node *p_node) { +void ConnectDialog::init(Connection c, bool bEdit) { + source = static_cast(c.source); + signal = c.signal; - node = p_node; + tree->set_selected(NULL); + tree->set_marked(source, true); - //dst_method_list->get_popup()->clear(); + set_dst_node( static_cast(c.target) ); + set_dst_method( c.method ); + + bool bDeferred = (c.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED; + bool bOneshot = (c.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT; + + deferred->set_pressed(bDeferred); + oneshot->set_pressed(bOneshot); - tree->set_selected(NULL); - tree->set_marked(node, true); - dst_path->set_text(""); - dst_method->set_text(""); - deferred->set_pressed(false); - oneshot->set_pressed(false); cdbinds->params.clear(); + cdbinds->params = c.binds; cdbinds->notify_changed(); + + bEditMode = bEdit; } void ConnectDialog::ok_pressed() { @@ -168,6 +175,11 @@ bool ConnectDialog::get_oneshot() const { return oneshot->is_pressed(); } +bool ConnectDialog::is_editing() const +{ + return bEditMode; +} + StringName ConnectDialog::get_dst_method() const { String txt = dst_method->get_text(); @@ -176,6 +188,16 @@ StringName ConnectDialog::get_dst_method() const { return txt; } +Node * ConnectDialog::get_source() const +{ + return source; +} + +StringName ConnectDialog::get_signal() const +{ + return signal; +} + Vector ConnectDialog::get_binds() const { return cdbinds->params; @@ -372,43 +394,62 @@ void ConnectionsDock::_close() { hide(); } -void ConnectionsDock::_connect() { +void ConnectionsDock::_make_or_edit_connection() { TreeItem *it = tree->get_selected(); ERR_FAIL_COND(!it); - String signal = it->get_metadata(0).operator Dictionary()["name"]; NodePath dst_path = connect_dialog->get_dst_path(); Node *target = node->get_node(dst_path); ERR_FAIL_COND(!target); - StringName dst_method = connect_dialog->get_dst_method(); + Connection cToMake; + cToMake.source = connect_dialog->get_source(); + cToMake.target = target; + cToMake.signal = connect_dialog->get_signal(); //it->get_metadata(0).operator Dictionary()["name"] + cToMake.method = connect_dialog->get_dst_method(); + cToMake.binds = connect_dialog->get_binds(); bool defer = connect_dialog->get_deferred(); bool oshot = connect_dialog->get_oneshot(); - Vector binds = connect_dialog->get_binds(); - PoolStringArray args = it->get_metadata(0).operator Dictionary()["args"]; - int flags = CONNECT_PERSIST | (defer ? CONNECT_DEFERRED : 0) | (oshot ? CONNECT_ONESHOT : 0); - - undo_redo->create_action(vformat(TTR("Connect '%s' to '%s'"), signal, String(dst_method))); - undo_redo->add_do_method(node, "connect", signal, target, dst_method, binds, flags); - undo_redo->add_undo_method(node, "disconnect", signal, target, dst_method); - undo_redo->add_do_method(this, "update_tree"); - undo_redo->add_undo_method(this, "update_tree"); - undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree - undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree - - undo_redo->commit_action(); + cToMake.flags = CONNECT_PERSIST | (defer ? CONNECT_DEFERRED : 0) | (oshot ? CONNECT_ONESHOT : 0); + + if (connect_dialog->is_editing()) { + _disconnect(it); + _connect(cToMake); + } + else { + _connect(cToMake); + } if (connect_dialog->get_make_callback()) { - + PoolStringArray args = it->get_metadata(0).operator Dictionary()["args"]; print_line("request connect"); - editor->emit_signal("script_add_function_request", target, dst_method, args); + editor->emit_signal("script_add_function_request", target, cToMake.method, args); hide(); } update_tree(); } +void ConnectionsDock::_connect(Connection cToMake) +{ + Node* source = static_cast(cToMake.source); + Node* target = static_cast(cToMake.target); + + if (!source || !target) + return; + + undo_redo->create_action(vformat(TTR("Connect '%s' to '%s'"), String(cToMake.signal), String(cToMake.method))); + undo_redo->add_do_method(source, "connect", cToMake.signal, target, cToMake.method, cToMake.binds, cToMake.flags); + undo_redo->add_undo_method(source, "disconnect", cToMake.signal, target, cToMake.method); + undo_redo->add_do_method(this, "update_tree"); + undo_redo->add_undo_method(this, "update_tree"); + undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree + undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); + + undo_redo->commit_action(); +} + void ConnectionsDock::_disconnect( TreeItem *item ) { Connection c = item->get_metadata(0); @@ -416,23 +457,22 @@ void ConnectionsDock::_disconnect( TreeItem *item ) undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), c.signal, c.method)); undo_redo->add_do_method(node, "disconnect", c.signal, c.target, c.method); - undo_redo->add_undo_method(node, "connect", c.signal, c.target, c.method, Vector(), c.flags); + undo_redo->add_undo_method(node, "connect", c.signal, c.target, c.method, Vector(), c.flags); //Empty binds? undo_redo->add_do_method(this, "update_tree"); undo_redo->add_undo_method(this, "update_tree"); undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree - undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree + undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); undo_redo->commit_action(); - c.source->disconnect(c.signal, c.target, c.method); update_tree(); } -void ConnectionsDock::_open_connection_dialog( TreeItem *item ) -{ +void ConnectionsDock::_open_connection_dialog( TreeItem *item ) { + String signal = item->get_metadata(0).operator Dictionary()["name"]; String signalname = signal; String midname = node->get_name(); - for (int i = 0; i < midname.length(); i++) { + for (int i = 0; i < midname.length(); i++) { //TODO: Regex filter is cleaner. CharType c = midname[i]; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') { //all good @@ -443,15 +483,33 @@ void ConnectionsDock::_open_connection_dialog( TreeItem *item ) i--; continue; } - midname[i] = c; } - connect_dialog->edit(node); + Node *dst_node = node->get_owner() ? node->get_owner() : node; + StringName dst_method = "_on_" + midname + "_" + signal; + + Connection c; + c.source = node; + c.signal = StringName(signalname); + c.target = dst_node; + c.method = dst_method; + + connect_dialog->init(c); + connect_dialog->set_title(TTR("Connect Signal: ") + signalname); connect_dialog->popup_centered_ratio(); - connect_dialog->set_title(TTR("Connecting Signal:") + " " + signalname); - connect_dialog->set_dst_method("_on_" + midname + "_" + signal); - connect_dialog->set_dst_node(node->get_owner() ? node->get_owner() : node); +} + +void ConnectionsDock::_open_connection_dialog( Connection cToEdit ) { + + Node *src = static_cast(cToEdit.source); + Node *dst = static_cast(cToEdit.target); + + if(src && dst) { + connect_dialog->init(cToEdit, true); + connect_dialog->set_title(TTR("Edit Connection: ") + cToEdit.signal); + connect_dialog->popup_centered_ratio(); + } } void ConnectionsDock::_connect_pressed() { @@ -633,7 +691,6 @@ void ConnectionsDock::_something_selected() { } else if (_is_item_signal( item )) { connect_button->set_text(TTR("Connect...")); connect_button->set_disabled(false); - } else { connect_button->set_text(TTR("Disconnect")); connect_button->set_disabled(false); @@ -688,7 +745,8 @@ void ConnectionsDock::_handle_slot_option( int option ) { { case SlotMenuOption::EDIT: { - //TODO: add edit functionality + Connection c = item->get_metadata(0); + _open_connection_dialog(c); } break; case SlotMenuOption::DISCONNECT: { @@ -718,7 +776,7 @@ void ConnectionsDock::_rmb_pressed( Vector2 position ) { } void ConnectionsDock::_bind_methods() { - ClassDB::bind_method("_connect", &ConnectionsDock::_connect); + ClassDB::bind_method("_connect", &ConnectionsDock::_make_or_edit_connection); ClassDB::bind_method("_something_selected", &ConnectionsDock::_something_selected); ClassDB::bind_method("_something_activated", &ConnectionsDock::_something_activated); ClassDB::bind_method("_handle_signal_option", &ConnectionsDock::_handle_signal_option); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index ca0e404740..26479e9729 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -62,8 +62,11 @@ class ConnectDialog : public ConfirmationDialog { CheckButton *oneshot; CheckButton *make_callback; PropertyEditor *bind_editor; - Node *node; + Node *source; + StringName signal; ConnectDialogBinds *cdbinds; + bool bEditMode; + void ok_pressed(); void _cancel_pressed(); void _tree_node_selected(); @@ -78,13 +81,16 @@ public: bool get_make_callback() { return make_callback->is_visible() && make_callback->is_pressed(); } NodePath get_dst_path() const; StringName get_dst_method() const; + Node *get_source() const; + StringName get_signal() const; bool get_deferred() const; bool get_oneshot() const; + bool is_editing() const; Vector get_binds() const; void set_dst_method(const StringName &p_method); void set_dst_node(Node *p_node); - void edit(Node *p_node); + void init(Connection c, bool bEdit = false); ConnectDialog(); ~ConnectDialog(); @@ -114,8 +120,10 @@ class ConnectionsDock : public VBoxContainer { PopupMenu *slot_menu; void _close(); - void _connect(); + void _make_or_edit_connection(); + void _connect( Connection cToMake ); void _disconnect( TreeItem *item ); + void _edit( TreeItem *item ); void _something_selected(); void _something_activated(); void _handle_signal_option( int option ); @@ -131,7 +139,7 @@ protected: private: bool _is_item_signal( TreeItem *item ); void _open_connection_dialog( TreeItem *item ); - + void _open_connection_dialog( Connection cToEdit ); public: void set_undoredo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } -- cgit v1.2.3 From 37e166f4c7406a6f1cf6274c16ca7c1839165161 Mon Sep 17 00:00:00 2001 From: Eoin O'Neill Date: Sun, 29 Apr 2018 00:03:49 -0700 Subject: Added disconnect_all and edit functionality to ConnectionsDock. Refactor: Changed function order so header and source are in sync, renamed functions and members to be more clear. Replaced pointers with references where appropriate. --- editor/connections_dialog.cpp | 670 ++++++++++++++++++++++++------------------ editor/connections_dialog.h | 79 ++--- 2 files changed, 424 insertions(+), 325 deletions(-) diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index ec63da127c..7f93917744 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -88,58 +88,12 @@ public: } }; -void ConnectDialog::_notification(int p_what) { - - if (p_what == NOTIFICATION_ENTER_TREE) { - bind_editor->edit(cdbinds); - } -} - -void ConnectDialog::_tree_node_selected() { - - //dst_method_list->get_popup()->clear(); - Node *current = tree->get_selected(); - - if (!current) { - make_callback->hide(); - return; - } - - if (current->get_script().is_null()) - make_callback->hide(); - else - make_callback->show(); - - dst_path->set_text(source->get_path_to(current)); -} - -void ConnectDialog::init(Connection c, bool bEdit) { - source = static_cast(c.source); - signal = c.signal; - - tree->set_selected(NULL); - tree->set_marked(source, true); - - set_dst_node( static_cast(c.target) ); - set_dst_method( c.method ); - - bool bDeferred = (c.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED; - bool bOneshot = (c.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT; - - deferred->set_pressed(bDeferred); - oneshot->set_pressed(bOneshot); - - cdbinds->params.clear(); - cdbinds->params = c.binds; - cdbinds->notify_changed(); - - bEditMode = bEdit; -} - +/* +Signal automatically called by parent dialog. +*/ void ConnectDialog::ok_pressed() { if (dst_method->get_text() == "") { - error->set_text(TTR("Method in target Node must be specified!")); error->popup_centered_minsize(); return; @@ -155,54 +109,35 @@ void ConnectDialog::ok_pressed() { emit_signal("connected"); hide(); } + void ConnectDialog::_cancel_pressed() { hide(); } -NodePath ConnectDialog::get_dst_path() const { - - return dst_path->get_text(); -} - -bool ConnectDialog::get_deferred() const { - - return deferred->is_pressed(); -} - -bool ConnectDialog::get_oneshot() const { - - return oneshot->is_pressed(); -} - -bool ConnectDialog::is_editing() const -{ - return bEditMode; -} - -StringName ConnectDialog::get_dst_method() const { - - String txt = dst_method->get_text(); - if (txt.find("(") != -1) - txt = txt.left(txt.find("(")).strip_edges(); - return txt; -} +/* +Called each time a target node is selected within the target node tree. +*/ +void ConnectDialog::_tree_node_selected() { -Node * ConnectDialog::get_source() const -{ - return source; -} + Node *current = tree->get_selected(); -StringName ConnectDialog::get_signal() const -{ - return signal; -} + if (!current) { + make_callback->hide(); + return; + } -Vector ConnectDialog::get_binds() const { + if (current->get_script().is_null()) + make_callback->hide(); + else + make_callback->show(); - return cdbinds->params; + dst_path->set_text(source->get_path_to(current)); } +/* +Adds a new parameter bind to connection. +*/ void ConnectDialog::_add_bind() { if (cdbinds->params.size() >= VARIANT_ARG_MAX) @@ -212,7 +147,6 @@ void ConnectDialog::_add_bind() { Variant value; switch (vt) { - case Variant::BOOL: value = false; break; case Variant::INT: value = 0; break; case Variant::REAL: value = 0.0; break; @@ -226,7 +160,6 @@ void ConnectDialog::_add_bind() { case Variant::BASIS: value = Basis(); break; case Variant::TRANSFORM: value = Transform(); break; case Variant::COLOR: value = Color(); break; - default: { ERR_FAIL(); } break; } @@ -236,6 +169,9 @@ void ConnectDialog::_add_bind() { cdbinds->notify_changed(); } +/* +Remove parameter bind from connection. +*/ void ConnectDialog::_remove_bind() { String st = bind_editor->get_selected_path(); @@ -248,25 +184,106 @@ void ConnectDialog::_remove_bind() { cdbinds->notify_changed(); } +void ConnectDialog::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + bind_editor->edit(cdbinds); + } +} + +void ConnectDialog::_bind_methods() { + + ClassDB::bind_method("_cancel", &ConnectDialog::_cancel_pressed); + ClassDB::bind_method("_tree_node_selected", &ConnectDialog::_tree_node_selected); + ClassDB::bind_method("_add_bind", &ConnectDialog::_add_bind); + ClassDB::bind_method("_remove_bind", &ConnectDialog::_remove_bind); + + ADD_SIGNAL(MethodInfo("connected")); +} + +Node *ConnectDialog::get_source() const { + + return source; +} + +StringName ConnectDialog::get_signal_name() const { + + return signal; +} + +NodePath ConnectDialog::get_dst_path() const { + + return dst_path->get_text(); +} + void ConnectDialog::set_dst_node(Node *p_node) { tree->set_selected(p_node); } +StringName ConnectDialog::get_dst_method_name() const { + + String txt = dst_method->get_text(); + if (txt.find("(") != -1) + txt = txt.left(txt.find("(")).strip_edges(); + return txt; +} + void ConnectDialog::set_dst_method(const StringName &p_method) { dst_method->set_text(p_method); } -void ConnectDialog::_bind_methods() { +Vector ConnectDialog::get_binds() const { - ClassDB::bind_method("_cancel", &ConnectDialog::_cancel_pressed); - ClassDB::bind_method("_tree_node_selected", &ConnectDialog::_tree_node_selected); + return cdbinds->params; +} - ClassDB::bind_method("_add_bind", &ConnectDialog::_add_bind); - ClassDB::bind_method("_remove_bind", &ConnectDialog::_remove_bind); +bool ConnectDialog::get_deferred() const { - ADD_SIGNAL(MethodInfo("connected")); + return deferred->is_pressed(); +} + +bool ConnectDialog::get_oneshot() const { + + return oneshot->is_pressed(); +} + +/* +Returns true if ConnectDialog is being used to edit an existing connection. +*/ +bool ConnectDialog::is_editing() const { + + return bEditMode; +} + +/* +Initialize ConnectDialog and populate fields with expected data. +If creating a connection from scratch, sensible defaults are used. +If editing an existing connection, previous data is retained. +*/ +void ConnectDialog::init(Connection c, bool bEdit) { + + source = static_cast(c.source); + signal = c.signal; + + tree->set_selected(NULL); + tree->set_marked(source, true); + + set_dst_node(static_cast(c.target)); + set_dst_method(c.method); + + bool bDeferred = (c.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED; + bool bOneshot = (c.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT; + + deferred->set_pressed(bDeferred); + oneshot->set_pressed(bOneshot); + + cdbinds->params.clear(); + cdbinds->params = c.binds; + cdbinds->notify_changed(); + + bEditMode = bEdit; } ConnectDialog::ConnectDialog() { @@ -284,6 +301,8 @@ ConnectDialog::ConnectDialog() { tree = memnew(SceneTreeEditor(false)); tree->get_scene_tree()->connect("item_activated", this, "_ok"); + tree->connect("node_selected", this, "_tree_node_selected"); + vbc_left->add_margin_child(TTR("Connect To Node:"), tree, true); VBoxContainer *vbc_right = memnew(VBoxContainer); @@ -295,12 +314,10 @@ ConnectDialog::ConnectDialog() { type_list = memnew(OptionButton); type_list->set_h_size_flags(SIZE_EXPAND_FILL); add_bind_hb->add_child(type_list); - type_list->add_item("bool", Variant::BOOL); type_list->add_item("int", Variant::INT); type_list->add_item("real", Variant::REAL); type_list->add_item("string", Variant::STRING); - //type_list->add_separator(); type_list->add_item("Vector2", Variant::VECTOR2); type_list->add_item("Rect2", Variant::RECT2); type_list->add_item("Vector3", Variant::VECTOR3); @@ -309,12 +326,10 @@ ConnectDialog::ConnectDialog() { type_list->add_item("AABB", Variant::AABB); type_list->add_item("Basis", Variant::BASIS); type_list->add_item("Transform", Variant::TRANSFORM); - //type_list->add_separator(); type_list->add_item("Color", Variant::COLOR); type_list->select(0); Button *add_bind = memnew(Button); - add_bind->set_text(TTR("Add")); add_bind_hb->add_child(add_bind); add_bind->connect("pressed", this, "_add_bind"); @@ -341,7 +356,8 @@ ConnectDialog::ConnectDialog() { dst_method->set_h_size_flags(SIZE_EXPAND_FILL); dstm_hb->add_child(dst_method); - /*dst_method_list = memnew( MenuButton ); + /* + dst_method_list = memnew( MenuButton ); dst_method_list->set_text("List..."); dst_method_list->set_anchor( MARGIN_RIGHT, ANCHOR_END ); dst_method_list->set_anchor( MARGIN_LEFT, ANCHOR_END ); @@ -350,7 +366,6 @@ ConnectDialog::ConnectDialog() { dst_method_list->set_begin( Point2( 70,59) ); dst_method_list->set_end( Point2( 15,39 ) ); */ - //add_child(dst_method_list); make_callback = memnew(CheckButton); make_callback->set_toggle_mode(true); @@ -366,8 +381,6 @@ ConnectDialog::ConnectDialog() { oneshot->set_text(TTR("Oneshot")); dstm_hb->add_child(oneshot); - tree->connect("node_selected", this, "_tree_node_selected"); - set_as_toplevel(true); cdbinds = memnew(ConnectDialogBinds); @@ -379,51 +392,51 @@ ConnectDialog::ConnectDialog() { } ConnectDialog::~ConnectDialog() { + memdelete(cdbinds); } -void ConnectionsDock::_notification(int p_what) { - - if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - update_tree(); - } -} +//ConnectionsDock ========================== -void ConnectionsDock::_close() { +struct _ConnectionsDockMethodInfoSort { - hide(); -} + _FORCE_INLINE_ bool operator()(const MethodInfo &a, const MethodInfo &b) const { + return a.name < b.name; + } +}; +/* +Post-ConnectDialog callback for creating/editing connections. +Creates or edits connections based on state of the ConnectDialog when "Connect" is pressed. +*/ void ConnectionsDock::_make_or_edit_connection() { TreeItem *it = tree->get_selected(); ERR_FAIL_COND(!it); NodePath dst_path = connect_dialog->get_dst_path(); - Node *target = node->get_node(dst_path); + Node *target = selectedNode->get_node(dst_path); ERR_FAIL_COND(!target); Connection cToMake; cToMake.source = connect_dialog->get_source(); cToMake.target = target; - cToMake.signal = connect_dialog->get_signal(); //it->get_metadata(0).operator Dictionary()["name"] - cToMake.method = connect_dialog->get_dst_method(); + cToMake.signal = connect_dialog->get_signal_name(); + cToMake.method = connect_dialog->get_dst_method_name(); cToMake.binds = connect_dialog->get_binds(); bool defer = connect_dialog->get_deferred(); bool oshot = connect_dialog->get_oneshot(); cToMake.flags = CONNECT_PERSIST | (defer ? CONNECT_DEFERRED : 0) | (oshot ? CONNECT_ONESHOT : 0); - + if (connect_dialog->is_editing()) { - _disconnect(it); + _disconnect(*it); _connect(cToMake); - } - else { + } else { _connect(cToMake); } if (connect_dialog->get_make_callback()) { PoolStringArray args = it->get_metadata(0).operator Dictionary()["args"]; - print_line("request connect"); editor->emit_signal("script_add_function_request", target, cToMake.method, args); hide(); } @@ -431,66 +444,142 @@ void ConnectionsDock::_make_or_edit_connection() { update_tree(); } -void ConnectionsDock::_connect(Connection cToMake) -{ - Node* source = static_cast(cToMake.source); - Node* target = static_cast(cToMake.target); +/* +Creates single connection w/ undo-redo functionality. +*/ +void ConnectionsDock::_connect(Connection cToMake) { + + Node *source = static_cast(cToMake.source); + Node *target = static_cast(cToMake.target); if (!source || !target) return; - + undo_redo->create_action(vformat(TTR("Connect '%s' to '%s'"), String(cToMake.signal), String(cToMake.method))); + undo_redo->add_do_method(source, "connect", cToMake.signal, target, cToMake.method, cToMake.binds, cToMake.flags); undo_redo->add_undo_method(source, "disconnect", cToMake.signal, target, cToMake.method); undo_redo->add_do_method(this, "update_tree"); undo_redo->add_undo_method(this, "update_tree"); undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree - undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); undo_redo->commit_action(); } -void ConnectionsDock::_disconnect( TreeItem *item ) -{ - Connection c = item->get_metadata(0); - ERR_FAIL_COND(c.source != node); //shouldn't happen but...bugcheck +/* +Break single connection w/ undo-redo functionality. +*/ +void ConnectionsDock::_disconnect(TreeItem &item) { + + Connection c = item.get_metadata(0); + ERR_FAIL_COND(c.source != selectedNode); //shouldn't happen but...bugcheck undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), c.signal, c.method)); - undo_redo->add_do_method(node, "disconnect", c.signal, c.target, c.method); - undo_redo->add_undo_method(node, "connect", c.signal, c.target, c.method, Vector(), c.flags); //Empty binds? + + undo_redo->add_do_method(selectedNode, "disconnect", c.signal, c.target, c.method); + undo_redo->add_undo_method(selectedNode, "connect", c.signal, c.target, c.method, c.binds, c.flags); undo_redo->add_do_method(this, "update_tree"); undo_redo->add_undo_method(this, "update_tree"); undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); + undo_redo->commit_action(); +} - update_tree(); +/* +Break all conections of currently selected signal. +Can undo-redo as a single action. +*/ +void ConnectionsDock::_disconnect_all() { + + TreeItem *item = tree->get_selected(); + + if (!_is_item_signal(*item)) + return; + + TreeItem *child = item->get_children(); + String signalName = item->get_metadata(0).operator Dictionary()["name"]; + undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signalName)); + + while (child) { + Connection c = child->get_metadata(0); + undo_redo->add_do_method(selectedNode, "disconnect", c.signal, c.target, c.method); + undo_redo->add_undo_method(selectedNode, "connect", c.signal, c.target, c.method, c.binds, c.flags); + child = child->get_next(); + } + + undo_redo->add_do_method(this, "update_tree"); + undo_redo->add_undo_method(this, "update_tree"); + undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); + + undo_redo->commit_action(); } -void ConnectionsDock::_open_connection_dialog( TreeItem *item ) { +void ConnectionsDock::_tree_item_selected() { - String signal = item->get_metadata(0).operator Dictionary()["name"]; + TreeItem *item = tree->get_selected(); + if (!item) { //Unlikely. Disable button just in case. + connect_button->set_text(TTR("Connect...")); + connect_button->set_disabled(true); + } else if (_is_item_signal(*item)) { + connect_button->set_text(TTR("Connect...")); + connect_button->set_disabled(false); + } else { + connect_button->set_text(TTR("Disconnect")); + connect_button->set_disabled(false); + } +} + +void ConnectionsDock::_tree_item_activated() { //"Activation" on double-click. + + TreeItem *item = tree->get_selected(); + + if (!item) + return; + + if (_is_item_signal(*item)) { + _open_connection_dialog(*item); + } else { + _go_to_script(*item); + } +} + +bool ConnectionsDock::_is_item_signal(TreeItem &item) { + + return (item.get_parent() == tree->get_root() || item.get_parent()->get_parent() == tree->get_root()); +} + +/* +Open connection dialog with TreeItem data to CREATE a brand-new connection. +*/ +void ConnectionsDock::_open_connection_dialog(TreeItem &item) { + + String signal = item.get_metadata(0).operator Dictionary()["name"]; String signalname = signal; - String midname = node->get_name(); - for (int i = 0; i < midname.length(); i++) { //TODO: Regex filter is cleaner. + String midname = selectedNode->get_name(); + for (int i = 0; i < midname.length(); i++) { //TODO: Regex filter may be cleaner. CharType c = midname[i]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') { - //all good - } else if (c == ' ') { - c = '_'; - } else { - midname.remove(i); - i--; - continue; + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) { + if (c == ' ') { + //Replace spaces with underlines. + c = '_'; + } else { + //Remove any other characters. + midname.remove(i); + i--; + continue; + } } midname[i] = c; } - Node *dst_node = node->get_owner() ? node->get_owner() : node; + Node *dst_node = selectedNode->get_owner() ? selectedNode->get_owner() : selectedNode; StringName dst_method = "_on_" + midname + "_" + signal; Connection c; - c.source = node; + c.source = selectedNode; c.signal = StringName(signalname); c.target = dst_node; c.method = dst_method; @@ -500,55 +589,168 @@ void ConnectionsDock::_open_connection_dialog( TreeItem *item ) { connect_dialog->popup_centered_ratio(); } -void ConnectionsDock::_open_connection_dialog( Connection cToEdit ) { +/* +Open connection dialog with Connection data to EDIT an existing connection. +*/ +void ConnectionsDock::_open_connection_dialog(Connection cToEdit) { - Node *src = static_cast(cToEdit.source); - Node *dst = static_cast(cToEdit.target); + Node *src = static_cast(cToEdit.source); + Node *dst = static_cast(cToEdit.target); - if(src && dst) { + if (src && dst) { connect_dialog->init(cToEdit, true); connect_dialog->set_title(TTR("Edit Connection: ") + cToEdit.signal); connect_dialog->popup_centered_ratio(); } } +/* +Open slot method location in script editor. +*/ +void ConnectionsDock::_go_to_script(TreeItem &item) { + + if (_is_item_signal(item)) + return; + + Connection c = item.get_metadata(0); + ERR_FAIL_COND(c.source != selectedNode); //shouldn't happen but...bugcheck + + if (!c.target) + return; + + Ref