Improve Visual Script editor to suggest the proper visual script nodes.

This commit is contained in:
David Cambré 2021-11-20 13:52:37 +01:00
parent 324dca57af
commit 3a82f66974
4 changed files with 1570 additions and 776 deletions

View File

@ -1366,7 +1366,7 @@ void VisualScriptEditor::_create_function() {
}
void VisualScriptEditor::_add_node_dialog() {
_generic_search(script->get_instance_base_type(), graph->get_global_position() + Vector2(55, 80), true);
_generic_search(graph->get_global_position() + Vector2(55, 80), true);
}
void VisualScriptEditor::_add_func_input() {
@ -1442,7 +1442,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
if (p_button == 1) {
// Ensure script base exists otherwise use custom base type.
ERR_FAIL_COND(script.is_null());
new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), String(), true);
new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), true);
return;
} else if (p_button == 0) {
String name = _validate_name("new_function");
@ -1948,14 +1948,14 @@ void VisualScriptEditor::_on_nodes_duplicate() {
}
}
void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool node_centered) {
void VisualScriptEditor::_generic_search(Vector2 pos, bool node_centered) {
if (node_centered) {
port_action_pos = graph->get_size() / 2.0f;
} else {
port_action_pos = graph->get_viewport()->get_mouse_position() - graph->get_global_position();
}
new_connect_node_select->select_from_visual_script(p_base_type, false, false); // neither connecting nor reset text
new_connect_node_select->select_from_visual_script(script, false); // do not reset text
// Ensure that the dialog fits inside the graph.
Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
@ -1992,7 +1992,7 @@ void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
}
}
if (is_empty_selection && clipboard->nodes.is_empty()) {
_generic_search(script->get_instance_base_type(), mouse_up_position);
_generic_search();
} else {
popup_menu->set_item_disabled(int(EDIT_CUT_NODES), is_empty_selection);
popup_menu->set_item_disabled(int(EDIT_COPY_NODES), is_empty_selection);
@ -2446,7 +2446,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
drop_position = pos;
drop_node = node;
drop_path = sn->get_path_to(node);
new_connect_node_select->select_from_instance(node, "", false, node->get_class());
new_connect_node_select->select_from_instance(node, false);
}
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
@ -3234,19 +3234,34 @@ void VisualScriptEditor::_port_action_menu(int p_option) {
n->set_base_type("Object");
}
String type_string;
String base_script = "";
if (script->get_node(port_action_node)->get_output_value_port_count() > 0) {
type_string = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
VisualScriptFunctionCall *vsfc = Object::cast_to<VisualScriptFunctionCall>(*script->get_node(port_action_node));
if (vsfc) {
base_script = vsfc->get_base_script();
} else {
VisualScriptPropertyGet *vspg = Object::cast_to<VisualScriptPropertyGet>(*script->get_node(port_action_node));
if (vspg) {
base_script = vspg->get_base_script();
} else {
VisualScriptPropertySet *vsps = Object::cast_to<VisualScriptPropertySet>(*script->get_node(port_action_node));
if (vsps) {
base_script = vsps->get_base_script();
}
}
}
}
if (tg.type == Variant::OBJECT) {
if (tg.script.is_valid()) {
new_connect_node_select->select_from_script(tg.script, "");
} else if (!type_string.is_empty()) {
new_connect_node_select->select_from_base_type(type_string);
new_connect_node_select->select_from_script(tg.script);
} else if (type_string != String()) {
new_connect_node_select->select_from_base_type(type_string, base_script);
} else {
new_connect_node_select->select_from_base_type(n->get_base_type());
new_connect_node_select->select_from_base_type(n->get_base_type(), base_script);
}
} else if (tg.type == Variant::NIL) {
new_connect_node_select->select_from_base_type("");
new_connect_node_select->select_from_base_type("", base_script);
} else {
new_connect_node_select->select_from_basic_type(tg.type);
}
@ -3309,66 +3324,54 @@ void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<Visua
}
void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting) {
#ifdef OSX_ENABLED
bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::META);
#else
bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
#endif
Vector2 pos = _get_pos_in_graph(port_action_pos);
Set<int> vn;
bool port_node_exists = true;
if (drop_position != Vector2()) {
pos = drop_position;
}
drop_position = Vector2();
bool port_node_exists = true;
Ref<VisualScriptNode> vnode;
Ref<VisualScriptNode> vnode_old;
if (port_node_exists && p_connecting) {
vnode_old = script->get_node(port_action_node);
}
// if (func == StringName()) {
// func = default_func;
// port_node_exists = false;
// }
if (p_category.begins_with("VisualScriptNode")) {
Ref<VisualScriptNode> n = VisualScriptLanguage::singleton->create_node_from_name(p_text);
if (p_category == "visualscript") {
Ref<VisualScriptNode> vnode_new = VisualScriptLanguage::singleton->create_node_from_name(p_text);
Ref<VisualScriptNode> vnode_old;
if (port_node_exists && p_connecting) {
vnode_old = script->get_node(port_action_node);
}
int new_id = script->get_available_id();
if (Object::cast_to<VisualScriptOperator>(vnode_new.ptr()) && vnode_old.is_valid()) {
Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type;
Object::cast_to<VisualScriptOperator>(vnode_new.ptr())->set_typed(type);
}
if (Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr()) && vnode_old.is_valid()) {
if (Object::cast_to<VisualScriptTypeCast>(n.ptr()) && vnode_old.is_valid()) {
Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type;
String hint_name = vnode_old->get_output_value_port_info(port_action_output).hint_string;
if (type == Variant::OBJECT) {
Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(hint_name);
Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(hint_name);
} else if (type == Variant::NIL) {
Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type("");
Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type("");
} else {
Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(Variant::get_type_name(type));
Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(Variant::get_type_name(type));
}
}
undo_redo->create_action(TTR("Add Node"));
undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode_new, pos);
if (vnode_old.is_valid() && p_connecting) {
connect_seq(vnode_old, vnode_new, new_id);
connect_data(vnode_old, vnode_new, new_id);
}
undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
return;
vnode = n;
}
Ref<VisualScriptNode> vnode;
Ref<VisualScriptPropertySet> script_prop_set;
if (p_category == String("method")) {
if (p_category == String("Class") && !p_connecting) {
Ref<VisualScriptFunctionCall> n;
n.instantiate();
n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SINGLETON);
n->set_singleton("ClassDB");
n->set_function("instantiate");
// Did not find a way to edit the input port value
vnode = n;
} else if (p_category == String("class_method")) {
Ref<VisualScriptFunctionCall> n;
n.instantiate();
if (!drop_path.is_empty()) {
@ -3386,96 +3389,151 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
}
}
vnode = n;
} else if (p_category == String("set")) {
Ref<VisualScriptPropertySet> n;
} else if (p_category == String("class_property")) {
Vector<String> property_path = p_text.split(":");
if (held_ctrl) {
Ref<VisualScriptPropertySet> n;
n.instantiate();
n->set_property(property_path[1]);
if (!drop_path.is_empty()) {
if (drop_path == ".") {
n->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF);
} else {
n->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH);
n->set_base_path(drop_path);
}
}
if (drop_node) {
n->set_base_type(drop_node->get_class());
if (drop_node->get_script_instance()) {
n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());
}
}
vnode = n;
} else {
Ref<VisualScriptPropertyGet> n;
n.instantiate();
n->set_property(property_path[1]);
if (!drop_path.is_empty()) {
if (drop_path == ".") {
n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF);
} else {
n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH);
n->set_base_path(drop_path);
}
}
if (drop_node) {
n->set_base_type(drop_node->get_class());
if (drop_node->get_script_instance()) {
n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());
}
}
vnode = n;
}
} else if (p_category == String("class_constant")) {
Vector<String> property_path = p_text.split(":");
if (ClassDB::class_exists(property_path[0])) {
Ref<VisualScriptClassConstant> n;
n.instantiate();
n->set_base_type(property_path[0]);
n->set_class_constant(property_path[1]);
vnode = n;
} else {
Ref<VisualScriptBasicTypeConstant> n;
n.instantiate();
if (property_path[0] == "Nil") {
n->set_basic_type(Variant::NIL);
} else if (property_path[0] == "bool") {
n->set_basic_type(Variant::BOOL);
} else if (property_path[0] == "int") {
n->set_basic_type(Variant::INT);
} else if (property_path[0] == "float") {
n->set_basic_type(Variant::FLOAT);
} else if (property_path[0] == "String") {
n->set_basic_type(Variant::STRING);
} else if (property_path[0] == "Vector2") {
n->set_basic_type(Variant::VECTOR2);
} else if (property_path[0] == "Vector2i") {
n->set_basic_type(Variant::VECTOR2I);
} else if (property_path[0] == "Rect2") {
n->set_basic_type(Variant::RECT2);
} else if (property_path[0] == "Rect2i") {
n->set_basic_type(Variant::RECT2I);
} else if (property_path[0] == "Transform2D") {
n->set_basic_type(Variant::TRANSFORM2D);
} else if (property_path[0] == "Vector3") {
n->set_basic_type(Variant::VECTOR3);
} else if (property_path[0] == "Vector3i") {
n->set_basic_type(Variant::VECTOR3I);
} else if (property_path[0] == "Plane") {
n->set_basic_type(Variant::PLANE);
} else if (property_path[0] == "ABB") {
n->set_basic_type(Variant::AABB);
} else if (property_path[0] == "Quaternion") {
n->set_basic_type(Variant::QUATERNION);
} else if (property_path[0] == "Basis") {
n->set_basic_type(Variant::BASIS);
} else if (property_path[0] == "Transform3D") {
n->set_basic_type(Variant::TRANSFORM3D);
} else if (property_path[0] == "Color") {
n->set_basic_type(Variant::COLOR);
} else if (property_path[0] == "RID") {
n->set_basic_type(Variant::RID);
} else if (property_path[0] == "Object") {
n->set_basic_type(Variant::OBJECT);
} else if (property_path[0] == "Callable") {
n->set_basic_type(Variant::CALLABLE);
} else if (property_path[0] == "Signal") {
n->set_basic_type(Variant::SIGNAL);
} else if (property_path[0] == "StringName") {
n->set_basic_type(Variant::STRING_NAME);
} else if (property_path[0] == "NodePath") {
n->set_basic_type(Variant::NODE_PATH);
} else if (property_path[0] == "Dictionary") {
n->set_basic_type(Variant::DICTIONARY);
} else if (property_path[0] == "Array") {
n->set_basic_type(Variant::ARRAY);
} else if (property_path[0] == "PackedByteArray") {
n->set_basic_type(Variant::PACKED_BYTE_ARRAY);
} else if (property_path[0] == "PackedInt32Array") {
n->set_basic_type(Variant::PACKED_INT32_ARRAY);
} else if (property_path[0] == "PackedInt64Array") {
n->set_basic_type(Variant::PACKED_INT64_ARRAY);
} else if (property_path[0] == "PackedFloat32Array") {
n->set_basic_type(Variant::PACKED_FLOAT32_ARRAY);
} else if (property_path[0] == "PackedStringArray") {
n->set_basic_type(Variant::PACKED_STRING_ARRAY);
} else if (property_path[0] == "PackedVector2Array") {
n->set_basic_type(Variant::PACKED_VECTOR2_ARRAY);
} else if (property_path[0] == "PackedVector3Array") {
n->set_basic_type(Variant::PACKED_VECTOR3_ARRAY);
} else if (property_path[0] == "PackedColorArray") {
n->set_basic_type(Variant::PACKED_COLOR_ARRAY);
}
n->set_basic_type_constant(property_path[1]);
vnode = n;
}
} else if (p_category == String("class_signal")) {
Vector<String> property_path = p_text.split(":");
ERR_FAIL_COND(!(script->has_custom_signal(property_path[1]) || ClassDB::has_signal(script->get_instance_base_type(), property_path[1])));
Ref<VisualScriptEmitSignal> n;
n.instantiate();
if (!drop_path.is_empty()) {
if (drop_path == ".") {
n->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF);
} else {
n->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH);
n->set_base_path(drop_path);
}
}
if (drop_node) {
n->set_base_type(drop_node->get_class());
if (drop_node->get_script_instance()) {
n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());
}
}
vnode = n;
script_prop_set = n;
} else if (p_category == String("get")) {
Ref<VisualScriptPropertyGet> n;
n.instantiate();
n->set_property(p_text);
if (!drop_path.is_empty()) {
if (drop_path == ".") {
n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF);
} else {
n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH);
n->set_base_path(drop_path);
}
}
if (drop_node) {
n->set_base_type(drop_node->get_class());
if (drop_node->get_script_instance()) {
n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());
}
}
n->set_signal(property_path[1]);
vnode = n;
}
drop_path = String();
drop_node = nullptr;
if (p_category == String("action")) {
if (p_text == "VisualScriptCondition") {
Ref<VisualScriptCondition> n;
n.instantiate();
vnode = n;
}
if (p_text == "VisualScriptSwitch") {
Ref<VisualScriptSwitch> n;
n.instantiate();
vnode = n;
} else if (p_text == "VisualScriptSequence") {
Ref<VisualScriptSequence> n;
n.instantiate();
vnode = n;
} else if (p_text == "VisualScriptIterator") {
Ref<VisualScriptIterator> n;
n.instantiate();
vnode = n;
} else if (p_text == "VisualScriptWhile") {
Ref<VisualScriptWhile> n;
n.instantiate();
vnode = n;
} else if (p_text == "VisualScriptReturn") {
Ref<VisualScriptReturn> n;
n.instantiate();
vnode = n;
}
if (vnode == nullptr) {
print_error("Category not handled: " + p_category.quote());
}
int new_id = script->get_available_id();
undo_redo->create_action(TTR("Add Node"));
undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);
undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph", new_id);
undo_redo->add_undo_method(this, "_update_graph", new_id);
undo_redo->commit_action();
if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr()) && p_category != "Class") {
Vector<String> property_path = p_text.split(":");
String class_of_method = property_path[0];
String method_name = property_path[1];
if (script_prop_set.is_valid()) {
script_prop_set->set_property(p_text);
}
port_action_new_node = new_id;
Ref<VisualScriptNode> vsn = script->get_node(port_action_new_node);
if (Object::cast_to<VisualScriptFunctionCall>(vsn.ptr())) {
Ref<VisualScriptFunctionCall> vsfc = vsn;
vsfc->set_function(p_text);
Ref<VisualScriptFunctionCall> vsfc = vnode;
vsfc->set_function(method_name);
if (port_node_exists && p_connecting) {
VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
@ -3492,7 +3550,7 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
if (!base_type.is_empty() && hint == PROPERTY_HINT_TYPE_STRING) {
vsfc->set_base_type(base_type);
}
if (p_text == "call" || p_text == "call_deferred") {
if (method_name == "call" || method_name == "call_deferred") {
vsfc->set_function(String(""));
}
}
@ -3510,8 +3568,8 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
}
if (port_node_exists && p_connecting) {
if (Object::cast_to<VisualScriptPropertySet>(vsn.ptr())) {
Ref<VisualScriptPropertySet> vsp = vsn;
if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) {
Ref<VisualScriptPropertySet> vsp = vnode;
VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
if (tg.type == Variant::OBJECT) {
@ -3540,8 +3598,8 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
}
}
if (Object::cast_to<VisualScriptPropertyGet>(vsn.ptr())) {
Ref<VisualScriptPropertyGet> vsp = vsn;
if (Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())) {
Ref<VisualScriptPropertyGet> vsp = vnode;
VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
if (tg.type == Variant::OBJECT) {
@ -3569,13 +3627,85 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
}
}
}
if (vnode == nullptr) {
print_error("Not able to create node from category: \"" + p_category + "\" and text \"" + p_text + "\" Not created");
return;
}
int new_id = script->get_available_id();
undo_redo->create_action(TTR("Add Node"));
undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);
undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
undo_redo->add_do_method(this, "_update_graph", new_id);
undo_redo->add_undo_method(this, "_update_graph", new_id);
undo_redo->commit_action();
port_action_new_node = new_id;
String base_script = "";
String base_type = "";
if (port_node_exists) {
Ref<VisualScriptNode> vnode_old = script->get_node(port_action_node);
if (vnode_old.is_valid()) {
if (Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())) {
base_type = Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())->get_base_type();
base_script = Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())->get_base_script();
} else if (Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())) {
base_type = Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())->get_base_type();
base_script = Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())->get_base_script();
} else if (Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())) {
base_type = Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())->get_base_type();
base_script = Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())->get_base_script();
} else if (Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())) {
base_type = Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())->get_base_type();
base_script = Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())->get_base_script();
}
}
Vector<String> property_path = p_text.split(":");
if (ClassDB::is_parent_class(script->get_instance_base_type(), property_path[0]) || script->get_path().ends_with(property_path[0].unquote())) {
if (!p_connecting) {
base_type = script->get_instance_base_type();
base_script = script->get_path();
}
} else {
base_type = property_path[0];
base_script = "";
}
if (drop_node) {
Ref<Script> script = drop_node->get_script();
if (script != nullptr) {
base_script = script->get_path();
}
}
if (vnode_old.is_valid() && p_connecting) {
if (base_type == "") {
base_type = property_path[0];
} else if (ClassDB::is_parent_class(property_path[0], base_type)) {
base_type = property_path[0];
}
connect_seq(vnode_old, vnode, port_action_new_node);
connect_data(vnode_old, vnode, port_action_new_node);
}
}
if (Object::cast_to<VisualScriptTypeCast>(vnode.ptr())) {
Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_type(base_type);
Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_script(base_script);
} else if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())) {
Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_type(base_type);
Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_script(base_script);
} else if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) {
Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_type(base_type);
Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_script(base_script);
} else if (Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())) {
Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())->set_base_type(base_type);
Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())->set_base_script(base_script);
}
drop_path = String();
drop_node = nullptr;
_update_graph(port_action_new_node);
}
@ -3625,7 +3755,7 @@ void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<Visual
}
void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting) {
String name = p_text;
String name = p_text.substr(p_text.find_char(':') + 1);
if (script->has_function(name)) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Script already has function '%s'"), name));
return;
@ -3901,7 +4031,7 @@ void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_
void VisualScriptEditor::_menu_option(int p_what) {
switch (p_what) {
case EDIT_ADD_NODE: {
_generic_search(script->get_instance_base_type(), mouse_up_position);
_generic_search();
} break;
case EDIT_DELETE_NODES: {
_on_nodes_delete();
@ -3931,7 +4061,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
} break;
case EDIT_FIND_NODE_TYPE: {
_generic_search(script->get_instance_base_type());
_generic_search();
} break;
case EDIT_COPY_NODES: {
_on_nodes_copy();

View File

@ -85,55 +85,55 @@ class VisualScriptEditor : public ScriptEditorBase {
MEMBER_SIGNAL
};
VBoxContainer *members_section;
MenuButton *edit_menu;
VBoxContainer *members_section = nullptr;
MenuButton *edit_menu = nullptr;
Ref<VisualScript> script;
Button *base_type_select;
Button *base_type_select = nullptr;
LineEdit *func_name_box;
ScrollContainer *func_input_scroll;
VBoxContainer *func_input_vbox;
ConfirmationDialog *function_create_dialog;
LineEdit *func_name_box = nullptr;
ScrollContainer *func_input_scroll = nullptr;
VBoxContainer *func_input_vbox = nullptr;
ConfirmationDialog *function_create_dialog = nullptr;
GraphEdit *graph;
HBoxContainer *status_bar;
Button *toggle_scripts_button;
GraphEdit *graph = nullptr;
HBoxContainer *status_bar = nullptr;
Button *toggle_scripts_button = nullptr;
VisualScriptEditorSignalEdit *signal_editor;
VisualScriptEditorSignalEdit *signal_editor = nullptr;
AcceptDialog *edit_signal_dialog;
EditorInspector *edit_signal_edit;
AcceptDialog *edit_signal_dialog = nullptr;
EditorInspector *edit_signal_edit = nullptr;
VisualScriptPropertySelector *method_select;
VisualScriptPropertySelector *new_connect_node_select;
VisualScriptPropertySelector *new_virtual_method_select;
VisualScriptPropertySelector *method_select = nullptr;
VisualScriptPropertySelector *new_connect_node_select = nullptr;
VisualScriptPropertySelector *new_virtual_method_select = nullptr;
VisualScriptEditorVariableEdit *variable_editor;
VisualScriptEditorVariableEdit *variable_editor = nullptr;
AcceptDialog *edit_variable_dialog;
EditorInspector *edit_variable_edit;
AcceptDialog *edit_variable_dialog = nullptr;
EditorInspector *edit_variable_edit = nullptr;
CustomPropertyEditor *default_value_edit;
CustomPropertyEditor *default_value_edit = nullptr;
UndoRedo *undo_redo;
UndoRedo *undo_redo = nullptr;
Tree *members;
AcceptDialog *function_name_edit;
LineEdit *function_name_box;
Tree *members = nullptr;
AcceptDialog *function_name_edit = nullptr;
LineEdit *function_name_box = nullptr;
Label *hint_text;
Timer *hint_text_timer;
Label *hint_text = nullptr;
Timer *hint_text_timer = nullptr;
Label *select_func_text;
Label *select_func_text = nullptr;
bool updating_graph = false;
void _show_hint(const String &p_hint);
void _hide_timer();
CreateDialog *select_base_type;
CreateDialog *select_base_type = nullptr;
struct VirtualInMenu {
String name;
@ -241,7 +241,7 @@ class VisualScriptEditor : public ScriptEditorBase {
bool node_has_sequence_connections(int p_id);
void _generic_search(String p_base_type = "", Vector2 pos = Vector2(), bool node_centered = false);
void _generic_search(Vector2 pos = Vector2(), bool node_centered = false);
virtual void input(const Ref<InputEvent> &p_event) override;
void _graph_gui_input(const Ref<InputEvent> &p_event);

View File

@ -31,6 +31,7 @@
#ifndef VISUALSCRIPT_PROPERTYSELECTOR_H
#define VISUALSCRIPT_PROPERTYSELECTOR_H
#include "../visual_script.h"
#include "editor/editor_help.h"
#include "editor/property_editor.h"
#include "scene/gui/rich_text_label.h"
@ -38,15 +39,56 @@
class VisualScriptPropertySelector : public ConfirmationDialog {
GDCLASS(VisualScriptPropertySelector, ConfirmationDialog);
enum SearchFlags {
SEARCH_CLASSES = 1 << 0,
SEARCH_CONSTRUCTORS = 1 << 1,
SEARCH_METHODS = 1 << 2,
SEARCH_OPERATORS = 1 << 3,
SEARCH_SIGNALS = 1 << 4,
SEARCH_CONSTANTS = 1 << 5,
SEARCH_PROPERTIES = 1 << 6,
SEARCH_THEME_ITEMS = 1 << 7,
SEARCH_VISUAL_SCRIPT_NODES = 1 << 8,
SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS,
SEARCH_CASE_SENSITIVE = 1 << 29,
SEARCH_SHOW_HIERARCHY = 1 << 30,
};
enum ScopeFlags {
SCOPE_BASE = 1 << 0,
SCOPE_INHERITERS = 1 << 1,
SCOPE_UNRELATED = 1 << 2,
SCOPE_RELATED = SCOPE_BASE | SCOPE_INHERITERS,
SCOPE_ALL = SCOPE_BASE | SCOPE_INHERITERS | SCOPE_UNRELATED
};
LineEdit *search_box;
Tree *search_options;
void _text_changed(const String &p_newtext);
Button *case_sensitive_button;
Button *hierarchy_button;
Button *search_visual_script_nodes;
Button *search_classes;
Button *search_operators;
Button *search_methods;
Button *search_signals;
Button *search_constants;
Button *search_properties;
Button *search_theme_items;
OptionButton *scope_combo;
Tree *results_tree;
class SearchRunner;
Ref<SearchRunner> search_runner;
void _update_icons();
void _sbox_input(const Ref<InputEvent> &p_ie);
void _update_search();
void create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text);
void get_visual_node_names(const String &root_filter, const Set<String> &p_modifiers, bool &found, TreeItem *const root, LineEdit *const search_box);
void _update_results_i(int p_int);
void _update_results_s(String p_string);
void _update_results();
void _confirmed();
void _item_selected();
@ -60,32 +102,118 @@ class VisualScriptPropertySelector : public ConfirmationDialog {
String selected;
Variant::Type type;
String base_type;
String base_script;
ObjectID script;
Object *instance;
bool virtuals_only;
bool seq_connect;
VBoxContainer *vbc;
Vector<Variant::Type> type_filter;
VBoxContainer *vbox;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void select_method_from_base_type(const String &p_base, const String &p_current = "", const bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true);
void select_from_base_type(const String &p_base, const String &p_current = "", bool p_virtuals_only = false, bool p_seq_connect = false, const bool p_connecting = true, bool clear_text = true);
void select_from_script(const Ref<Script> &p_script, const String &p_current = "", const bool p_connecting = true, bool clear_text = true);
void select_from_basic_type(Variant::Type p_type, const String &p_current = "", const bool p_connecting = true, bool clear_text = true);
void select_from_action(const String &p_type, const String &p_current = "", const bool p_connecting = true, bool clear_text = true);
void select_from_instance(Object *p_instance, const String &p_current = "", const bool p_connecting = true, const String &p_basetype = "", bool clear_text = true);
void select_from_visual_script(const String &p_base, const bool p_connecting = true, bool clear_text = true);
void select_method_from_base_type(const String &p_base, const bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true);
void select_from_base_type(const String &p_base, const String &p_base_script = "", bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true);
void select_from_script(const Ref<Script> &p_script, const bool p_connecting = true, bool clear_text = true);
void select_from_basic_type(Variant::Type p_type, const bool p_connecting = true, bool clear_text = true);
void select_from_action(const String &p_type, const bool p_connecting = true, bool clear_text = true);
void select_from_instance(Object *p_instance, const bool p_connecting = true, bool clear_text = true);
void select_from_visual_script(const Ref<Script> &p_script, bool clear_text = true);
void show_window(float p_screen_ratio);
void set_type_filter(const Vector<Variant::Type> &p_type_filter);
VisualScriptPropertySelector();
};
class VisualScriptPropertySelector::SearchRunner : public RefCounted {
enum Phase {
PHASE_INIT,
PHASE_MATCH_CLASSES_INIT,
PHASE_NODE_CLASSES_INIT,
PHASE_NODE_CLASSES_BUILD,
PHASE_MATCH_CLASSES,
PHASE_CLASS_ITEMS_INIT,
PHASE_CLASS_ITEMS,
PHASE_MEMBER_ITEMS_INIT,
PHASE_MEMBER_ITEMS,
PHASE_SELECT_MATCH,
PHASE_MAX
};
int phase = 0;
struct ClassMatch {
DocData::ClassDoc *doc;
bool name = false;
String category = "";
Vector<DocData::MethodDoc *> constructors;
Vector<DocData::MethodDoc *> methods;
Vector<DocData::MethodDoc *> operators;
Vector<DocData::MethodDoc *> signals;
Vector<DocData::ConstantDoc *> constants;
Vector<DocData::PropertyDoc *> properties;
Vector<DocData::ThemeItemDoc *> theme_properties;
bool required() {
return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size();
}
};
VisualScriptPropertySelector *selector_ui;
Control *ui_service;
Tree *results_tree;
String term;
int search_flags;
int scope_flags;
Ref<Texture2D> empty_icon;
Color disabled_color;
Map<String, DocData::ClassDoc>::Element *iterator_doc = nullptr;
Map<String, ClassMatch> matches;
Map<String, ClassMatch>::Element *iterator_match = nullptr;
TreeItem *root_item = nullptr;
Map<String, TreeItem *> class_items;
TreeItem *matched_item = nullptr;
float match_highest_score = 0;
Map<String, DocData::ClassDoc> combined_docs;
List<String> vs_nodes;
bool _is_class_disabled_by_feature_profile(const StringName &p_class);
bool _is_class_disabled_by_scope(const StringName &p_class);
bool _slice();
bool _phase_init();
bool _phase_match_classes_init();
bool _phase_node_classes_init();
bool _phase_node_classes_build();
bool _phase_match_classes();
bool _phase_class_items_init();
bool _phase_class_items();
bool _phase_member_items_init();
bool _phase_member_items();
bool _phase_select_match();
bool _match_string(const String &p_term, const String &p_string) const;
bool _match_visual_script(DocData::ClassDoc &class_doc);
bool _match_is_hidden(DocData::ClassDoc &class_doc);
void _match_item(TreeItem *p_item, const String &p_text);
void _add_class_doc(String class_name, String inherits, String category);
DocData::MethodDoc _get_method_doc(MethodInfo method_info);
TreeItem *_create_class_hierarchy(const ClassMatch &p_match);
TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray);
TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc);
TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc);
TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc);
TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc);
TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc);
TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_description);
public:
bool work(uint64_t slot = 100000);
SearchRunner(VisualScriptPropertySelector *p_selector_ui, Tree *p_results_tree);
};
#endif // VISUALSCRIPT_PROPERTYSELECTOR_H