diff options
| -rw-r--r-- | doc/classes/ScriptEditorBase.xml | 9 | ||||
| -rw-r--r-- | editor/icons/MemberAnnotation.svg | 2 | ||||
| -rw-r--r-- | editor/icons/MethodOverride.svg | 1 | ||||
| -rw-r--r-- | editor/icons/MethodOverrideAndSlot.svg | 1 | ||||
| -rw-r--r-- | editor/plugins/script_editor_plugin.cpp | 2 | ||||
| -rw-r--r-- | editor/plugins/script_text_editor.cpp | 97 | 
6 files changed, 99 insertions, 13 deletions
diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml index 68834839f3..a3fcf53228 100644 --- a/doc/classes/ScriptEditorBase.xml +++ b/doc/classes/ScriptEditorBase.xml @@ -35,6 +35,13 @@  				Emitted when the user requests a specific documentation page.  			</description>  		</signal> +		<signal name="go_to_method"> +			<param index="0" name="script" type="Object" /> +			<param index="1" name="method" type="String" /> +			<description> +				Emitted when the user requests to view a specific method of a script, similar to [signal request_open_script_at_line]. +			</description> +		</signal>  		<signal name="name_changed">  			<description>  				Emitted after script validation or when the edited resource has changed. @@ -56,7 +63,7 @@  			<param index="0" name="script" type="Object" />  			<param index="1" name="line" type="int" />  			<description> -				Emitted when the user requests a script. +				Emitted when the user requests to view a specific line of a script, similar to [signal go_to_method].  			</description>  		</signal>  		<signal name="request_save_history"> diff --git a/editor/icons/MemberAnnotation.svg b/editor/icons/MemberAnnotation.svg index c73ebf7b9b..39bef6d9ee 100644 --- a/editor/icons/MemberAnnotation.svg +++ b/editor/icons/MemberAnnotation.svg @@ -1 +1 @@ -<svg width="16" height="16" version="1.0" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><script id="custom-useragent-string-page-script"/><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538 0.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983 0.4329-0.21023-0.19282-0.44783-1.1594-0.3819-1.5089 0.35827-1.8946 1.0885-4.0778-0.72151-4.7234-2.4171-0.86457-4.5592 1.6495-4.9697 4.0193-0.47396 2.7343 2.284 3.3749 4.1487 1.9879 0.4553-0.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983.4329-.21023-.19282-.44783-1.1594-.3819-1.5089.35827-1.8946 1.0885-4.0778-.72151-4.7234-2.4171-.86457-4.5592 1.6495-4.9697 4.0193-.47396 2.7343 2.284 3.3749 4.1487 1.9879.4553-.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg> diff --git a/editor/icons/MethodOverride.svg b/editor/icons/MethodOverride.svg new file mode 100644 index 0000000000..004b9bf283 --- /dev/null +++ b/editor/icons/MethodOverride.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.49005985 3.3580432.83285685-.0000001v-.7093212c.0027125-.6681099.2054076-1.1321001 1.0021593-1.1328214h.3207573v-.79375l1.3229167 1.0648649-1.3229167 1.0518017v-.79375h-.3364788c-.2888876 0-.4514151.2436282-.4573001.5980603 0 .2833012.0000193.4455045.0000289.7134508h.79375v.4907171l-2.15577345.00147z" fill="#5fb2ff"/></svg> diff --git a/editor/icons/MethodOverrideAndSlot.svg b/editor/icons/MethodOverrideAndSlot.svg new file mode 100644 index 0000000000..d3bd9f0253 --- /dev/null +++ b/editor/icons/MethodOverrideAndSlot.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.15761184 3.636193h.37155483l.004252-.7093212c.0027092-.6681099.12999225-1.1321001.92674393-1.1328214h.1273374l.0042585-.7357171 1.3186582 1.006832-1.3229167 1.0700676v-.8531081h-.1260545c-.2888876 0-.3972562.2847204-.4031411.6391525 0 .2833012.0000193.4455045.0000289.7134508h1.2412654v.4907171h-2.14198686z" fill="#5fb2ff"/><path d="m2.38125.79375h1.5875v2.6458333h-1.5875v-.5291666h1.0583333v-1.5875h-1.0583333z" fill="#5fff97"/></svg> diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 8791da8245..941fcbac2a 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -227,6 +227,7 @@ void ScriptEditorBase::_bind_methods() {  	// TODO: This signal is no use for VisualScript.  	ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text")));  	ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text"))); +	ADD_SIGNAL(MethodInfo("go_to_method", PropertyInfo(Variant::OBJECT, "script"), PropertyInfo(Variant::STRING, "method")));  }  class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache { @@ -2380,6 +2381,7 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,  	se->connect("request_save_history", callable_mp(this, &ScriptEditor::_save_history));  	se->connect("search_in_files_requested", callable_mp(this, &ScriptEditor::_on_find_in_files_requested));  	se->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::_on_replace_in_files_requested)); +	se->connect("go_to_method", callable_mp(this, &ScriptEditor::script_goto_method));  	//test for modification, maybe the script was not edited but was loaded diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index ad07ac180b..7a57f8a1e2 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -956,10 +956,7 @@ void ScriptTextEditor::_update_connected_methods() {  	CodeEdit *text_edit = code_editor->get_text_editor();  	text_edit->set_gutter_width(connection_gutter, text_edit->get_line_height());  	for (int i = 0; i < text_edit->get_line_count(); i++) { -		if (text_edit->get_line_gutter_metadata(i, connection_gutter) == "") { -			continue; -		} -		text_edit->set_line_gutter_metadata(i, connection_gutter, ""); +		text_edit->set_line_gutter_metadata(i, connection_gutter, Dictionary());  		text_edit->set_line_gutter_icon(i, connection_gutter, nullptr);  		text_edit->set_line_gutter_clickable(i, connection_gutter, false);  	} @@ -974,6 +971,7 @@ void ScriptTextEditor::_update_connected_methods() {  		return;  	} +	// Add connection icons to methods.  	Vector<Node *> nodes = _find_all_node_for_script(base, base, script);  	HashSet<StringName> methods_found;  	for (int i = 0; i < nodes.size(); i++) { @@ -1002,8 +1000,11 @@ void ScriptTextEditor::_update_connected_methods() {  				for (int j = 0; j < functions.size(); j++) {  					String name = functions[j].get_slice(":", 0);  					if (name == method) { +						Dictionary line_meta; +						line_meta["type"] = "connection"; +						line_meta["method"] = method;  						line = functions[j].get_slice(":", 1).to_int() - 1; -						text_edit->set_line_gutter_metadata(line, connection_gutter, method); +						text_edit->set_line_gutter_metadata(line, connection_gutter, line_meta);  						text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("Slot"), SNAME("EditorIcons")));  						text_edit->set_line_gutter_clickable(line, connection_gutter, true);  						methods_found.insert(method); @@ -1033,6 +1034,58 @@ void ScriptTextEditor::_update_connected_methods() {  			}  		}  	} + +	// Add override icons to methods. +	methods_found.clear(); +	for (int i = 0; i < functions.size(); i++) { +		StringName name = StringName(functions[i].get_slice(":", 0)); +		if (methods_found.has(name)) { +			continue; +		} + +		String found_base_class; +		StringName base_class = script->get_instance_base_type(); +		Ref<Script> inherited_script = script->get_base_script(); +		while (!inherited_script.is_null()) { +			if (inherited_script->has_method(name)) { +				found_base_class = "script:" + inherited_script->get_path(); +				break; +			} + +			base_class = inherited_script->get_instance_base_type(); +			inherited_script = inherited_script->get_base_script(); +		} + +		if (found_base_class.is_empty() && base_class) { +			List<MethodInfo> methods; +			ClassDB::get_method_list(base_class, &methods); +			for (int j = 0; j < methods.size(); j++) { +				if (methods[j].name == name) { +					found_base_class = "builtin:" + base_class; +					break; +				} +			} +		} + +		if (!found_base_class.is_empty()) { +			int line = functions[i].get_slice(":", 1).to_int() - 1; + +			Dictionary line_meta = text_edit->get_line_gutter_metadata(line, connection_gutter); +			if (line_meta.is_empty()) { +				// Add override icon to gutter. +				line_meta["type"] = "inherits"; +				line_meta["method"] = name; +				line_meta["base_class"] = found_base_class; +				text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("MethodOverride"), SNAME("EditorIcons"))); +				text_edit->set_line_gutter_clickable(line, connection_gutter, true); +			} else { +				// If method is also connected to signal, then merge icons and keep the click behavior of the slot. +				text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("MethodOverrideAndSlot"), SNAME("EditorIcons"))); +			} + +			methods_found.insert(name); +		} +	}  }  void ScriptTextEditor::_update_gutter_indexes() { @@ -1054,18 +1107,40 @@ void ScriptTextEditor::_gutter_clicked(int p_line, int p_gutter) {  		return;  	} -	String method = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter); -	if (method.is_empty()) { +	Dictionary meta = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter); +	String type = meta.get("type", ""); +	if (type.is_empty()) {  		return;  	} -	Node *base = get_tree()->get_edited_scene_root(); -	if (!base) { +	// All types currently need a method name. +	String method = meta.get("method", ""); +	if (method.is_empty()) {  		return;  	} -	Vector<Node *> nodes = _find_all_node_for_script(base, base, script); -	connection_info_dialog->popup_connections(method, nodes); +	if (type == "connection") { +		Node *base = get_tree()->get_edited_scene_root(); +		if (!base) { +			return; +		} + +		Vector<Node *> nodes = _find_all_node_for_script(base, base, script); +		connection_info_dialog->popup_connections(method, nodes); +	} else if (type == "inherits") { +		String base_class_raw = meta["base_class"]; +		PackedStringArray base_class_split = base_class_raw.split(":", true, 1); + +		if (base_class_split[0] == "script") { +			// Go to function declaration. +			Ref<Script> base_script = ResourceLoader::load(base_class_split[1]); +			ERR_FAIL_COND(!base_script.is_valid()); +			emit_signal(SNAME("go_to_method"), base_script, method); +		} else if (base_class_split[0] == "builtin") { +			// Open method documentation. +			emit_signal(SNAME("go_to_help"), "class_method:" + base_class_split[1] + ":" + method); +		} +	}  }  void ScriptTextEditor::_edit_option(int p_op) {  |