Forráskód Böngészése

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.
Eoin O'Neill 7 éve
szülő
commit
37e166f4c7
2 módosított fájl, 424 hozzáadás és 325 törlés
  1. 381 289
      editor/connections_dialog.cpp
  2. 43 36
      editor/connections_dialog.h

+ 381 - 289
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<Node*>(c.source);
-	signal = c.signal;
-
-	tree->set_selected(NULL);
-	tree->set_marked(source, true);
-
-	set_dst_node( static_cast<Node*>(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<Variant> 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<Variant> 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<Node *>(c.source);
+	signal = c.signal;
+
+	tree->set_selected(NULL);
+	tree->set_marked(source, true);
+
+	set_dst_node(static_cast<Node *>(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<Node*>(cToMake.source);
-	Node* target = static_cast<Node*>(cToMake.target);
+/*
+Creates single connection w/ undo-redo functionality.
+*/
+void ConnectionsDock::_connect(Connection cToMake) {
+
+	Node *source = static_cast<Node *>(cToMake.source);
+	Node *target = static_cast<Node *>(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<Variant>(), 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<Node*>(cToEdit.source);
-	Node *dst = static_cast<Node*>(cToEdit.target);
+	Node *src = static_cast<Node *>(cToEdit.source);
+	Node *dst = static_cast<Node *>(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<Script> script = c.target->get_script();
+
+	if (script.is_null())
+		return;
+
+	if (script.is_valid() && ScriptEditor::get_singleton()->script_goto_method(script, c.method)) {
+		editor->call("_editor_select", EditorNode::EDITOR_SCRIPT);
+	}
+}
+
+void ConnectionsDock::_handle_signal_menu_option(int option) {
+
+	TreeItem *item = tree->get_selected();
+
+	if (!item)
+		return;
+
+	switch (option) {
+		case CONNECT: {
+			_open_connection_dialog(*item);
+		} break;
+		case DISCONNECT_ALL: {
+			StringName signalName = item->get_metadata(0).operator Dictionary()["name"];
+			disconnect_all_dialog->set_text(TTR("Are you sure you want to remove all connections from the \"") + signalName + "\" signal?");
+			disconnect_all_dialog->popup_centered();
+		} break;
+	}
+}
+
+void ConnectionsDock::_handle_slot_menu_option(int option) {
+
+	TreeItem *item = tree->get_selected();
+
+	if (!item)
+		return;
+
+	switch (option) {
+		case EDIT: {
+			Connection c = item->get_metadata(0);
+			_open_connection_dialog(c);
+		} break;
+		case GO_TO_SCRIPT: {
+			_go_to_script(*item);
+		} break;
+		case DISCONNECT: {
+			_disconnect(*item);
+			update_tree();
+		} 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::_close() {
+
+	hide();
+}
+
 void ConnectionsDock::_connect_pressed() {
+
 	TreeItem *item = tree->get_selected();
 	if (!item) {
 		connect_button->set_disabled(true);
 		return;
 	}
 
-	if (_is_item_signal( item )) {
-		_open_connection_dialog( item );
+	if (_is_item_signal(*item)) {
+		_open_connection_dialog(*item);
 	} else {
-		_disconnect( item );
+		_disconnect(*item);
+		update_tree();
 	}
 }
 
-struct _ConnectionsDockMethodInfoSort {
+void ConnectionsDock::_notification(int p_what) {
 
-	_FORCE_INLINE_ bool operator()(const MethodInfo &a, const MethodInfo &b) const {
-		return a.name < b.name;
+	if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
+		update_tree();
 	}
-};
+}
+
+void ConnectionsDock::_bind_methods() {
+
+	ClassDB::bind_method("_make_or_edit_connection", &ConnectionsDock::_make_or_edit_connection);
+	ClassDB::bind_method("_disconnect_all", &ConnectionsDock::_disconnect_all);
+	ClassDB::bind_method("_tree_item_selected", &ConnectionsDock::_tree_item_selected);
+	ClassDB::bind_method("_tree_item_activated", &ConnectionsDock::_tree_item_activated);
+	ClassDB::bind_method("_handle_signal_menu_option", &ConnectionsDock::_handle_signal_menu_option);
+	ClassDB::bind_method("_handle_slot_menu_option", &ConnectionsDock::_handle_slot_menu_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);
+}
+
+void ConnectionsDock::set_node(Node *p_node) {
+
+	selectedNode = p_node;
+	update_tree();
+}
 
 void ConnectionsDock::update_tree() {
 
 	tree->clear();
 
-	if (!node)
+	if (!selectedNode)
 		return;
 
 	TreeItem *root = tree->create_item();
 
 	List<MethodInfo> node_signals;
 
-	node->get_signal_list(&node_signals);
+	selectedNode->get_signal_list(&node_signals);
 
 	//node_signals.sort_custom<_ConnectionsDockMethodInfoSort>();
 	bool did_script = false;
-	StringName base = node->get_class();
+	StringName base = selectedNode->get_class();
 
 	while (base) {
 
@@ -558,7 +760,7 @@ void ConnectionsDock::update_tree() {
 
 		if (!did_script) {
 
-			Ref<Script> scr = node->get_script();
+			Ref<Script> scr = selectedNode->get_script();
 			if (scr.is_valid()) {
 				scr->get_script_signal_list(&node_signals);
 				if (scr->get_path().is_resource_file())
@@ -628,7 +830,7 @@ void ConnectionsDock::update_tree() {
 			item->set_icon(0, get_icon("Signal", "EditorIcons"));
 
 			List<Object::Connection> connections;
-			node->get_signal_connection_list(mi.name, &connections);
+			selectedNode->get_signal_connection_list(mi.name, &connections);
 
 			for (List<Object::Connection>::Element *F = connections.front(); F; F = F->next()) {
 
@@ -640,7 +842,7 @@ void ConnectionsDock::update_tree() {
 				if (!target)
 					continue;
 
-				String path = String(node->get_path_to(target)) + " :: " + c.method + "()";
+				String path = String(selectedNode->get_path_to(target)) + " :: " + c.method + "()";
 				if (c.flags & CONNECT_DEFERRED)
 					path += " (deferred)";
 				if (c.flags & CONNECT_ONESHOT)
@@ -675,118 +877,6 @@ void ConnectionsDock::update_tree() {
 	connect_button->set_disabled(true);
 }
 
-void ConnectionsDock::set_node(Node *p_node) {
-	node = p_node;
-	update_tree();
-}
-
-void ConnectionsDock::_something_selected() {
-
-	TreeItem *item = tree->get_selected();
-	if (!item) {
-		//no idea how this happened, but disable
-		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::_something_activated() {
-
-	TreeItem *item = tree->get_selected();
-
-	if (!item)
-		return;
-
-	if (_is_item_signal( item )) {
-		_open_connection_dialog( item );
-	} else {
-		//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
-
-		if (!c.target)
-			return;
-
-		Ref<Script> script = c.target->get_script();
-
-		if (script.is_valid() && ScriptEditor::get_singleton()->script_goto_method(script, c.method)) {
-			editor->call("_editor_select", EditorNode::EDITOR_SCRIPT);
-		}
-	}
-}
-
-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:
-		{
-			Connection c = item->get_metadata(0);
-			_open_connection_dialog(c);
-		} 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::_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);
-	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);
-}
-
 ConnectionsDock::ConnectionsDock(EditorNode *p_editor) {
 
 	editor = p_editor;
@@ -809,26 +899,29 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) {
 	hb->add_spacer();
 	hb->add_child(connect_button);
 	connect_button->connect("pressed", this, "_connect_pressed");
-	//add_child(tree);
 
 	connect_dialog = memnew(ConnectDialog);
 	connect_dialog->set_as_toplevel(true);
 	add_child(connect_dialog);
 
-	remove_confirm = memnew(ConfirmationDialog);
-	remove_confirm->set_as_toplevel(true);
-	add_child(remove_confirm);
+	disconnect_all_dialog = memnew(ConfirmationDialog);
+	disconnect_all_dialog->set_as_toplevel(true);
+	add_child(disconnect_all_dialog);
+	disconnect_all_dialog->connect("confirmed", this, "_disconnect_all");
+	disconnect_all_dialog->set_text(TTR("Are you sure you want to remove all connections from this signal?"));
 
 	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 );
+	signal_menu->connect("id_pressed", this, "_handle_signal_menu_option");
+	signal_menu->add_item(TTR("Connect..."), CONNECT);
+	signal_menu->add_item(TTR("Disconnect All"), DISCONNECT_ALL);
 
 	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);
+	slot_menu->connect("id_pressed", this, "_handle_slot_menu_option");
+	slot_menu->add_item(TTR("Edit..."), EDIT);
+	slot_menu->add_item(TTR("Go To Method"), GO_TO_SCRIPT);
+	slot_menu->add_item(TTR("Disconnect"), DISCONNECT);
 
 	/*
 	node_only->set_anchor( MARGIN_TOP, ANCHOR_END );
@@ -839,11 +932,10 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) {
 	node_only->set_end( Point2( 10,44) );
 	*/
 
-	remove_confirm->connect("confirmed", this, "_remove_confirm");
-	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" );
+	connect_dialog->connect("connected", this, "_make_or_edit_connection");
+	tree->connect("item_selected", this, "_tree_item_selected");
+	tree->connect("item_activated", this, "_tree_item_activated");
+	tree->connect("item_rmb_selected", this, "_rmb_pressed");
 
 	add_constant_override("separation", 3 * EDSCALE);
 }

+ 43 - 36
editor/connections_dialog.h

@@ -53,19 +53,20 @@ class ConnectDialog : public ConfirmationDialog {
 
 	GDCLASS(ConnectDialog, ConfirmationDialog);
 
-	ConfirmationDialog *error;
+	Node *source;
+	StringName signal;
 	LineEdit *dst_path;
 	LineEdit *dst_method;
+	ConnectDialogBinds *cdbinds;
+	bool bEditMode;
+
 	SceneTreeEditor *tree;
+	ConfirmationDialog *error;
+	PropertyEditor *bind_editor;
 	OptionButton *type_list;
 	CheckButton *deferred;
 	CheckButton *oneshot;
 	CheckButton *make_callback;
-	PropertyEditor *bind_editor;
-	Node *source;
-	StringName signal;
-	ConnectDialogBinds *cdbinds;
-	bool bEditMode;
 
 	void ok_pressed();
 	void _cancel_pressed();
@@ -78,17 +79,18 @@ protected:
 	static void _bind_methods();
 
 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;
+	StringName get_signal_name() const;
+	NodePath get_dst_path() const;
+	void set_dst_node(Node *p_node);
+	StringName get_dst_method_name() const;
+	void set_dst_method(const StringName &p_method);
+	Vector<Variant> get_binds() const;
+
+	bool get_make_callback() { return make_callback->is_visible() && make_callback->is_pressed(); }
 	bool get_deferred() const;
 	bool get_oneshot() const;
 	bool is_editing() const;
-	Vector<Variant> get_binds() const;
-	void set_dst_method(const StringName &p_method);
-	void set_dst_node(Node *p_node);
 
 	void init(Connection c, bool bEdit = false);
 
@@ -96,56 +98,61 @@ public:
 	~ConnectDialog();
 };
 
+//========================================
+
 class ConnectionsDock : public VBoxContainer {
 
 	GDCLASS(ConnectionsDock, VBoxContainer);
 
+	//Right-click Pop-up Menu Options.
 	enum SignalMenuOption {
-		CONNECT
+		CONNECT,
+		DISCONNECT_ALL
 	};
 
 	enum SlotMenuOption {
 		EDIT,
+		GO_TO_SCRIPT,
 		DISCONNECT
 	};
 
-	Button *connect_button;
-	EditorNode *editor;
-	Node *node;
+	Node *selectedNode;
 	Tree *tree;
-	ConfirmationDialog *remove_confirm;
-	ConnectDialog *connect_dialog;
+	EditorNode *editor;
 
+	ConfirmationDialog *disconnect_all_dialog;
+	ConnectDialog *connect_dialog;
+	Button *connect_button;
 	PopupMenu *signal_menu;
 	PopupMenu *slot_menu;
+	UndoRedo *undo_redo;
 
-	void _close();
 	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 );
-	void _handle_slot_option( int option );
-	void _rmb_pressed( Vector2 position );
-	UndoRedo *undo_redo;
+	void _connect(Connection cToMake);
+	void _disconnect(TreeItem &item);
+	void _disconnect_all();
+
+	void _tree_item_selected();
+	void _tree_item_activated();
+	bool _is_item_signal(TreeItem &item);
+
+	void _open_connection_dialog(TreeItem &item);
+	void _open_connection_dialog(Connection cToEdit);
+	void _go_to_script(TreeItem &item);
+
+	void _handle_signal_menu_option(int option);
+	void _handle_slot_menu_option(int option);
+	void _rmb_pressed(Vector2 position);
+	void _close();
 
 protected:
 	void _connect_pressed();
 	void _notification(int p_what);
 	static void _bind_methods();
 
-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; }
-
 	void set_node(Node *p_node);
-	String get_selected_type();
 	void update_tree();
 
 	ConnectionsDock(EditorNode *p_editor = NULL);