Visualscript editor graph unification & refactoring

Removes the need to have separate graphs per function for the VisualScript Nodes, and refactoring UI and other improvements such as fuzzy search, right click search boxes and in-graph editable nodes
This commit is contained in:
Swarnim Arun 2019-09-14 00:44:12 +05:30
parent edf9055b7f
commit 59738e3fa3
No known key found for this signature in database
GPG key ID: A110DB7473A8E5A9
13 changed files with 2705 additions and 725 deletions

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualScriptComposeArray" inherits="VisualScriptLists" category="Core" version="3.2">
<brief_description>
A Visual Script Node used to create array from a list of items.
</brief_description>
<description>
A Visual Script Node used to compose array from the list of elements provided with custom in-graph UI hard coded in the VisualScript Editor.
</description>
<tutorials>
</tutorials>
<methods>
</methods>
<constants>
</constants>
</class>

View file

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualScriptLists" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A Visual Script virtual class for in-graph editable nodes.
</brief_description>
<description>
A Visual Script virtual class that defines the shape and the default behaviour of the nodes that have to be in-graph editable nodes.
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_input_data_port">
<return type="void">
</return>
<argument index="0" name="p_type" type="int" enum="Variant.Type">
</argument>
<argument index="1" name="p_name" type="String">
</argument>
<argument index="2" name="p_index" type="int">
</argument>
<description>
</description>
</method>
<method name="add_output_data_port">
<return type="void">
</return>
<argument index="0" name="p_type" type="int" enum="Variant.Type">
</argument>
<argument index="1" name="p_name" type="String">
</argument>
<argument index="2" name="p_index" type="int">
</argument>
<description>
</description>
</method>
<method name="remove_input_data_port">
<return type="void">
</return>
<argument index="0" name="p_index" type="int">
</argument>
<description>
</description>
</method>
<method name="remove_output_data_port">
<return type="void">
</return>
<argument index="0" name="p_index" type="int">
</argument>
<description>
</description>
</method>
<method name="set_input_data_port_name">
<return type="void">
</return>
<argument index="0" name="p_index" type="int">
</argument>
<argument index="1" name="p_name" type="String">
</argument>
<description>
</description>
</method>
<method name="set_input_data_port_type">
<return type="void">
</return>
<argument index="0" name="p_index" type="int">
</argument>
<argument index="1" name="p_type" type="int" enum="Variant.Type">
</argument>
<description>
</description>
</method>
<method name="set_output_data_port_name">
<return type="void">
</return>
<argument index="0" name="p_index" type="int">
</argument>
<argument index="1" name="p_name" type="String">
</argument>
<description>
</description>
</method>
<method name="set_output_data_port_type">
<return type="void">
</return>
<argument index="0" name="p_index" type="int">
</argument>
<argument index="1" name="p_type" type="int" enum="Variant.Type">
</argument>
<description>
</description>
</method>
</methods>
<constants>
</constants>
</class>

View file

@ -56,6 +56,8 @@ void register_visual_script_types() {
ClassDB::register_virtual_class<VisualScriptNode>();
ClassDB::register_class<VisualScriptFunctionState>();
ClassDB::register_class<VisualScriptFunction>();
ClassDB::register_virtual_class<VisualScriptLists>();
ClassDB::register_class<VisualScriptComposeArray>();
ClassDB::register_class<VisualScriptOperator>();
ClassDB::register_class<VisualScriptVariableSet>();
ClassDB::register_class<VisualScriptVariableGet>();

View file

@ -1014,17 +1014,16 @@ void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const {
Ref<VisualScriptFunction> func = E->get().nodes[E->get().function_id].node;
if (func.is_valid()) {
for (int i = 0; i < func->get_argument_count(); i++) {
PropertyInfo arg;
arg.name = func->get_argument_name(i);
arg.type = func->get_argument_type(i);
mi.arguments.push_back(arg);
}
p_list->push_back(mi);
}
}
p_list->push_back(mi);
}
}
@ -1137,6 +1136,9 @@ void VisualScript::_set_data(const Dictionary &p_data) {
Array funcs = d["functions"];
functions.clear();
Vector2 last_pos = Vector2(-100 * funcs.size(), -100 * funcs.size()); // this is the center of the last fn box
Vector2 last_size = Vector2(0.0, 0.0);
for (int i = 0; i < funcs.size(); i++) {
Dictionary func = funcs[i];
@ -1149,11 +1151,42 @@ void VisualScript::_set_data(const Dictionary &p_data) {
Array nodes = func["nodes"];
for (int j = 0; j < nodes.size(); j += 3) {
if (!d.has("vs_unify") && nodes.size() > 0) {
Vector2 top_left = nodes[1];
Vector2 bottom_right = nodes[1];
add_node(name, nodes[j], nodes[j + 2], nodes[j + 1]);
for (int j = 0; j < nodes.size(); j += 3) {
Point2 pos = nodes[j + 1];
if (pos.y > top_left.y) {
top_left.y = pos.y;
}
if (pos.y < bottom_right.y) {
bottom_right.y = pos.y;
}
if (pos.x > bottom_right.x) {
bottom_right.x = pos.x;
}
if (pos.x < top_left.x) {
top_left.x = pos.x;
}
}
Vector2 size = Vector2(bottom_right.x - top_left.x, top_left.y - bottom_right.y);
Vector2 offset = last_pos + (last_size / 2.0) + (size / 2.0); // dunno I might just keep it in one axis but diagonal feels better....
last_pos = offset;
last_size = size;
for (int j = 0; j < nodes.size(); j += 3) {
add_node(name, nodes[j], nodes[j + 2], offset + nodes[j + 1]); // also add an additional buffer if you want to
}
} else {
for (int j = 0; j < nodes.size(); j += 3) {
add_node(name, nodes[j], nodes[j + 2], nodes[j + 1]);
}
}
Array sequence_connections = func["sequence_connections"];
for (int j = 0; j < sequence_connections.size(); j += 3) {
@ -1254,8 +1287,8 @@ Dictionary VisualScript::_get_data() const {
}
d["functions"] = funcs;
d["is_tool_script"] = is_tool_script;
d["vs_unify"] = true;
return d;
}
@ -1330,6 +1363,10 @@ VisualScript::VisualScript() {
base_type = "Object";
}
StringName VisualScript::get_default_func() const {
return StringName("f_312843592");
}
Set<int> VisualScript::get_output_sequence_ports_connected(const String &edited_func, int from_node) {
List<VisualScript::SequenceConnection> *sc = memnew(List<VisualScript::SequenceConnection>);
get_sequence_connection_list(edited_func, sc);
@ -1403,6 +1440,10 @@ void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
for (const Map<StringName, VisualScript::Function>::Element *E = script->functions.front(); E; E = E->next()) {
if (E->key() == script->get_default_func()) {
continue;
}
MethodInfo mi;
mi.name = E->key();
if (E->get().function_id >= 0 && E->get().nodes.has(E->get().function_id)) {
@ -1421,8 +1462,6 @@ void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
if (!vsf->is_sequenced()) { //assumed constant if not sequenced
mi.flags |= METHOD_FLAG_CONST;
}
//vsf->Get_ for now at least it does not return..
}
}
@ -1431,6 +1470,9 @@ void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
}
bool VisualScriptInstance::has_method(const StringName &p_method) const {
if (p_method == script->get_default_func())
return false;
return script->functions.has(p_method);
}
@ -2002,6 +2044,9 @@ Ref<Script> VisualScriptInstance::get_script() const {
MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const {
if (p_method == script->get_default_func())
return MultiplayerAPI::RPC_MODE_DISABLED;
const Map<StringName, VisualScript::Function>::Element *E = script->functions.find(p_method);
if (!E) {
return MultiplayerAPI::RPC_MODE_DISABLED;
@ -2050,11 +2095,14 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
for (const Map<StringName, VisualScript::Variable>::Element *E = script->variables.front(); E; E = E->next()) {
variables[E->key()] = E->get().default_value;
//no hacer que todo exporte, solo las que queres!
}
for (const Map<StringName, VisualScript::Function>::Element *E = script->functions.front(); E; E = E->next()) {
if (E->key() == script->get_default_func()) {
continue;
}
Function function;
function.node = E->get().function_id;
function.max_stack = 0;
@ -2091,6 +2139,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
for (const Map<int, VisualScript::Function::NodeData>::Element *F = E->get().nodes.front(); F; F = F->next()) {
Ref<VisualScriptNode> node = F->get().node;
VisualScriptNodeInstance *instance = node->instance(this); //create instance
ERR_FAIL_COND(!instance);

View file

@ -239,6 +239,7 @@ private:
PropertyInfo info;
Variant default_value;
bool _export;
// add getter & setter options here
};
Map<StringName, Function> functions;
@ -267,6 +268,8 @@ protected:
static void _bind_methods();
public:
// TODO: Remove it in future when breaking changes are acceptable
StringName get_default_func() const;
void add_function(const StringName &p_name);
bool has_function(const StringName &p_name) const;
void remove_function(const StringName &p_name);

File diff suppressed because it is too large Load diff

View file

@ -59,6 +59,8 @@ class VisualScriptEditor : public ScriptEditorBase {
EDIT_COPY_NODES,
EDIT_CUT_NODES,
EDIT_PASTE_NODES,
EDIT_CREATE_FUNCTION,
REFRESH_GRAPH
};
enum PortAction {
@ -86,10 +88,11 @@ class VisualScriptEditor : public ScriptEditorBase {
Button *base_type_select;
GraphEdit *graph;
LineEdit *func_name_box;
VBoxContainer *func_input_vbox;
ConfirmationDialog *function_create_dialog;
LineEdit *node_filter;
TextureRect *node_filter_icon;
GraphEdit *graph;
VisualScriptEditorSignalEdit *signal_editor;
@ -110,7 +113,8 @@ class VisualScriptEditor : public ScriptEditorBase {
UndoRedo *undo_redo;
Tree *members;
Tree *nodes;
PopupDialog *function_name_edit;
LineEdit *function_name_box;
Label *hint_text;
Timer *hint_text_timer;
@ -133,6 +137,7 @@ class VisualScriptEditor : public ScriptEditorBase {
HashMap<StringName, Ref<StyleBox> > node_styles;
StringName edited_func;
StringName default_func;
void _update_graph_connections();
void _update_graph(int p_only_id = -1);
@ -165,9 +170,13 @@ class VisualScriptEditor : public ScriptEditorBase {
int port_action_output;
Vector2 port_action_pos;
int port_action_new_node;
void _port_action_menu(int p_option);
void new_node(Ref<VisualScriptNode> vnode, Vector2 ofs);
bool saved_pos_dirty;
Vector2 saved_position;
Vector2 mouse_up_position;
void _port_action_menu(int p_option, const StringName &p_func);
void connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id);
@ -175,13 +184,13 @@ class VisualScriptEditor : public ScriptEditorBase {
void connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id);
void _cancel_connect_node();
void _create_new_node(const String &p_text, const String &p_category, const Vector2 &p_point);
int _create_new_node_from_name(const String &p_text, const Vector2 &p_point, const StringName &p_func = StringName());
void _selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting);
int error_line;
void _node_selected(Node *p_node);
void _center_on_node(int p_id);
void _center_on_node(const StringName &p_func, int p_id);
void _node_filter_changed(const String &p_text);
void _change_base_type_callback();
@ -192,7 +201,9 @@ class VisualScriptEditor : public ScriptEditorBase {
void _begin_node_move();
void _end_node_move();
void _move_node(String func, int p_id, const Vector2 &p_to);
void _move_node(const StringName &p_func, int p_id, const Vector2 &p_to);
void _get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes);
void _node_moved(Vector2 p_from, Vector2 p_to, int p_id);
void _remove_node(int p_id);
@ -201,21 +212,44 @@ class VisualScriptEditor : public ScriptEditorBase {
void _graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos);
void _node_ports_changed(const String &p_func, int p_id);
void _available_node_doubleclicked();
void _node_create();
void _update_available_nodes();
void _member_button(Object *p_item, int p_column, int p_button);
void _expression_text_changed(const String &p_text, int p_id);
void _add_input_port(int p_id);
void _add_output_port(int p_id);
void _remove_input_port(int p_id, int p_port);
void _remove_output_port(int p_id, int p_port);
void _change_port_type(int p_select, int p_id, int p_port, bool is_input);
void _update_node_size(int p_id);
void _port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input);
String revert_on_drag;
Vector2 _get_available_pos(bool centered = true, Vector2 pos = Vector2()) const;
StringName _get_function_of_node(int p_id) const;
void _move_nodes_with_rescan(const StringName &p_func_from, const StringName &p_func_to, int p_id);
bool node_has_sequence_connections(const StringName &p_func, int p_id);
void _generic_search(String p_base_type = "", Vector2 pos = Vector2(), bool node_centered = false);
void _input(const Ref<InputEvent> &p_event);
void _generic_search(String p_base_type = "");
void _graph_gui_input(const Ref<InputEvent> &p_event);
void _members_gui_input(const Ref<InputEvent> &p_event);
void _fn_name_box_input(const Ref<InputEvent> &p_event);
void _rename_function(const String &p_name, const String &p_new_name);
void _create_function_dialog();
void _create_function();
void _add_func_input();
void _remove_func_input(Node *p_node);
void _deselect_input_names();
void _add_node_dialog();
void _node_item_selected();
void _node_item_unselected();
void _on_nodes_delete();
void _on_nodes_duplicate();
@ -226,6 +260,10 @@ class VisualScriptEditor : public ScriptEditorBase {
int editing_id;
int editing_input;
bool can_swap;
int data_disconnect_node;
int data_disconnect_port;
void _default_value_changed();
void _default_value_edited(Node *p_button, int p_id, int p_input_port);
@ -240,7 +278,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _draw_color_over_button(Object *obj, Color p_color);
void _button_resource_previewed(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, Variant p_ud);
VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes);
VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &p_visited_nodes);
void _member_rmb_selected(const Vector2 &p_pos);
void _member_option(int p_option);

View file

@ -133,10 +133,12 @@ int VisualScriptFunctionCall::get_input_value_port_count() const {
MethodBind *mb = ClassDB::get_method(_get_base_type(), function);
if (mb) {
return mb->get_argument_count() + (call_mode == CALL_MODE_INSTANCE ? 1 : 0) + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) - use_default_args;
int defaulted_args = mb->get_argument_count() < use_default_args ? mb->get_argument_count() : use_default_args;
return mb->get_argument_count() + (call_mode == CALL_MODE_INSTANCE ? 1 : 0) + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) - defaulted_args;
}
return method_cache.arguments.size() + (call_mode == CALL_MODE_INSTANCE ? 1 : 0) + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) - use_default_args;
int defaulted_args = method_cache.arguments.size() < use_default_args ? method_cache.arguments.size() : use_default_args;
return method_cache.arguments.size() + (call_mode == CALL_MODE_INSTANCE ? 1 : 0) + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) - defaulted_args;
}
}
int VisualScriptFunctionCall::get_output_value_port_count() const {
@ -1056,13 +1058,6 @@ PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) cons
if (call_mode == CALL_MODE_BASIC_TYPE) {
return PropertyInfo(basic_type, "out");
} else if (call_mode == CALL_MODE_INSTANCE) {
List<PropertyInfo> props;
ClassDB::get_property_list(_get_base_type(), &props, true);
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
if (E->get().name == property) {
return PropertyInfo(E->get().type, "pass", PROPERTY_HINT_TYPE_STRING, E->get().hint_string);
}
}
return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type());
} else {
return PropertyInfo();

View file

@ -355,6 +355,441 @@ int VisualScriptFunction::get_stack_size() const {
return stack_size;
}
//////////////////////////////////////////
/////////////////LISTS////////////////////
//////////////////////////////////////////
int VisualScriptLists::get_output_sequence_port_count() const {
if (sequenced)
return 1;
return 0;
}
bool VisualScriptLists::has_input_sequence_port() const {
return sequenced;
}
String VisualScriptLists::get_output_sequence_port_text(int p_port) const {
return "";
}
int VisualScriptLists::get_input_value_port_count() const {
return inputports.size();
}
int VisualScriptLists::get_output_value_port_count() const {
return outputports.size();
}
PropertyInfo VisualScriptLists::get_input_value_port_info(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, inputports.size(), PropertyInfo());
PropertyInfo pi;
pi.name = inputports[p_idx].name;
pi.type = inputports[p_idx].type;
return pi;
}
PropertyInfo VisualScriptLists::get_output_value_port_info(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, outputports.size(), PropertyInfo());
PropertyInfo pi;
pi.name = outputports[p_idx].name;
pi.type = outputports[p_idx].type;
return pi;
}
bool VisualScriptLists::is_input_port_editable() const {
return ((flags & INPUT_EDITABLE) == INPUT_EDITABLE);
}
bool VisualScriptLists::is_input_port_name_editable() const {
return ((flags & INPUT_NAME_EDITABLE) == INPUT_NAME_EDITABLE);
}
bool VisualScriptLists::is_input_port_type_editable() const {
return ((flags & INPUT_TYPE_EDITABLE) == INPUT_TYPE_EDITABLE);
}
bool VisualScriptLists::is_output_port_editable() const {
return ((flags & OUTPUT_EDITABLE) == OUTPUT_EDITABLE);
}
bool VisualScriptLists::is_output_port_name_editable() const {
return ((flags & INPUT_NAME_EDITABLE) == INPUT_NAME_EDITABLE);
}
bool VisualScriptLists::is_output_port_type_editable() const {
return ((flags & INPUT_TYPE_EDITABLE) == INPUT_TYPE_EDITABLE);
}
// for the inspector
bool VisualScriptLists::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "input_count" && is_input_port_editable()) {
int new_argc = p_value;
int argc = inputports.size();
if (argc == new_argc)
return true;
inputports.resize(new_argc);
for (int i = argc; i < new_argc; i++) {
inputports.write[i].name = "arg" + itos(i + 1);
inputports.write[i].type = Variant::NIL;
}
ports_changed_notify();
_change_notify();
return true;
}
if (String(p_name).begins_with("input_") && is_input_port_editable()) {
int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
ERR_FAIL_INDEX_V(idx, inputports.size(), false);
String what = String(p_name).get_slice("/", 1);
if (what == "type") {
Variant::Type new_type = Variant::Type(int(p_value));
inputports.write[idx].type = new_type;
ports_changed_notify();
return true;
}
if (what == "name") {
inputports.write[idx].name = p_value;
ports_changed_notify();
return true;
}
}
if (p_name == "output_count" && is_output_port_editable()) {
int new_argc = p_value;
int argc = outputports.size();
if (argc == new_argc)
return true;
outputports.resize(new_argc);
for (int i = argc; i < new_argc; i++) {
outputports.write[i].name = "arg" + itos(i + 1);
outputports.write[i].type = Variant::NIL;
}
ports_changed_notify();
_change_notify();
return true;
}
if (String(p_name).begins_with("output_") && is_output_port_editable()) {
int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
ERR_FAIL_INDEX_V(idx, outputports.size(), false);
String what = String(p_name).get_slice("/", 1);
if (what == "type") {
Variant::Type new_type = Variant::Type(int(p_value));
outputports.write[idx].type = new_type;
ports_changed_notify();
return true;
}
if (what == "name") {
outputports.write[idx].name = p_value;
ports_changed_notify();
return true;
}
}
if (p_name == "sequenced/sequenced") {
sequenced = p_value;
ports_changed_notify();
return true;
}
return false;
}
bool VisualScriptLists::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "input_count" && is_input_port_editable()) {
r_ret = inputports.size();
return true;
}
if (String(p_name).begins_with("input_") && is_input_port_editable()) {
int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
ERR_FAIL_INDEX_V(idx, inputports.size(), false);
String what = String(p_name).get_slice("/", 1);
if (what == "type") {
r_ret = inputports[idx].type;
return true;
}
if (what == "name") {
r_ret = inputports[idx].name;
return true;
}
}
if (p_name == "output_count" && is_output_port_editable()) {
r_ret = outputports.size();
return true;
}
if (String(p_name).begins_with("output_") && is_output_port_editable()) {
int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
ERR_FAIL_INDEX_V(idx, outputports.size(), false);
String what = String(p_name).get_slice("/", 1);
if (what == "type") {
r_ret = outputports[idx].type;
return true;
}
if (what == "name") {
r_ret = outputports[idx].name;
return true;
}
}
if (p_name == "sequenced/sequenced") {
r_ret = sequenced;
return true;
}
return false;
}
void VisualScriptLists::_get_property_list(List<PropertyInfo> *p_list) const {
if (is_input_port_editable()) {
p_list->push_back(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,256"));
String argt = "Any";
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
argt += "," + Variant::get_type_name(Variant::Type(i));
}
for (int i = 0; i < inputports.size(); i++) {
p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt));
p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i + 1) + "/name"));
}
}
if (is_output_port_editable()) {
p_list->push_back(PropertyInfo(Variant::INT, "output_count", PROPERTY_HINT_RANGE, "0,256"));
String argt = "Any";
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
argt += "," + Variant::get_type_name(Variant::Type(i));
}
for (int i = 0; i < outputports.size(); i++) {
p_list->push_back(PropertyInfo(Variant::INT, "output_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt));
p_list->push_back(PropertyInfo(Variant::STRING, "output_" + itos(i + 1) + "/name"));
}
}
p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced/sequenced"));
}
// input data port interaction
void VisualScriptLists::add_input_data_port(Variant::Type p_type, const String &p_name, int p_index) {
if (!is_input_port_editable())
return;
Port inp;
inp.name = p_name;
inp.type = p_type;
if (p_index >= 0)
inputports.insert(p_index, inp);
else
inputports.push_back(inp);
ports_changed_notify();
_change_notify();
}
void VisualScriptLists::set_input_data_port_type(int p_idx, Variant::Type p_type) {
if (!is_input_port_type_editable())
return;
ERR_FAIL_INDEX(p_idx, inputports.size());
inputports.write[p_idx].type = p_type;
ports_changed_notify();
_change_notify();
}
void VisualScriptLists::set_input_data_port_name(int p_idx, const String &p_name) {
if (!is_input_port_name_editable())
return;
ERR_FAIL_INDEX(p_idx, inputports.size());
inputports.write[p_idx].name = p_name;
ports_changed_notify();
_change_notify();
}
void VisualScriptLists::remove_input_data_port(int p_argidx) {
if (!is_input_port_editable())
return;
ERR_FAIL_INDEX(p_argidx, inputports.size());
inputports.remove(p_argidx);
ports_changed_notify();
_change_notify();
}
// output data port interaction
void VisualScriptLists::add_output_data_port(Variant::Type p_type, const String &p_name, int p_index) {
if (!is_output_port_editable())
return;
Port out;
out.name = p_name;
out.type = p_type;
if (p_index >= 0)
outputports.insert(p_index, out);
else
outputports.push_back(out);
ports_changed_notify();
_change_notify();
}
void VisualScriptLists::set_output_data_port_type(int p_idx, Variant::Type p_type) {
if (!is_output_port_type_editable())
return;
ERR_FAIL_INDEX(p_idx, outputports.size());
outputports.write[p_idx].type = p_type;
ports_changed_notify();
_change_notify();
}
void VisualScriptLists::set_output_data_port_name(int p_idx, const String &p_name) {
if (!is_output_port_name_editable())
return;
ERR_FAIL_INDEX(p_idx, outputports.size());
outputports.write[p_idx].name = p_name;
ports_changed_notify();
_change_notify();
}
void VisualScriptLists::remove_output_data_port(int p_argidx) {
if (!is_output_port_editable())
return;
ERR_FAIL_INDEX(p_argidx, outputports.size());
outputports.remove(p_argidx);
ports_changed_notify();
_change_notify();
}
// sequences
void VisualScriptLists::set_sequenced(bool p_enable) {
if (sequenced == p_enable)
return;
sequenced = p_enable;
ports_changed_notify();
}
bool VisualScriptLists::is_sequenced() const {
return sequenced;
}
VisualScriptLists::VisualScriptLists() {
// initialize
sequenced = false;
flags = 0;
}
void VisualScriptLists::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_input_data_port"), &VisualScriptLists::add_input_data_port);
ClassDB::bind_method(D_METHOD("set_input_data_port_name"), &VisualScriptLists::set_input_data_port_name);
ClassDB::bind_method(D_METHOD("set_input_data_port_type"), &VisualScriptLists::set_input_data_port_type);
ClassDB::bind_method(D_METHOD("remove_input_data_port"), &VisualScriptLists::remove_input_data_port);
ClassDB::bind_method(D_METHOD("add_output_data_port"), &VisualScriptLists::add_output_data_port);
ClassDB::bind_method(D_METHOD("set_output_data_port_name"), &VisualScriptLists::set_output_data_port_name);
ClassDB::bind_method(D_METHOD("set_output_data_port_type"), &VisualScriptLists::set_output_data_port_type);
ClassDB::bind_method(D_METHOD("remove_output_data_port"), &VisualScriptLists::remove_output_data_port);
}
//////////////////////////////////////////
//////////////COMPOSEARRAY////////////////
//////////////////////////////////////////
int VisualScriptComposeArray::get_output_sequence_port_count() const {
if (sequenced)
return 1;
return 0;
}
bool VisualScriptComposeArray::has_input_sequence_port() const {
return sequenced;
}
String VisualScriptComposeArray::get_output_sequence_port_text(int p_port) const {
return "";
}
int VisualScriptComposeArray::get_input_value_port_count() const {
return inputports.size();
}
int VisualScriptComposeArray::get_output_value_port_count() const {
return 1;
}
PropertyInfo VisualScriptComposeArray::get_input_value_port_info(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, inputports.size(), PropertyInfo());
PropertyInfo pi;
pi.name = inputports[p_idx].name;
pi.type = inputports[p_idx].type;
return pi;
}
PropertyInfo VisualScriptComposeArray::get_output_value_port_info(int p_idx) const {
PropertyInfo pi;
pi.name = "out";
pi.type = Variant::ARRAY;
return pi;
}
String VisualScriptComposeArray::get_caption() const {
return "Compose Array";
}
String VisualScriptComposeArray::get_text() const {
return "";
}
class VisualScriptComposeArrayNode : public VisualScriptNodeInstance {
public:
int input_count = 0;
virtual int get_working_memory_size() const { return 0; }
virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) {
if (input_count > 0) {
Array arr;
for (int i = 0; i < input_count; i++)
arr.push_back((*p_inputs[i]));
Variant va = Variant(arr);
*p_outputs[0] = va;
}
return 0;
}
};
VisualScriptNodeInstance *VisualScriptComposeArray::instance(VisualScriptInstance *p_instance) {
VisualScriptComposeArrayNode *instance = memnew(VisualScriptComposeArrayNode);
instance->input_count = inputports.size();
return instance;
}
VisualScriptComposeArray::VisualScriptComposeArray() {
// initialize stuff here
sequenced = false;
flags = INPUT_EDITABLE;
}
//////////////////////////////////////////
////////////////OPERATOR//////////////////
//////////////////////////////////////////
@ -3698,6 +4133,7 @@ void register_visual_script_nodes() {
VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct", create_node_generic<VisualScriptDeconstruct>);
VisualScriptLanguage::singleton->add_register_func("functions/compose_array", create_node_generic<VisualScriptComposeArray>);
for (int i = 1; i < Variant::VARIANT_MAX; i++) {

View file

@ -103,6 +103,103 @@ public:
VisualScriptFunction();
};
class VisualScriptLists : public VisualScriptNode {
GDCLASS(VisualScriptLists, VisualScriptNode)
struct Port {
String name;
Variant::Type type;
};
protected:
Vector<Port> inputports;
Vector<Port> outputports;
enum {
OUTPUT_EDITABLE = 0x0001,
OUTPUT_NAME_EDITABLE = 0x0002,
OUTPUT_TYPE_EDITABLE = 0x0004,
INPUT_EDITABLE = 0x0008,
INPUT_NAME_EDITABLE = 0x000F,
INPUT_TYPE_EDITABLE = 0x0010,
};
int flags;
bool sequenced;
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
public:
virtual bool is_output_port_editable() const;
virtual bool is_output_port_name_editable() const;
virtual bool is_output_port_type_editable() const;
virtual bool is_input_port_editable() const;
virtual bool is_input_port_name_editable() const;
virtual bool is_input_port_type_editable() const;
virtual int get_output_sequence_port_count() const;
virtual bool has_input_sequence_port() const;
virtual String get_output_sequence_port_text(int p_port) const;
virtual int get_input_value_port_count() const;
virtual int get_output_value_port_count() const;
virtual PropertyInfo get_input_value_port_info(int p_idx) const;
virtual PropertyInfo get_output_value_port_info(int p_idx) const;
virtual String get_caption() const = 0;
virtual String get_text() const = 0;
virtual String get_category() const = 0;
void add_input_data_port(Variant::Type p_type, const String &p_name, int p_index = -1);
void set_input_data_port_type(int p_idx, Variant::Type p_type);
void set_input_data_port_name(int p_idx, const String &p_name);
void remove_input_data_port(int p_argidx);
void add_output_data_port(Variant::Type p_type, const String &p_name, int p_index = -1);
void set_output_data_port_type(int p_idx, Variant::Type p_type);
void set_output_data_port_name(int p_idx, const String &p_name);
void remove_output_data_port(int p_argidx);
void set_sequenced(bool p_enable);
bool is_sequenced() const;
VisualScriptLists();
};
class VisualScriptComposeArray : public VisualScriptLists {
GDCLASS(VisualScriptComposeArray, VisualScriptLists)
public:
virtual int get_output_sequence_port_count() const;
virtual bool has_input_sequence_port() const;
virtual String get_output_sequence_port_text(int p_port) const;
virtual int get_input_value_port_count() const;
virtual int get_output_value_port_count() const;
virtual PropertyInfo get_input_value_port_info(int p_idx) const;
virtual PropertyInfo get_output_value_port_info(int p_idx) const;
virtual String get_caption() const;
virtual String get_text() const;
virtual String get_category() const { return "functions"; }
virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance);
VisualScriptComposeArray();
};
class VisualScriptOperator : public VisualScriptNode {
GDCLASS(VisualScriptOperator, VisualScriptNode);

View file

@ -200,13 +200,10 @@ void VisualScriptPropertySelector::_update_search() {
Object *obj = ObjectDB::get_instance(script);
if (Object::cast_to<Script>(obj)) {
methods.push_back(MethodInfo("*Script Methods"));
Object::cast_to<Script>(obj)->get_script_method_list(&methods);
} else {
methods.push_back(MethodInfo("*" + String(E->get())));
ClassDB::get_method_list(E->get(), &methods, true, true);
}
ClassDB::get_method_list(E->get(), &methods, true, true);
}
}
for (List<MethodInfo>::Element *M = methods.front(); M; M = M->next()) {
@ -349,26 +346,37 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt
continue;
}
if (search_box->get_text() != String() && E->get().findn(search_box->get_text()) == -1) {
Vector<String> tx_filters = search_box->get_text().split(" ");
for (int i = 0; i < tx_filters.size(); i++) {
if (tx_filters[i] != String() && E->get().findn(tx_filters[i]) == -1) {
is_filter = true;
break;
}
}
if (is_filter) {
continue;
}
TreeItem *item = search_options->create_item(root);
VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(*VisualScriptLanguage::singleton->create_node_from_name(E->get()));
Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(E->get());
Ref<VisualScriptOperator> vnode_operator = vnode;
String type_name;
if (vnode_operator != NULL) {
if (vnode_operator.is_valid()) {
String type;
if (path.size() >= 2) {
type = path[1];
}
type_name = type.capitalize() + " ";
}
VisualScriptFunctionCall *vnode_function_call = Object::cast_to<VisualScriptFunctionCall>(*VisualScriptLanguage::singleton->create_node_from_name(E->get()));
if (vnode_function_call != NULL) {
Ref<VisualScriptFunctionCall> vnode_function_call = vnode;
if (vnode_function_call.is_valid()) {
String basic_type = Variant::get_type_name(vnode_function_call->get_basic_type());
type_name = basic_type.capitalize() + " ";
}
Vector<String> desc = path[path.size() - 1].replace("(", "( ").replace(")", " )").replace(",", ", ").split(" ");
Ref<VisualScriptConstructor> vnode_constructor = vnode;
if (vnode_constructor.is_valid()) {
type_name = "Construct ";
}
Vector<String> desc = path[path.size() - 1].replace("(", " ").replace(")", " ").replace(",", " ").split(" ");
for (int i = 0; i < desc.size(); i++) {
desc.write[i] = desc[i].capitalize();
if (desc[i].ends_with(",")) {
@ -504,7 +512,7 @@ void VisualScriptPropertySelector::_notification(int p_what) {
}
}
void VisualScriptPropertySelector::select_method_from_base_type(const String &p_base, const String &p_current, const bool p_virtuals_only, const bool p_connecting) {
void VisualScriptPropertySelector::select_method_from_base_type(const String &p_base, const String &p_current, const bool p_virtuals_only, const bool p_connecting, bool clear_text) {
base_type = p_base;
selected = p_current;
@ -515,7 +523,10 @@ void VisualScriptPropertySelector::select_method_from_base_type(const String &p_
virtuals_only = p_virtuals_only;
show_window(.5f);
search_box->set_text("");
if (clear_text)
search_box->set_text("");
else
search_box->select_all();
search_box->grab_focus();
connecting = p_connecting;
@ -526,7 +537,7 @@ void VisualScriptPropertySelector::set_type_filter(const Vector<Variant::Type> &
type_filter = p_type_filter;
}
void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_current, bool p_virtuals_only, bool p_seq_connect, const bool p_connecting) {
void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_current, bool p_virtuals_only, bool p_seq_connect, const bool p_connecting, bool clear_text) {
base_type = p_base;
selected = p_current;
@ -538,7 +549,10 @@ void VisualScriptPropertySelector::select_from_base_type(const String &p_base, c
virtuals_only = p_virtuals_only;
show_window(.5f);
search_box->set_text("");
if (clear_text)
search_box->set_text("");
else
search_box->select_all();
search_box->grab_focus();
seq_connect = p_seq_connect;
connecting = p_connecting;
@ -546,7 +560,7 @@ void VisualScriptPropertySelector::select_from_base_type(const String &p_base, c
_update_search();
}
void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_script, const String &p_current, const bool p_connecting) {
void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_script, const String &p_current, const bool p_connecting, bool clear_text) {
ERR_FAIL_COND(p_script.is_null());
base_type = p_script->get_instance_base_type();
@ -559,7 +573,10 @@ void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_scrip
virtuals_only = false;
show_window(.5f);
search_box->set_text("");
if (clear_text)
search_box->set_text("");
else
search_box->select_all();
search_box->grab_focus();
seq_connect = false;
connecting = p_connecting;
@ -567,7 +584,7 @@ void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_scrip
_update_search();
}
void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type, const String &p_current, const bool p_connecting) {
void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type, const String &p_current, const bool p_connecting, bool clear_text) {
ERR_FAIL_COND(p_type == Variant::NIL);
base_type = "";
selected = p_current;
@ -579,7 +596,10 @@ void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type,
virtuals_only = false;
show_window(.5f);
search_box->set_text("");
if (clear_text)
search_box->set_text("");
else
search_box->select_all();
search_box->grab_focus();
seq_connect = false;
connecting = p_connecting;
@ -587,7 +607,7 @@ void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type,
_update_search();
}
void VisualScriptPropertySelector::select_from_action(const String &p_type, const String &p_current, const bool p_connecting) {
void VisualScriptPropertySelector::select_from_action(const String &p_type, const String &p_current, const bool p_connecting, bool clear_text) {
base_type = p_type;
selected = p_current;
type = Variant::NIL;
@ -598,7 +618,10 @@ void VisualScriptPropertySelector::select_from_action(const String &p_type, cons
virtuals_only = false;
show_window(.5f);
search_box->set_text("");
if (clear_text)
search_box->set_text("");
else
search_box->select_all();
search_box->grab_focus();
seq_connect = true;
connecting = p_connecting;
@ -606,8 +629,8 @@ void VisualScriptPropertySelector::select_from_action(const String &p_type, cons
_update_search();
}
void VisualScriptPropertySelector::select_from_instance(Object *p_instance, const String &p_current, const bool p_connecting) {
base_type = "";
void VisualScriptPropertySelector::select_from_instance(Object *p_instance, const String &p_current, const bool p_connecting, const String &p_basetype, bool clear_text) {
base_type = p_basetype;
selected = p_current;
type = Variant::NIL;
script = 0;
@ -617,7 +640,10 @@ void VisualScriptPropertySelector::select_from_instance(Object *p_instance, cons
virtuals_only = false;
show_window(.5f);
search_box->set_text("");
if (clear_text)
search_box->set_text("");
else
search_box->select_all();
search_box->grab_focus();
seq_connect = false;
connecting = p_connecting;
@ -625,7 +651,7 @@ void VisualScriptPropertySelector::select_from_instance(Object *p_instance, cons
_update_search();
}
void VisualScriptPropertySelector::select_from_visual_script(const String &p_base, const bool p_connecting) {
void VisualScriptPropertySelector::select_from_visual_script(const String &p_base, const bool p_connecting, bool clear_text) {
base_type = p_base;
selected = "";
type = Variant::NIL;
@ -635,7 +661,10 @@ void VisualScriptPropertySelector::select_from_visual_script(const String &p_bas
instance = NULL;
virtuals_only = false;
show_window(.5f);
search_box->set_text("");
if (clear_text)
search_box->set_text("");
else
search_box->select_all();
search_box->grab_focus();
connecting = p_connecting;
@ -646,7 +675,7 @@ void VisualScriptPropertySelector::show_window(float p_screen_ratio) {
Rect2 rect;
Point2 window_size = get_viewport_rect().size;
rect.size = (window_size * p_screen_ratio).floor();
rect.size.x = rect.size.x / 1.25f;
rect.size.x = rect.size.x / 2.2f;
rect.position = ((window_size - rect.size) / 2.0f).floor();
popup(rect);
}

View file

@ -74,13 +74,13 @@ protected:
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);
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);
void select_from_script(const Ref<Script> &p_script, const String &p_current = "", const bool p_connecting = true);
void select_from_basic_type(Variant::Type p_type, const String &p_current = "", const bool p_connecting = true);
void select_from_action(const String &p_type, const String &p_current = "", const bool p_connecting = true);
void select_from_instance(Object *p_instance, const String &p_current = "", const bool p_connecting = true);
void select_from_visual_script(const String &p_base, const bool p_connecting = true);
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 show_window(float p_screen_ratio);

View file

@ -2546,7 +2546,9 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
} else {
Rect2 rect = get_selected()->get_meta("__focus_rect");
if (rect.has_point(Point2(b->get_position().x, b->get_position().y))) {
edit_selected();
if (!edit_selected()) {
emit_signal("item_double_clicked");
}
} else {
emit_signal("item_double_clicked");
}