Reorganized connection dialog for much improved ease of use.

-Removed dest path field
-Added a "Source" signal
-Added an "Advanced" button to hide complexity
-Fix bug on Tree to make sure "ensure visible" works on hidden trees
-Fix bug on TextEdit to ensure signals created with script not open sill focus the right line
This commit is contained in:
Juan Linietsky 2019-04-11 23:21:48 -03:00
parent da65d54649
commit 9f4b5a91c0
7 changed files with 153 additions and 41 deletions

View File

@ -37,6 +37,25 @@
#include "scene/gui/label.h" #include "scene/gui/label.h"
#include "scene/gui/popup_menu.h" #include "scene/gui/popup_menu.h"
static Node *_find_first_script(Node *p_root, Node *p_node) {
if (p_node != p_root && p_node->get_owner() != p_root) {
return NULL;
}
if (!p_node->get_script().is_null()) {
return p_node;
}
for (int i = 0; i < p_node->get_child_count(); i++) {
Node *ret = _find_first_script(p_root, p_node->get_child(i));
if (ret) {
return ret;
}
}
return NULL;
}
class ConnectDialogBinds : public Object { class ConnectDialogBinds : public Object {
GDCLASS(ConnectDialogBinds, Object); GDCLASS(ConnectDialogBinds, Object);
@ -122,17 +141,8 @@ void ConnectDialog::_tree_node_selected() {
Node *current = tree->get_selected(); Node *current = tree->get_selected();
if (!current) { dst_path = source->get_path_to(current);
make_callback->hide(); get_ok()->set_disabled(false);
return;
}
if (current->get_script().is_null())
make_callback->hide();
else
make_callback->show();
dst_path->set_text(source->get_path_to(current));
} }
/* /*
@ -195,6 +205,7 @@ void ConnectDialog::_notification(int p_what) {
void ConnectDialog::_bind_methods() { void ConnectDialog::_bind_methods() {
ClassDB::bind_method("_advanced_pressed", &ConnectDialog::_advanced_pressed);
ClassDB::bind_method("_cancel", &ConnectDialog::_cancel_pressed); ClassDB::bind_method("_cancel", &ConnectDialog::_cancel_pressed);
ClassDB::bind_method("_tree_node_selected", &ConnectDialog::_tree_node_selected); ClassDB::bind_method("_tree_node_selected", &ConnectDialog::_tree_node_selected);
ClassDB::bind_method("_add_bind", &ConnectDialog::_add_bind); ClassDB::bind_method("_add_bind", &ConnectDialog::_add_bind);
@ -215,7 +226,7 @@ StringName ConnectDialog::get_signal_name() const {
NodePath ConnectDialog::get_dst_path() const { NodePath ConnectDialog::get_dst_path() const {
return dst_path->get_text(); return dst_path;
} }
void ConnectDialog::set_dst_node(Node *p_node) { void ConnectDialog::set_dst_node(Node *p_node) {
@ -272,8 +283,13 @@ void ConnectDialog::init(Connection c, bool bEdit) {
tree->set_selected(NULL); tree->set_selected(NULL);
tree->set_marked(source, true); tree->set_marked(source, true);
if (c.target) {
get_ok()->set_disabled(false);
set_dst_node(static_cast<Node *>(c.target)); set_dst_node(static_cast<Node *>(c.target));
set_dst_method(c.method); set_dst_method(c.method);
} else {
get_ok()->set_disabled(true);
}
bool bDeferred = (c.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED; bool bDeferred = (c.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED;
bool bOneshot = (c.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT; bool bOneshot = (c.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT;
@ -288,6 +304,36 @@ void ConnectDialog::init(Connection c, bool bEdit) {
bEditMode = bEdit; bEditMode = bEdit;
} }
void ConnectDialog::popup_dialog(const String &p_for_signal, bool p_advanced) {
advanced->set_pressed(p_advanced);
from_signal->set_text(p_for_signal);
error_label->add_color_override("font_color", get_color("error_color", "Editor"));
if (p_advanced) {
popup_centered(Size2(900, 500) * EDSCALE);
connect_to_label->set_text("Connect to Node:");
tree->set_connect_to_script_mode(false);
error_label->hide();
} else {
popup_centered(Size2(700, 500) * EDSCALE);
connect_to_label->set_text("Connect to Script:");
tree->set_connect_to_script_mode(true);
if (!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root())) {
error_label->show();
} else {
error_label->hide();
}
}
}
void ConnectDialog::_advanced_pressed() {
vbc_right->set_visible(advanced->is_pressed());
popup_dialog(from_signal->get_text(), advanced->is_pressed());
}
ConnectDialog::ConnectDialog() { ConnectDialog::ConnectDialog() {
VBoxContainer *vbc = memnew(VBoxContainer); VBoxContainer *vbc = memnew(VBoxContainer);
@ -301,15 +347,27 @@ ConnectDialog::ConnectDialog() {
main_hb->add_child(vbc_left); main_hb->add_child(vbc_left);
vbc_left->set_h_size_flags(SIZE_EXPAND_FILL); vbc_left->set_h_size_flags(SIZE_EXPAND_FILL);
from_signal = memnew(LineEdit);
from_signal->set_editable(false);
vbc_left->add_margin_child(TTR("From Signal:"), from_signal);
tree = memnew(SceneTreeEditor(false)); tree = memnew(SceneTreeEditor(false));
tree->get_scene_tree()->connect("item_activated", this, "_ok"); tree->get_scene_tree()->connect("item_activated", this, "_ok");
tree->connect("node_selected", this, "_tree_node_selected"); tree->connect("node_selected", this, "_tree_node_selected");
tree->set_connect_to_script_mode(true);
vbc_left->add_margin_child(TTR("Connect To Node:"), tree, true); Node *mc = vbc_left->add_margin_child(TTR("Connect To Script:"), tree, true);
connect_to_label = Object::cast_to<Label>(vbc_left->get_child(mc->get_index() - 1));
VBoxContainer *vbc_right = memnew(VBoxContainer); error_label = memnew(Label);
error_label->set_text(TTR("Scene does not contain any script."));
vbc_left->add_child(error_label);
error_label->hide();
vbc_right = memnew(VBoxContainer);
main_hb->add_child(vbc_right); main_hb->add_child(vbc_right);
vbc_right->set_h_size_flags(SIZE_EXPAND_FILL); vbc_right->set_h_size_flags(SIZE_EXPAND_FILL);
vbc_right->hide();
HBoxContainer *add_bind_hb = memnew(HBoxContainer); HBoxContainer *add_bind_hb = memnew(HBoxContainer);
@ -347,16 +405,18 @@ ConnectDialog::ConnectDialog() {
vbc_right->add_margin_child(TTR("Extra Call Arguments:"), bind_editor, true); vbc_right->add_margin_child(TTR("Extra Call Arguments:"), bind_editor, true);
dst_path = memnew(LineEdit);
vbc->add_margin_child(TTR("Path to Node:"), dst_path);
HBoxContainer *dstm_hb = memnew(HBoxContainer); HBoxContainer *dstm_hb = memnew(HBoxContainer);
vbc->add_margin_child("Method In Node:", dstm_hb); vbc_left->add_margin_child("Method to Create:", dstm_hb);
dst_method = memnew(LineEdit); dst_method = memnew(LineEdit);
dst_method->set_h_size_flags(SIZE_EXPAND_FILL); dst_method->set_h_size_flags(SIZE_EXPAND_FILL);
dstm_hb->add_child(dst_method); dstm_hb->add_child(dst_method);
advanced = memnew(CheckBox);
dstm_hb->add_child(advanced);
advanced->set_text(TTR("Advanced.."));
advanced->connect("pressed", this, "_advanced_pressed");
/* /*
dst_method_list = memnew( MenuButton ); dst_method_list = memnew( MenuButton );
dst_method_list->set_text("List..."); dst_method_list->set_text("List...");
@ -368,19 +428,13 @@ ConnectDialog::ConnectDialog() {
dst_method_list->set_end( Point2( 15,39 ) ); dst_method_list->set_end( Point2( 15,39 ) );
*/ */
make_callback = memnew(CheckButton);
make_callback->set_toggle_mode(true);
make_callback->set_pressed(EDITOR_DEF("text_editor/tools/create_signal_callbacks", true));
make_callback->set_text(TTR("Make Function"));
dstm_hb->add_child(make_callback);
deferred = memnew(CheckButton); deferred = memnew(CheckButton);
deferred->set_text(TTR("Deferred")); deferred->set_text(TTR("Deferred"));
dstm_hb->add_child(deferred); vbc_right->add_child(deferred);
oneshot = memnew(CheckButton); oneshot = memnew(CheckButton);
oneshot->set_text(TTR("Oneshot")); oneshot->set_text(TTR("Oneshot"));
dstm_hb->add_child(oneshot); vbc_right->add_child(oneshot);
set_as_toplevel(true); set_as_toplevel(true);
@ -429,7 +483,8 @@ void ConnectionsDock::_make_or_edit_connection() {
bool oshot = connect_dialog->get_oneshot(); bool oshot = connect_dialog->get_oneshot();
cToMake.flags = CONNECT_PERSIST | (defer ? CONNECT_DEFERRED : 0) | (oshot ? CONNECT_ONESHOT : 0); cToMake.flags = CONNECT_PERSIST | (defer ? CONNECT_DEFERRED : 0) | (oshot ? CONNECT_ONESHOT : 0);
bool add_script_function = connect_dialog->get_make_callback(); //conditions to add function, must have a script and must have a method
bool add_script_function = !target->get_script().is_null() && !ClassDB::has_method(target->get_class(), cToMake.method);
PoolStringArray script_function_args; PoolStringArray script_function_args;
if (add_script_function) { if (add_script_function) {
// pick up args here before "it" is deleted by update_tree // pick up args here before "it" is deleted by update_tree
@ -568,6 +623,7 @@ bool ConnectionsDock::_is_item_signal(TreeItem &item) {
/* /*
Open connection dialog with TreeItem data to CREATE a brand-new connection. Open connection dialog with TreeItem data to CREATE a brand-new connection.
*/ */
void ConnectionsDock::_open_connection_dialog(TreeItem &item) { void ConnectionsDock::_open_connection_dialog(TreeItem &item) {
String signal = item.get_metadata(0).operator Dictionary()["name"]; String signal = item.get_metadata(0).operator Dictionary()["name"];
@ -590,6 +646,10 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &item) {
} }
Node *dst_node = selectedNode->get_owner() ? selectedNode->get_owner() : selectedNode; Node *dst_node = selectedNode->get_owner() ? selectedNode->get_owner() : selectedNode;
if (!dst_node || dst_node->get_script().is_null()) {
dst_node = _find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root());
}
StringName dst_method = "_on_" + midname + "_" + signal; StringName dst_method = "_on_" + midname + "_" + signal;
Connection c; Connection c;
@ -598,9 +658,10 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &item) {
c.target = dst_node; c.target = dst_node;
c.method = dst_method; c.method = dst_method;
//connect_dialog->set_title(TTR("Connect Signal: ") + signalname);
connect_dialog->popup_dialog(signalname, false);
connect_dialog->init(c); connect_dialog->init(c);
connect_dialog->set_title(TTR("Connect Signal: ") + signalname); connect_dialog->set_title(TTR("Connect a Signal to a Method"));
connect_dialog->popup_centered_ratio();
} }
/* /*
@ -612,9 +673,9 @@ void ConnectionsDock::_open_connection_dialog(Connection cToEdit) {
Node *dst = static_cast<Node *>(cToEdit.target); 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->set_title(TTR("Edit Connection:") + cToEdit.signal);
connect_dialog->popup_centered_ratio(); connect_dialog->popup_centered_ratio();
connect_dialog->init(cToEdit, true);
} }
} }

View File

@ -53,12 +53,15 @@ class ConnectDialog : public ConfirmationDialog {
GDCLASS(ConnectDialog, ConfirmationDialog); GDCLASS(ConnectDialog, ConfirmationDialog);
Label *connect_to_label;
LineEdit *from_signal;
Node *source; Node *source;
StringName signal; StringName signal;
LineEdit *dst_path;
LineEdit *dst_method; LineEdit *dst_method;
ConnectDialogBinds *cdbinds; ConnectDialogBinds *cdbinds;
bool bEditMode; bool bEditMode;
NodePath dst_path;
VBoxContainer *vbc_right;
SceneTreeEditor *tree; SceneTreeEditor *tree;
ConfirmationDialog *error; ConfirmationDialog *error;
@ -66,13 +69,16 @@ class ConnectDialog : public ConfirmationDialog {
OptionButton *type_list; OptionButton *type_list;
CheckButton *deferred; CheckButton *deferred;
CheckButton *oneshot; CheckButton *oneshot;
CheckButton *make_callback; CheckBox *advanced;
Label *error_label;
void ok_pressed(); void ok_pressed();
void _cancel_pressed(); void _cancel_pressed();
void _tree_node_selected(); void _tree_node_selected();
void _add_bind(); void _add_bind();
void _remove_bind(); void _remove_bind();
void _advanced_pressed();
protected: protected:
void _notification(int p_what); void _notification(int p_what);
@ -87,13 +93,13 @@ public:
void set_dst_method(const StringName &p_method); void set_dst_method(const StringName &p_method);
Vector<Variant> get_binds() const; Vector<Variant> get_binds() const;
bool get_make_callback() { return make_callback->is_visible() && make_callback->is_pressed(); }
bool get_deferred() const; bool get_deferred() const;
bool get_oneshot() const; bool get_oneshot() const;
bool is_editing() const; bool is_editing() const;
void init(Connection c, bool bEdit = false); void init(Connection c, bool bEdit = false);
void popup_dialog(const String &p_for_signal, bool p_advanced);
ConnectDialog(); ConnectDialog();
~ConnectDialog(); ~ConnectDialog();
}; };

View File

@ -48,6 +48,9 @@ Node *SceneTreeEditor::get_scene_node() {
void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id) { void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id) {
if (connect_to_script_mode) {
return; //dont do anything in this mode
}
TreeItem *item = Object::cast_to<TreeItem>(p_item); TreeItem *item = Object::cast_to<TreeItem>(p_item);
ERR_FAIL_COND(!item); ERR_FAIL_COND(!item);
@ -190,7 +193,25 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
item->set_icon(0, icon); item->set_icon(0, icon);
item->set_metadata(0, p_node->get_path()); item->set_metadata(0, p_node->get_path());
if (part_of_subscene) { if (connect_to_script_mode) {
Color accent = get_color("accent_color", "Editor");
if (!p_node->get_script().is_null()) {
//has script
item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT);
} else {
//has no script
item->set_custom_color(0, get_color("disabled_font_color", "Editor"));
item->set_selectable(0, false);
accent.a *= 0.7;
}
if (marked.has(p_node)) {
item->set_text(0, String(p_node->get_name()) + " " + TTR("(Connecting From)"));
item->set_custom_color(0, accent);
}
} else if (part_of_subscene) {
//item->set_selectable(0,marked_selectable); //item->set_selectable(0,marked_selectable);
if (valid_types.size() == 0) { if (valid_types.size() == 0) {
@ -199,7 +220,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
} else if (marked.has(p_node)) { } else if (marked.has(p_node)) {
if (!connect_to_script_mode) {
item->set_selectable(0, marked_selectable); item->set_selectable(0, marked_selectable);
}
item->set_custom_color(0, get_color("error_color", "Editor")); item->set_custom_color(0, get_color("error_color", "Editor"));
} else if (!marked_selectable && !marked_children_selectable) { } else if (!marked_selectable && !marked_children_selectable) {
@ -620,6 +643,7 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
item->set_as_cursor(0); item->set_as_cursor(0);
selected = p_node; selected = p_node;
tree->ensure_cursor_is_visible(); tree->ensure_cursor_is_visible();
} else { } else {
if (!p_node) if (!p_node)
selected = NULL; selected = NULL;
@ -974,6 +998,11 @@ void SceneTreeEditor::_warning_changed(Node *p_for_node) {
update_timer->start(); update_timer->start();
} }
void SceneTreeEditor::set_connect_to_script_mode(bool p_enable) {
connect_to_script_mode = p_enable;
update_tree();
}
void SceneTreeEditor::_bind_methods() { void SceneTreeEditor::_bind_methods() {
ClassDB::bind_method("_tree_changed", &SceneTreeEditor::_tree_changed); ClassDB::bind_method("_tree_changed", &SceneTreeEditor::_tree_changed);
@ -1016,6 +1045,7 @@ void SceneTreeEditor::_bind_methods() {
SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_open_instance) { SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_open_instance) {
connect_to_script_mode = false;
undo_redo = NULL; undo_redo = NULL;
tree_dirty = true; tree_dirty = true;
selected = NULL; selected = NULL;

View File

@ -67,6 +67,8 @@ class SceneTreeEditor : public Control {
AcceptDialog *error; AcceptDialog *error;
AcceptDialog *warning; AcceptDialog *warning;
bool connect_to_script_mode;
int blocked; int blocked;
void _compute_hash(Node *p_node, uint64_t &hash); void _compute_hash(Node *p_node, uint64_t &hash);
@ -151,6 +153,8 @@ public:
void update_tree() { _update_tree(); } void update_tree() { _update_tree(); }
void set_connect_to_script_mode(bool p_enable);
Tree *get_scene_tree() { return tree; } Tree *get_scene_tree() { return tree; }
SceneTreeEditor(bool p_label = true, bool p_can_rename = false, bool p_can_open_instance = false); SceneTreeEditor(bool p_label = true, bool p_can_rename = false, bool p_can_open_instance = false);

View File

@ -590,6 +590,12 @@ void TextEdit::_notification(int p_what) {
} }
} break; } break;
case NOTIFICATION_DRAW: { case NOTIFICATION_DRAW: {
if (first_draw) {
//size may not be the final one, so attempts to ensure cursor was visible may have failed
adjust_viewport_to_cursor();
first_draw = false;
}
Size2 size = get_size(); Size2 size = get_size();
if ((!has_focus() && !menu->has_focus()) || !window_has_focus) { if ((!has_focus() && !menu->has_focus()) || !window_has_focus) {
draw_caret = false; draw_caret = false;
@ -6356,6 +6362,7 @@ TextEdit::TextEdit() {
menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z); menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z); menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
menu->connect("id_pressed", this, "menu_option"); menu->connect("id_pressed", this, "menu_option");
first_draw = true;
} }
TextEdit::~TextEdit() { TextEdit::~TextEdit() {

View File

@ -275,6 +275,7 @@ private:
int wrap_at; int wrap_at;
int wrap_right_offset; int wrap_right_offset;
bool first_draw;
bool setting_row; bool setting_row;
bool draw_tabs; bool draw_tabs;
bool override_selected_font_color; bool override_selected_font_color;

View File

@ -3388,10 +3388,13 @@ void Tree::ensure_cursor_is_visible() {
int h = compute_item_height(selected) + cache.vseparation; int h = compute_item_height(selected) + cache.vseparation;
int screenh = get_size().height - h_scroll->get_combined_minimum_size().height; int screenh = get_size().height - h_scroll->get_combined_minimum_size().height;
if (ofs + h > v_scroll->get_value() + screenh) if (h > screenh) { //screen size is too small, maybe it was not resized yet.
v_scroll->call_deferred("set_value", ofs - screenh + h);
else if (ofs < v_scroll->get_value())
v_scroll->set_value(ofs); v_scroll->set_value(ofs);
} else if (ofs + h > v_scroll->get_value() + screenh) {
v_scroll->call_deferred("set_value", ofs - screenh + h);
} else if (ofs < v_scroll->get_value()) {
v_scroll->set_value(ofs);
}
} }
int Tree::get_pressed_button() const { int Tree::get_pressed_button() const {